Files
FYS-STK4155/doc/pub/week46/html/week46.html
T
Morten Hjorth-Jensen e3034398b7 update
2022-11-18 05:37:13 +01:00

2740 lines
163 KiB
HTML

<!--
HTML file automatically generated from DocOnce source
(https://github.com/doconce/doconce/)
doconce format html week46.do.txt --pygments_html_style=default --html_style=bloodish --html_links_in_new_window --html_output=week46 --no_mako
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="DocOnce: https://github.com/doconce/doconce/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Week 46: Support Vector Machines and Project 3. Start Principal Component Analysis">
<title>Week 46: Support Vector Machines and Project 3. Start Principal Component Analysis</title>
<style type="text/css">
/* bloodish style */
body {
font-family: Helvetica, Verdana, Arial, Sans-serif;
color: #404040;
background: #ffffff;
}
h1 { font-size: 1.8em; color: #8A0808; }
h2 { font-size: 1.6em; color: #8A0808; }
h3 { font-size: 1.4em; color: #8A0808; }
h4 { font-size: 1.2em; color: #8A0808; }
a { color: #8A0808; text-decoration:none; }
tt { font-family: "Courier New", Courier; }
p { text-indent: 0px; }
hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
p.caption { width: 80%; font-style: normal; text-align: left; }
hr.figure { border: 0; width: 80%; border-bottom: 1px solid #aaa; }div.highlight {
border: 1px solid #cfcfcf;
border-radius: 2px;
line-height: 1.21429em;
}
div.cell {
width: 100%;
padding: 5px 5px 5px 0;
margin: 0;
outline: none;
}
div.input {
page-break-inside: avoid;
box-orient: horizontal;
box-align: stretch;
display: flex;
flex-direction: row;
align-items: stretch;
}
div.inner_cell {
box-orient: vertical;
box-align: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
box-flex: 1;
flex: 1;
}
div.input_area {
border: 1px solid #cfcfcf;
border-radius: 4px;
background: #f7f7f7;
line-height: 1.21429em;
}
div.input_area > div.highlight {
margin: .4em;
border: none;
padding: 0;
background-color: transparent;
}
div.output_wrapper {
position: relative;
box-orient: vertical;
box-align: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
}
.output {
box-orient: vertical;
box-align: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
}
div.output_area {
padding: 0;
page-break-inside: avoid;
box-orient: horizontal;
box-align: stretch;
display: flex;
flex-direction: row;
align-items: stretch;
}
div.output_subarea {
padding: .4em .4em 0 .4em;
box-flex: 1;
flex: 1;
}
div.output_text {
text-align: left;
color: #000;
line-height: 1.21429em;
}
.alert-text-small { font-size: 80%; }
.alert-text-large { font-size: 130%; }
.alert-text-normal { font-size: 90%; }
.alert {
padding:8px 35px 8px 14px; margin-bottom:18px;
text-shadow:0 1px 0 rgba(255,255,255,0.5);
border:1px solid #bababa;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
color: #555;
background-color: #f8f8f8;
background-position: 10px 5px;
background-repeat: no-repeat;
background-size: 38px;
padding-left: 55px;
width: 75%;
}
.alert-block {padding-top:14px; padding-bottom:14px}
.alert-block > p, .alert-block > ul {margin-bottom:1em}
.alert li {margin-top: 1em}
.alert-block p+p {margin-top:5px}
.alert-notice { background-image: url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_notice.png); }
.alert-summary { background-image:url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_summary.png); }
.alert-warning { background-image: url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_warning.png); }
.alert-question {background-image:url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_question.png); }
div { text-align: justify; text-justify: inter-word; }
.tab {
padding-left: 1.5em;
}
div.toc p,a {
line-height: 1.3;
margin-top: 1.1;
margin-bottom: 1.1;
}
</style>
</head>
<!-- tocinfo
{'highest level': 2,
'sections': [('Overview of week 46', 2, None, 'overview-of-week-46'),
('Support Vector Machines, overarching aims',
2,
None,
'support-vector-machines-overarching-aims'),
('Hyperplanes and all that', 2, None, 'hyperplanes-and-all-that'),
('What is a hyperplane?', 2, None, 'what-is-a-hyperplane'),
('A $p$-dimensional space of features',
2,
None,
'a-p-dimensional-space-of-features'),
('The two-dimensional case', 2, None, 'the-two-dimensional-case'),
('Getting into the details', 2, None, 'getting-into-the-details'),
('First attempt at a minimization approach',
2,
None,
'first-attempt-at-a-minimization-approach'),
('Solving the equations', 2, None, 'solving-the-equations'),
('Code Example', 2, None, 'code-example'),
('Problems with the Simpler Approach',
2,
None,
'problems-with-the-simpler-approach'),
('A better approach', 2, None, 'a-better-approach'),
('A quick Reminder on Lagrangian Multipliers',
2,
None,
'a-quick-reminder-on-lagrangian-multipliers'),
('Adding the Multiplier', 2, None, 'adding-the-multiplier'),
('Setting up the Problem', 2, None, 'setting-up-the-problem'),
('The problem to solve', 2, None, 'the-problem-to-solve'),
('The last steps', 2, None, 'the-last-steps'),
('A soft classifier', 2, None, 'a-soft-classifier'),
('Soft optmization problem', 2, None, 'soft-optmization-problem'),
('Kernels and non-linearity',
2,
None,
'kernels-and-non-linearity'),
('The equations', 2, None, 'the-equations'),
('The problem to solve', 2, None, 'the-problem-to-solve'),
("Different kernels and Mercer's theorem",
2,
None,
'different-kernels-and-mercer-s-theorem'),
('The moons example', 2, None, 'the-moons-example'),
('Mathematical optimization of convex functions',
2,
None,
'mathematical-optimization-of-convex-functions'),
('How do we solve these problems?',
2,
None,
'how-do-we-solve-these-problems'),
('A simple example', 2, None, 'a-simple-example'),
('Back to the more realistic cases',
2,
None,
'back-to-the-more-realistic-cases'),
('Basic ideas of the Principal Component Analysis (PCA)',
2,
None,
'basic-ideas-of-the-principal-component-analysis-pca'),
('Introducing the Covariance and Correlation functions',
2,
None,
'introducing-the-covariance-and-correlation-functions'),
('More on the covariance', 2, None, 'more-on-the-covariance'),
('Reminding ourselves about Linear Regression',
2,
None,
'reminding-ourselves-about-linear-regression'),
('Simple Example', 2, None, 'simple-example'),
('The Correlation Matrix', 2, None, 'the-correlation-matrix'),
('Numpy Functionality', 2, None, 'numpy-functionality'),
('Correlation Matrix again', 2, None, 'correlation-matrix-again'),
('Using Pandas', 2, None, 'using-pandas'),
('And then the Franke Function',
2,
None,
'and-then-the-franke-function'),
('Links with the Design Matrix',
2,
None,
'links-with-the-design-matrix'),
('Computing the Expectation Values',
2,
None,
'computing-the-expectation-values'),
('Towards the PCA theorem', 2, None, 'towards-the-pca-theorem'),
('More on the PCA Theorem', 2, None, 'more-on-the-pca-theorem'),
('Writing our own PCA code', 2, None, 'writing-our-own-pca-code'),
('Implementing it', 2, None, 'implementing-it'),
('First Step', 2, None, 'first-step'),
('Scaling', 2, None, 'scaling'),
('Centered Data', 2, None, 'centered-data'),
('Exploring', 2, None, 'exploring'),
('Diagonalize the sample covariance matrix to obtain the '
'principal components',
2,
None,
'diagonalize-the-sample-covariance-matrix-to-obtain-the-principal-components'),
('Collecting all Steps', 2, None, 'collecting-all-steps'),
('Classical PCA Theorem', 2, None, 'classical-pca-theorem'),
('The PCA Theorem', 2, None, 'the-pca-theorem'),
('Geometric Interpretation and link with Singular Value '
'Decomposition',
2,
None,
'geometric-interpretation-and-link-with-singular-value-decomposition'),
('PCA and scikit-learn', 2, None, 'pca-and-scikit-learn'),
('Back to the Cancer Data', 2, None, 'back-to-the-cancer-data'),
('Incremental PCA', 2, None, 'incremental-pca'),
('Randomized PCA', 3, None, 'randomized-pca'),
('Kernel PCA', 3, None, 'kernel-pca'),
('Other techniques', 2, None, 'other-techniques')]}
end of tocinfo -->
<body>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {
equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
}
});
</script>
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<!-- ------------------- main content ---------------------- -->
<center>
<h1>Week 46: Support Vector Machines and Project 3. Start Principal Component Analysis</h1>
</center> <!-- document title -->
<!-- author(s): Morten Hjorth-Jensen -->
<center>
<b>Morten Hjorth-Jensen</b> [1, 2]
</center>
<!-- institution(s) -->
<center>
[1] <b>Department of Physics, University of Oslo</b>
</center>
<center>
[2] <b>Department of Physics and Astronomy and National Superconducting Cyclotron Laboratory, Michigan State University</b>
</center>
<br>
<center>
<h4>Nov 18, 2022</h4>
</center> <!-- date -->
<br>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="overview-of-week-46">Overview of week 46 </h2>
<ul>
<li> <b>Thursday</b>: Support Vector Machines, discussion of project 3</li>
<ul>
<li> <a href="https://youtu.be/F3CkH-opbdY" target="_blank">Video of lecture</a></li>
</ul>
<li> <b>Friday</b>: Support vector machines and start Principal Component Analysis</li>
</ul>
<div class="alert alert-block alert-block alert-text-normal">
<b>Reading</b>
<p>
<p>Reading recommendations:</p>
<ol>
<li> See lecture notes for week 46 at <a href="https://compphysics.github.io/MachineLearning/doc/web/course.html." target="_blank"><tt>https://compphysics.github.io/MachineLearning/doc/web/course.html.</tt></a></li>
<li> Hastie et al chapter 12</li>
<li> Bishop chapter 7.1 and 7.2</li>
</ol>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b>Videos</b>
<p>
<ol>
<li> <a href="https://www.youtube.com/watch?v=efR1C6CvhmE&ab_channel=StatQuestwithJoshStarmer" target="_blank">Overview video on Support Vector Machines</a></li>
<li> See also <a href="https://www.youtube.com/watch?v=N1vOgolbjSc&ab_channel=AliceZhao" target="_blank">this video</a>.</li>
</ol>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="support-vector-machines-overarching-aims">Support Vector Machines, overarching aims </h2>
<p>A Support Vector Machine (SVM) is a very powerful and versatile
Machine Learning method, capable of performing linear or nonlinear
classification, regression, and even outlier detection. It is one of
the most popular models in Machine Learning, and anyone interested in
Machine Learning should have it in their toolbox. SVMs are
particularly well suited for classification of complex but small-sized or
medium-sized datasets.
</p>
<p>The case with two well-separated classes only can be understood in an
intuitive way in terms of lines in a two-dimensional space separating
the two classes (see figure below).
</p>
<p>The basic mathematics behind the SVM is however less familiar to most of us.
It relies on the definition of hyperplanes and the
definition of a <b>margin</b> which separates classes (in case of
classification problems) of variables. It is also used for regression
problems.
</p>
<p>With SVMs we distinguish between hard margin and soft margins. The
latter introduces a so-called softening parameter to be discussed
below. We distinguish also between linear and non-linear
approaches. The latter are the most frequent ones since it is rather
unlikely that we can separate classes easily by say straight lines.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="hyperplanes-and-all-that">Hyperplanes and all that </h2>
<p>The theory behind support vector machines (SVM hereafter) is based on
the mathematical description of so-called hyperplanes. Let us start
with a two-dimensional case. This will also allow us to introduce our
first SVM examples. These will be tailored to the case of two specific
classes, as displayed in the figure here based on the usage of the petal data.
</p>
<p>We assume here that our data set can be well separated into two
domains, where a straight line does the job in the separating the two
classes. Here the two classes are represented by either squares or
circles.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn</span> <span style="color: #008000; font-weight: bold">import</span> datasets
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.svm</span> <span style="color: #008000; font-weight: bold">import</span> SVC, LinearSVC
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.linear_model</span> <span style="color: #008000; font-weight: bold">import</span> SGDClassifier
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.preprocessing</span> <span style="color: #008000; font-weight: bold">import</span> StandardScaler
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;axes.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">14</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;xtick.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">12</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;ytick.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">12</span>
iris <span style="color: #666666">=</span> datasets<span style="color: #666666">.</span>load_iris()
X <span style="color: #666666">=</span> iris[<span style="color: #BA2121">&quot;data&quot;</span>][:, (<span style="color: #666666">2</span>, <span style="color: #666666">3</span>)] <span style="color: #408080; font-style: italic"># petal length, petal width</span>
y <span style="color: #666666">=</span> iris[<span style="color: #BA2121">&quot;target&quot;</span>]
setosa_or_versicolor <span style="color: #666666">=</span> (y <span style="color: #666666">==</span> <span style="color: #666666">0</span>) <span style="color: #666666">|</span> (y <span style="color: #666666">==</span> <span style="color: #666666">1</span>)
X <span style="color: #666666">=</span> X[setosa_or_versicolor]
y <span style="color: #666666">=</span> y[setosa_or_versicolor]
C <span style="color: #666666">=</span> <span style="color: #666666">5</span>
alpha <span style="color: #666666">=</span> <span style="color: #666666">1</span> <span style="color: #666666">/</span> (C <span style="color: #666666">*</span> <span style="color: #008000">len</span>(X))
lin_clf <span style="color: #666666">=</span> LinearSVC(loss<span style="color: #666666">=</span><span style="color: #BA2121">&quot;hinge&quot;</span>, C<span style="color: #666666">=</span>C, random_state<span style="color: #666666">=42</span>)
svm_clf <span style="color: #666666">=</span> SVC(kernel<span style="color: #666666">=</span><span style="color: #BA2121">&quot;linear&quot;</span>, C<span style="color: #666666">=</span>C)
sgd_clf <span style="color: #666666">=</span> SGDClassifier(loss<span style="color: #666666">=</span><span style="color: #BA2121">&quot;hinge&quot;</span>, learning_rate<span style="color: #666666">=</span><span style="color: #BA2121">&quot;constant&quot;</span>, eta0<span style="color: #666666">=0.001</span>, alpha<span style="color: #666666">=</span>alpha,
max_iter<span style="color: #666666">=100000</span>, random_state<span style="color: #666666">=42</span>)
scaler <span style="color: #666666">=</span> StandardScaler()
X_scaled <span style="color: #666666">=</span> scaler<span style="color: #666666">.</span>fit_transform(X)
lin_clf<span style="color: #666666">.</span>fit(X_scaled, y)
svm_clf<span style="color: #666666">.</span>fit(X_scaled, y)
sgd_clf<span style="color: #666666">.</span>fit(X_scaled, y)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;LinearSVC: &quot;</span>, lin_clf<span style="color: #666666">.</span>intercept_, lin_clf<span style="color: #666666">.</span>coef_)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;SVC: &quot;</span>, svm_clf<span style="color: #666666">.</span>intercept_, svm_clf<span style="color: #666666">.</span>coef_)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;SGDClassifier(alpha=</span><span style="color: #BB6688; font-weight: bold">{:.5f}</span><span style="color: #BA2121">):&quot;</span><span style="color: #666666">.</span>format(sgd_clf<span style="color: #666666">.</span>alpha), sgd_clf<span style="color: #666666">.</span>intercept_, sgd_clf<span style="color: #666666">.</span>coef_)
<span style="color: #408080; font-style: italic"># Compute the slope and bias of each decision boundary</span>
w1 <span style="color: #666666">=</span> <span style="color: #666666">-</span>lin_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">0</span>]<span style="color: #666666">/</span>lin_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]
b1 <span style="color: #666666">=</span> <span style="color: #666666">-</span>lin_clf<span style="color: #666666">.</span>intercept_[<span style="color: #666666">0</span>]<span style="color: #666666">/</span>lin_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]
w2 <span style="color: #666666">=</span> <span style="color: #666666">-</span>svm_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">0</span>]<span style="color: #666666">/</span>svm_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]
b2 <span style="color: #666666">=</span> <span style="color: #666666">-</span>svm_clf<span style="color: #666666">.</span>intercept_[<span style="color: #666666">0</span>]<span style="color: #666666">/</span>svm_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]
w3 <span style="color: #666666">=</span> <span style="color: #666666">-</span>sgd_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">0</span>]<span style="color: #666666">/</span>sgd_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]
b3 <span style="color: #666666">=</span> <span style="color: #666666">-</span>sgd_clf<span style="color: #666666">.</span>intercept_[<span style="color: #666666">0</span>]<span style="color: #666666">/</span>sgd_clf<span style="color: #666666">.</span>coef_[<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]
<span style="color: #408080; font-style: italic"># Transform the decision boundary lines back to the original scale</span>
line1 <span style="color: #666666">=</span> scaler<span style="color: #666666">.</span>inverse_transform([[<span style="color: #666666">-10</span>, <span style="color: #666666">-10</span> <span style="color: #666666">*</span> w1 <span style="color: #666666">+</span> b1], [<span style="color: #666666">10</span>, <span style="color: #666666">10</span> <span style="color: #666666">*</span> w1 <span style="color: #666666">+</span> b1]])
line2 <span style="color: #666666">=</span> scaler<span style="color: #666666">.</span>inverse_transform([[<span style="color: #666666">-10</span>, <span style="color: #666666">-10</span> <span style="color: #666666">*</span> w2 <span style="color: #666666">+</span> b2], [<span style="color: #666666">10</span>, <span style="color: #666666">10</span> <span style="color: #666666">*</span> w2 <span style="color: #666666">+</span> b2]])
line3 <span style="color: #666666">=</span> scaler<span style="color: #666666">.</span>inverse_transform([[<span style="color: #666666">-10</span>, <span style="color: #666666">-10</span> <span style="color: #666666">*</span> w3 <span style="color: #666666">+</span> b3], [<span style="color: #666666">10</span>, <span style="color: #666666">10</span> <span style="color: #666666">*</span> w3 <span style="color: #666666">+</span> b3]])
<span style="color: #408080; font-style: italic"># Plot all three decision boundaries</span>
plt<span style="color: #666666">.</span>figure(figsize<span style="color: #666666">=</span>(<span style="color: #666666">11</span>, <span style="color: #666666">4</span>))
plt<span style="color: #666666">.</span>plot(line1[:, <span style="color: #666666">0</span>], line1[:, <span style="color: #666666">1</span>], <span style="color: #BA2121">&quot;k:&quot;</span>, label<span style="color: #666666">=</span><span style="color: #BA2121">&quot;LinearSVC&quot;</span>)
plt<span style="color: #666666">.</span>plot(line2[:, <span style="color: #666666">0</span>], line2[:, <span style="color: #666666">1</span>], <span style="color: #BA2121">&quot;b--&quot;</span>, linewidth<span style="color: #666666">=2</span>, label<span style="color: #666666">=</span><span style="color: #BA2121">&quot;SVC&quot;</span>)
plt<span style="color: #666666">.</span>plot(line3[:, <span style="color: #666666">0</span>], line3[:, <span style="color: #666666">1</span>], <span style="color: #BA2121">&quot;r-&quot;</span>, label<span style="color: #666666">=</span><span style="color: #BA2121">&quot;SGDClassifier&quot;</span>)
plt<span style="color: #666666">.</span>plot(X[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==1</span>], X[:, <span style="color: #666666">1</span>][y<span style="color: #666666">==1</span>], <span style="color: #BA2121">&quot;bs&quot;</span>) <span style="color: #408080; font-style: italic"># label=&quot;Iris-Versicolor&quot;</span>
plt<span style="color: #666666">.</span>plot(X[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==0</span>], X[:, <span style="color: #666666">1</span>][y<span style="color: #666666">==0</span>], <span style="color: #BA2121">&quot;yo&quot;</span>) <span style="color: #408080; font-style: italic"># label=&quot;Iris-Setosa&quot;</span>
plt<span style="color: #666666">.</span>xlabel(<span style="color: #BA2121">&quot;Petal length&quot;</span>, fontsize<span style="color: #666666">=14</span>)
plt<span style="color: #666666">.</span>ylabel(<span style="color: #BA2121">&quot;Petal width&quot;</span>, fontsize<span style="color: #666666">=14</span>)
plt<span style="color: #666666">.</span>legend(loc<span style="color: #666666">=</span><span style="color: #BA2121">&quot;upper center&quot;</span>, fontsize<span style="color: #666666">=14</span>)
plt<span style="color: #666666">.</span>axis([<span style="color: #666666">0</span>, <span style="color: #666666">5.5</span>, <span style="color: #666666">0</span>, <span style="color: #666666">2</span>])
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="what-is-a-hyperplane">What is a hyperplane? </h2>
<p>The aim of the SVM algorithm is to find a hyperplane in a
\( p \)-dimensional space, where \( p \) is the number of features that
distinctly classifies the data points.
</p>
<p>In a \( p \)-dimensional space, a hyperplane is what we call an affine subspace of dimension of \( p-1 \).
As an example, in two dimension, a hyperplane is simply as straight line while in three dimensions it is
a two-dimensional subspace, or stated simply, a plane.
</p>
<p>In two dimensions, with the variables \( x_1 \) and \( x_2 \), the hyperplane is defined as</p>
$$
b+w_1x_1+w_2x_2=0,
$$
<p>where \( b \) is the intercept and \( w_1 \) and \( w_2 \) define the elements of a vector orthogonal to the line
\( b+w_1x_1+w_2x_2=0 \).
In two dimensions we define the vectors \( \boldsymbol{x} =[x1,x2] \) and \( \boldsymbol{w}=[w1,w2] \).
We can then rewrite the above equation as
</p>
$$
\boldsymbol{x}^T\boldsymbol{w}+b=0.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-p-dimensional-space-of-features">A \( p \)-dimensional space of features </h2>
<p>We limit ourselves to two classes of outputs \( y_i \) and assign these classes the values \( y_i = \pm 1 \).
In a \( p \)-dimensional space of say \( p \) features we have a hyperplane defines as
</p>
$$
b+wx_1+w_2x_2+\dots +w_px_p=0.
$$
<p>If we define a
matrix \( \boldsymbol{X}=\left[\boldsymbol{x}_1,\boldsymbol{x}_2,\dots, \boldsymbol{x}_p\right] \)
of dimension \( n\times p \), where \( n \) represents the observations for each feature and each vector \( x_i \) is a column vector of the matrix \( \boldsymbol{X} \),
</p>
$$
\boldsymbol{x}_i = \begin{bmatrix} x_{i1} \\ x_{i2} \\ \dots \\ \dots \\ x_{ip} \end{bmatrix}.
$$
<p>If the above condition is not met for a given vector \( \boldsymbol{x}_i \) we have </p>
$$
b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip} >0,
$$
<p>if our output \( y_i=1 \).
In this case we say that \( \boldsymbol{x}_i \) lies on one of the sides of the hyperplane and if
</p>
$$
b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip} < 0,
$$
<p>for the class of observations \( y_i=-1 \),
then \( \boldsymbol{x}_i \) lies on the other side.
</p>
<p>Equivalently, for the two classes of observations we have </p>
$$
y_i\left(b+w_1x_{i1}+w_2x_{i2}+\dots +w_px_{ip}\right) > 0.
$$
<p>When we try to separate hyperplanes, if it exists, we can use it to construct a natural classifier: a test observation is assigned a given class depending on which side of the hyperplane it is located.</p>
<!-- !split -->
<h2 id="the-two-dimensional-case">The two-dimensional case </h2>
<p>Let us try to develop our intuition about SVMs by limiting ourselves to a two-dimensional
plane. To separate the two classes of data points, there are many
possible lines (hyperplanes if you prefer a more strict naming)
that could be chosen. Our objective is to find a
plane that has the maximum margin, i.e the maximum distance between
data points of both classes. Maximizing the margin distance provides
some reinforcement so that future data points can be classified with
more confidence.
</p>
<p>What a linear classifier attempts to accomplish is to split the
feature space into two half spaces by placing a hyperplane between the
data points. This hyperplane will be our decision boundary. All
points on one side of the plane will belong to class one and all points
on the other side of the plane will belong to the second class two.
</p>
<p>Unfortunately there are many ways in which we can place a hyperplane
to divide the data. Below is an example of two candidate hyperplanes
for our data sample.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="getting-into-the-details">Getting into the details </h2>
<p>Let us define the function</p>
$$
f(x) = \boldsymbol{w}^T\boldsymbol{x}+b = 0,
$$
<p>as the function that determines the line \( L \) that separates two classes (our two features), see the figure here. </p>
<p>Any point defined by \( \boldsymbol{x}_i \) and \( \boldsymbol{x}_2 \) on the line \( L \) will satisfy \( \boldsymbol{w}^T(\boldsymbol{x}_1-\boldsymbol{x}_2)=0 \). </p>
<p>The signed distance \( \delta \) from any point defined by a vector \( \boldsymbol{x} \) and a point \( \boldsymbol{x}_0 \) on the line \( L \) is then</p>
$$
\delta = \frac{1}{\vert\vert \boldsymbol{w}\vert\vert}(\boldsymbol{w}^T\boldsymbol{x}+b).
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="first-attempt-at-a-minimization-approach">First attempt at a minimization approach </h2>
<p>How do we find the parameter \( b \) and the vector \( \boldsymbol{w} \)? What we could
do is to define a cost function which now contains the set of all
misclassified points \( M \) and attempt to minimize this function
</p>
$$
C(\boldsymbol{w},b) = -\sum_{i\in M} y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b).
$$
<p>We could now for example define all values \( y_i =1 \) as misclassified in case we have \( \boldsymbol{w}^T\boldsymbol{x}_i+b < 0 \) and the opposite if we have \( y_i=-1 \). Taking the derivatives gives us</p>
$$
\frac{\partial C}{\partial b} = -\sum_{i\in M} y_i,
$$
<p>and </p>
$$
\frac{\partial C}{\partial \boldsymbol{w}} = -\sum_{i\in M} y_ix_i.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="solving-the-equations">Solving the equations </h2>
<p>We can now use the Newton-Raphson method or different variants of the gradient descent family (from plain gradient descent to various stochastic gradient descent approaches) to solve the equations</p>
$$
b \leftarrow b +\eta \frac{\partial C}{\partial b},
$$
<p>and</p>
$$
\boldsymbol{w} \leftarrow \boldsymbol{w} +\eta \frac{\partial C}{\partial \boldsymbol{w}},
$$
<p>where \( \eta \) is our by now well-known learning rate. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="code-example">Code Example </h2>
<p>The equations we discussed above can be coded rather easily (the
framework is similar to what we developed for logistic
regression). We are going to set up a simple case with two classes only and we want to find a line which separates them the best possible way.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="problems-with-the-simpler-approach">Problems with the Simpler Approach </h2>
<p>There are however problems with this approach, although it looks
pretty straightforward to implement. When running the above code, we see that we can easily end up with many diffeent lines which separate the two classes.
</p>
<p>For small
gaps between the entries, we may also end up needing many iterations
before the solutions converge and if the data cannot be separated
properly into two distinct classes, we may not experience a converge
at all.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-better-approach">A better approach </h2>
<p>A better approach is rather to try to define a large margin between
the two classes (if they are well separated from the beginning).
</p>
<p>Thus, we wish to find a margin \( M \) with \( \boldsymbol{w} \) normalized to
\( \vert\vert \boldsymbol{w}\vert\vert =1 \) subject to the condition
</p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq M \hspace{0.1cm}\forall i=1,2,\dots, p.
$$
<p>All points are thus at a signed distance from the decision boundary defined by the line \( L \). The parameters \( b \) and \( w_1 \) and \( w_2 \) define this line. </p>
<p>We seek thus the largest value \( M \) defined by</p>
$$
\frac{1}{\vert \vert \boldsymbol{w}\vert\vert}y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq M \hspace{0.1cm}\forall i=1,2,\dots, n,
$$
<p>or just </p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq M\vert \vert \boldsymbol{w}\vert\vert \hspace{0.1cm}\forall i.
$$
<p>If we scale the equation so that \( \vert \vert \boldsymbol{w}\vert\vert = 1/M \), we have to find the minimum of
\( \boldsymbol{w}^T\boldsymbol{w}=\vert \vert \boldsymbol{w}\vert\vert \) (the norm) subject to the condition
</p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) \geq 1 \hspace{0.1cm}\forall i.
$$
<p>We have thus defined our margin as the invers of the norm of
\( \boldsymbol{w} \). We want to minimize the norm in order to have a as large as
possible margin \( M \). Before we proceed, we need to remind ourselves
about Lagrangian multipliers.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-quick-reminder-on-lagrangian-multipliers">A quick Reminder on Lagrangian Multipliers </h2>
<p>Consider a function of three independent variables \( f(x,y,z) \) . For the function \( f \) to be an
extreme we have
</p>
$$
df=0.
$$
<p>A necessary and sufficient condition is</p>
$$
\frac{\partial f}{\partial x} =\frac{\partial f}{\partial y}=\frac{\partial f}{\partial z}=0,
$$
<p>due to</p>
$$
df = \frac{\partial f}{\partial x}dx+\frac{\partial f}{\partial y}dy+\frac{\partial f}{\partial z}dz.
$$
<p>In many problems the variables \( x,y,z \) are often subject to constraints (such as those above for the margin)
so that they are no longer all independent. It is possible at least in principle to use each
constraint to eliminate one variable
and to proceed with a new and smaller set of independent varables.
</p>
<p>The use of so-called Lagrangian multipliers is an alternative technique when the elimination
of variables is incovenient or undesirable. Assume that we have an equation of constraint on
the variables \( x,y,z \)
</p>
$$
\phi(x,y,z) = 0,
$$
<p> resulting in</p>
$$
d\phi = \frac{\partial \phi}{\partial x}dx+\frac{\partial \phi}{\partial y}dy+\frac{\partial \phi}{\partial z}dz =0.
$$
<p>Now we cannot set anymore</p>
$$
\frac{\partial f}{\partial x} =\frac{\partial f}{\partial y}=\frac{\partial f}{\partial z}=0,
$$
<p>if \( df=0 \) is wanted
because there are now only two independent variables! Assume \( x \) and \( y \) are the independent
variables.
Then \( dz \) is no longer arbitrary.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="adding-the-multiplier">Adding the Multiplier </h2>
<p>However, we can add to</p>
$$
df = \frac{\partial f}{\partial x}dx+\frac{\partial f}{\partial y}dy+\frac{\partial f}{\partial z}dz,
$$
<p>a multiplum of \( d\phi \), viz. \( \lambda d\phi \), resulting in</p>
$$
df+\lambda d\phi = (\frac{\partial f}{\partial z}+\lambda
\frac{\partial \phi}{\partial x})dx+(\frac{\partial f}{\partial y}+\lambda\frac{\partial \phi}{\partial y})dy+
(\frac{\partial f}{\partial z}+\lambda\frac{\partial \phi}{\partial z})dz =0.
$$
<p>Our multiplier is chosen so that</p>
$$
\frac{\partial f}{\partial z}+\lambda\frac{\partial \phi}{\partial z} =0.
$$
<p>We need to remember that we took \( dx \) and \( dy \) to be arbitrary and thus we must have</p>
$$
\frac{\partial f}{\partial x}+\lambda\frac{\partial \phi}{\partial x} =0,
$$
<p>and</p>
$$
\frac{\partial f}{\partial y}+\lambda\frac{\partial \phi}{\partial y} =0.
$$
<p>When all these equations are satisfied, \( df=0 \). We have four unknowns, \( x,y,z \) and
\( \lambda \). Actually we want only \( x,y,z \), \( \lambda \) needs not to be determined,
it is therefore often called
Lagrange's undetermined multiplier.
If we have a set of constraints \( \phi_k \) we have the equations
</p>
$$
\frac{\partial f}{\partial x_i}+\sum_k\lambda_k\frac{\partial \phi_k}{\partial x_i} =0.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="setting-up-the-problem">Setting up the Problem </h2>
<p>In order to solve the above problem, we define the following Lagrangian function to be minimized </p>
$$
{\cal L}(\lambda,b,\boldsymbol{w})=\frac{1}{2}\boldsymbol{w}^T\boldsymbol{w}-\sum_{i=1}^n\lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)-1\right],
$$
<p>where \( \lambda_i \) is a so-called Lagrange multiplier subject to the condition \( \lambda_i \geq 0 \).</p>
<p>Taking the derivatives with respect to \( b \) and \( \boldsymbol{w} \) we obtain </p>
$$
\frac{\partial {\cal L}}{\partial b} = -\sum_{i} \lambda_iy_i=0,
$$
<p>and </p>
$$
\frac{\partial {\cal L}}{\partial \boldsymbol{w}} = 0 = \boldsymbol{w}-\sum_{i} \lambda_iy_i\boldsymbol{x}_i.
$$
<p>Inserting these constraints into the equation for \( {\cal L} \) we obtain</p>
$$
{\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{x}_j,
$$
<p>subject to the constraints \( \lambda_i\geq 0 \) and \( \sum_i\lambda_iy_i=0 \).
We must in addition satisfy the <a href="https://en.wikipedia.org/wiki/Karush%E2%80%93Kuhn%E2%80%93Tucker_conditions" target="_blank">Karush-Kuhn-Tucker</a> (KKT) condition
</p>
$$
\lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -1\right] \hspace{0.1cm}\forall i.
$$
<ol>
<li> If \( \lambda_i > 0 \), then \( y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1 \) and we say that \( x_i \) is on the boundary.</li>
<li> If \( y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)> 1 \), we say \( x_i \) is not on the boundary and we set \( \lambda_i=0 \).</li>
</ol>
<p>When \( \lambda_i > 0 \), the vectors \( \boldsymbol{x}_i \) are called support vectors. They are the vectors closest to the line (or hyperplane) and define the margin \( M \). </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-problem-to-solve">The problem to solve </h2>
<p>We can rewrite </p>
$$
{\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{x}_j,
$$
<p>and its constraints in terms of a matrix-vector problem where we minimize w.r.t. \( \lambda \) the following problem</p>
$$
\frac{1}{2} \boldsymbol{\lambda}^T\begin{bmatrix} y_1y_1\boldsymbol{x}_1^T\boldsymbol{x}_1 & y_1y_2\boldsymbol{x}_1^T\boldsymbol{x}_2 & \dots & \dots & y_1y_n\boldsymbol{x}_1^T\boldsymbol{x}_n \\
y_2y_1\boldsymbol{x}_2^T\boldsymbol{x}_1 & y_2y_2\boldsymbol{x}_2^T\boldsymbol{x}_2 & \dots & \dots & y_1y_n\boldsymbol{x}_2^T\boldsymbol{x}_n \\
\dots & \dots & \dots & \dots & \dots \\
\dots & \dots & \dots & \dots & \dots \\
y_ny_1\boldsymbol{x}_n^T\boldsymbol{x}_1 & y_ny_2\boldsymbol{x}_n^T\boldsymbol{x}_2 & \dots & \dots & y_ny_n\boldsymbol{x}_n^T\boldsymbol{x}_n \\
\end{bmatrix}\boldsymbol{\lambda}-\mathbb{1}\boldsymbol{\lambda},
$$
<p>subject to \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \). Here we defined the vectors \( \boldsymbol{\lambda} =[\lambda_1,\lambda_2,\dots,\lambda_n] \) and
\( \boldsymbol{y}=[y_1,y_2,\dots,y_n] \).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-last-steps">The last steps </h2>
<p>Solving the above problem, yields the values of \( \lambda_i \).
To find the coefficients of your hyperplane we need simply to compute
</p>
$$
\boldsymbol{w}=\sum_{i} \lambda_iy_i\boldsymbol{x}_i.
$$
<p>With our vector \( \boldsymbol{w} \) we can in turn find the value of the intercept \( b \) (here in two dimensions) via </p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1,
$$
<p>resulting in</p>
$$
b = \frac{1}{y_i}-\boldsymbol{w}^T\boldsymbol{x}_i,
$$
<p>or if we write it out in terms of the support vectors only, with \( N_s \) being their number, we have</p>
$$
b = \frac{1}{N_s}\sum_{j\in N_s}\left(y_j-\sum_{i=1}^n\lambda_iy_i\boldsymbol{x}_i^T\boldsymbol{x}_j\right).
$$
<p>With our hyperplane coefficients we can use our classifier to assign any observation by simply using </p>
$$
y_i = \mathrm{sign}(\boldsymbol{w}^T\boldsymbol{x}_i+b).
$$
<p>Below we discuss how to find the optimal values of \( \lambda_i \). Before we proceed however, we discuss now the so-called soft classifier. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-soft-classifier">A soft classifier </h2>
<p>Till now, the margin is strictly defined by the support vectors. This defines what is called a hard classifier, that is the margins are well defined.</p>
<p>Suppose now that classes overlap in feature space, as shown in the
figure here. One way to deal with this problem before we define the
so-called <b>kernel approach</b>, is to allow a kind of slack in the sense
that we allow some points to be on the wrong side of the margin.
</p>
<p>We introduce thus the so-called <b>slack</b> variables \( \boldsymbol{\xi} =[\xi_1,x_2,\dots,x_n] \) and
modify our previous equation
</p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1,
$$
<p>to </p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1-\xi_i,
$$
<p>with the requirement \( \xi_i\geq 0 \). The total violation is now \( \sum_i\xi \).
The value \( \xi_i \) in the constraint the last constraint corresponds to the amount by which the prediction
\( y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1 \) is on the wrong side of its margin. Hence by bounding the sum \( \sum_i \xi_i \),
we bound the total amount by which predictions fall on the wrong side of their margins.
</p>
<p>Misclassifications occur when \( \xi_i > 1 \). Thus bounding the total sum by some value \( C \) bounds in turn the total number of
misclassifications.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="soft-optmization-problem">Soft optmization problem </h2>
<p>This has in turn the consequences that we change our optmization problem to finding the minimum of </p>
$$
{\cal L}=\frac{1}{2}\boldsymbol{w}^T\boldsymbol{w}-\sum_{i=1}^n\lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)-(1-\xi_)\right]+C\sum_{i=1}^n\xi_i-\sum_{i=1}^n\gamma_i\xi_i,
$$
<p>subject to </p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b)=1-\xi_i \hspace{0.1cm}\forall i,
$$
<p>with the requirement \( \xi_i\geq 0 \).</p>
<p>Taking the derivatives with respect to \( b \) and \( \boldsymbol{w} \) we obtain </p>
$$
\frac{\partial {\cal L}}{\partial b} = -\sum_{i} \lambda_iy_i=0,
$$
<p>and </p>
$$
\frac{\partial {\cal L}}{\partial \boldsymbol{w}} = 0 = \boldsymbol{w}-\sum_{i} \lambda_iy_i\boldsymbol{x}_i,
$$
<p>and</p>
$$
\lambda_i = C-\gamma_i \hspace{0.1cm}\forall i.
$$
<p>Inserting these constraints into the equation for \( {\cal L} \) we obtain the same equation as before</p>
$$
{\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{x}_j,
$$
<p>but now subject to the constraints \( \lambda_i\geq 0 \), \( \sum_i\lambda_iy_i=0 \) and \( 0\leq\lambda_i \leq C \).
We must in addition satisfy the Karush-Kuhn-Tucker condition which now reads
</p>
$$
\lambda_i\left[y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -(1-\xi_)\right]=0 \hspace{0.1cm}\forall i,
$$
$$
\gamma_i\xi_i = 0,
$$
<p>and </p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{x}_i+b) -(1-\xi_) \geq 0 \hspace{0.1cm}\forall i.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="kernels-and-non-linearity">Kernels and non-linearity </h2>
<p>The cases we have studied till now, were all characterized by two classes
with a close to linear separability. The classifiers we have described
so far find linear boundaries in our input feature space. It is
possible to make our procedure more flexible by exploring the feature
space using other basis expansions such as higher-order polynomials,
wavelets, splines etc.
</p>
<p>If our feature space is not easy to separate, as shown in the figure
here, we can achieve a better separation by introducing more complex
basis functions. The ideal would be, as shown in the next figure, to, via a specific transformation to
obtain a separation between the classes which is almost linear.
</p>
<p>The change of basis, from \( x\rightarrow z=\phi(x) \) leads to the same type of equations to be solved, except that
we need to introduce for example a polynomial transformation to a two-dimensional training set.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">os</span>
np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>seed(<span style="color: #666666">42</span>)
<span style="color: #408080; font-style: italic"># To plot pretty figures</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;axes.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">14</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;xtick.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">12</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;ytick.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">12</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.svm</span> <span style="color: #008000; font-weight: bold">import</span> SVC
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn</span> <span style="color: #008000; font-weight: bold">import</span> datasets
X1D <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linspace(<span style="color: #666666">-4</span>, <span style="color: #666666">4</span>, <span style="color: #666666">9</span>)<span style="color: #666666">.</span>reshape(<span style="color: #666666">-1</span>, <span style="color: #666666">1</span>)
X2D <span style="color: #666666">=</span> np<span style="color: #666666">.</span>c_[X1D, X1D<span style="color: #666666">**2</span>]
y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>])
plt<span style="color: #666666">.</span>figure(figsize<span style="color: #666666">=</span>(<span style="color: #666666">11</span>, <span style="color: #666666">4</span>))
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">121</span>)
plt<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>, which<span style="color: #666666">=</span><span style="color: #BA2121">&#39;both&#39;</span>)
plt<span style="color: #666666">.</span>axhline(y<span style="color: #666666">=0</span>, color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;k&#39;</span>)
plt<span style="color: #666666">.</span>plot(X1D[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==0</span>], np<span style="color: #666666">.</span>zeros(<span style="color: #666666">4</span>), <span style="color: #BA2121">&quot;bs&quot;</span>)
plt<span style="color: #666666">.</span>plot(X1D[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==1</span>], np<span style="color: #666666">.</span>zeros(<span style="color: #666666">5</span>), <span style="color: #BA2121">&quot;g^&quot;</span>)
plt<span style="color: #666666">.</span>gca()<span style="color: #666666">.</span>get_yaxis()<span style="color: #666666">.</span>set_ticks([])
plt<span style="color: #666666">.</span>xlabel(<span style="color: #BA2121">r&quot;$x_1$&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>axis([<span style="color: #666666">-4.5</span>, <span style="color: #666666">4.5</span>, <span style="color: #666666">-0.2</span>, <span style="color: #666666">0.2</span>])
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">122</span>)
plt<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>, which<span style="color: #666666">=</span><span style="color: #BA2121">&#39;both&#39;</span>)
plt<span style="color: #666666">.</span>axhline(y<span style="color: #666666">=0</span>, color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;k&#39;</span>)
plt<span style="color: #666666">.</span>axvline(x<span style="color: #666666">=0</span>, color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;k&#39;</span>)
plt<span style="color: #666666">.</span>plot(X2D[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==0</span>], X2D[:, <span style="color: #666666">1</span>][y<span style="color: #666666">==0</span>], <span style="color: #BA2121">&quot;bs&quot;</span>)
plt<span style="color: #666666">.</span>plot(X2D[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==1</span>], X2D[:, <span style="color: #666666">1</span>][y<span style="color: #666666">==1</span>], <span style="color: #BA2121">&quot;g^&quot;</span>)
plt<span style="color: #666666">.</span>xlabel(<span style="color: #BA2121">r&quot;$x_1$&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>ylabel(<span style="color: #BA2121">r&quot;$x_2$&quot;</span>, fontsize<span style="color: #666666">=20</span>, rotation<span style="color: #666666">=0</span>)
plt<span style="color: #666666">.</span>gca()<span style="color: #666666">.</span>get_yaxis()<span style="color: #666666">.</span>set_ticks([<span style="color: #666666">0</span>, <span style="color: #666666">4</span>, <span style="color: #666666">8</span>, <span style="color: #666666">12</span>, <span style="color: #666666">16</span>])
plt<span style="color: #666666">.</span>plot([<span style="color: #666666">-4.5</span>, <span style="color: #666666">4.5</span>], [<span style="color: #666666">6.5</span>, <span style="color: #666666">6.5</span>], <span style="color: #BA2121">&quot;r--&quot;</span>, linewidth<span style="color: #666666">=3</span>)
plt<span style="color: #666666">.</span>axis([<span style="color: #666666">-4.5</span>, <span style="color: #666666">4.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">17</span>])
plt<span style="color: #666666">.</span>subplots_adjust(right<span style="color: #666666">=1</span>)
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-equations">The equations </h2>
<p>Suppose we define a polynomial transformation of degree two only (we continue to live in a plane with \( x_i \) and \( y_i \) as variables)</p>
$$
z = \phi(x_i) =\left(x_i^2, y_i^2, \sqrt{2}x_iy_i\right).
$$
<p>With our new basis, the equations we solved earlier are basically the same, that is we have now (without the slack option for simplicity)</p>
$$
{\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{z}_i^T\boldsymbol{z}_j,
$$
<p>subject to the constraints \( \lambda_i\geq 0 \), \( \sum_i\lambda_iy_i=0 \), and for the support vectors</p>
$$
y_i(\boldsymbol{w}^T\boldsymbol{z}_i+b)= 1 \hspace{0.1cm}\forall i,
$$
<p>from which we also find \( b \).
To compute \( \boldsymbol{z}_i^T\boldsymbol{z}_j \) we define the kernel \( K(\boldsymbol{x}_i,\boldsymbol{x}_j) \) as
</p>
$$
K(\boldsymbol{x}_i,\boldsymbol{x}_j)=\boldsymbol{z}_i^T\boldsymbol{z}_j= \phi(\boldsymbol{x}_i)^T\phi(\boldsymbol{x}_j).
$$
<p>For the above example, the kernel reads</p>
$$
K(\boldsymbol{x}_i,\boldsymbol{x}_j)=[x_i^2, y_i^2, \sqrt{2}x_iy_i]^T\begin{bmatrix} x_j^2 \\ y_j^2 \\ \sqrt{2}x_jy_j \end{bmatrix}=x_i^2x_j^2+2x_ix_jy_iy_j+y_i^2y_j^2.
$$
<p>We note that this is nothing but the dot product of the two original
vectors \( (\boldsymbol{x}_i^T\boldsymbol{x}_j)^2 \). Instead of thus computing the
product in the Lagrangian of \( \boldsymbol{z}_i^T\boldsymbol{z}_j \) we simply compute
the dot product \( (\boldsymbol{x}_i^T\boldsymbol{x}_j)^2 \).
</p>
<p>This leads to the so-called
kernel trick and the result leads to the same as if we went through
the trouble of performing the transformation
\( \phi(\boldsymbol{x}_i)^T\phi(\boldsymbol{x}_j) \) during the SVM calculations.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-problem-to-solve">The problem to solve </h2>
<p>Using our definition of the kernel We can rewrite again the Lagrangian</p>
$$
{\cal L}=\sum_i\lambda_i-\frac{1}{2}\sum_{ij}^n\lambda_i\lambda_jy_iy_j\boldsymbol{x}_i^T\boldsymbol{z}_j,
$$
<p>subject to the constraints \( \lambda_i\geq 0 \), \( \sum_i\lambda_iy_i=0 \) in terms of a convex optimization problem</p>
$$
\frac{1}{2} \boldsymbol{\lambda}^T\begin{bmatrix} y_1y_1K(\boldsymbol{x}_1,\boldsymbol{x}_1) & y_1y_2K(\boldsymbol{x}_1,\boldsymbol{x}_2) & \dots & \dots & y_1y_nK(\boldsymbol{x}_1,\boldsymbol{x}_n) \\
y_2y_1K(\boldsymbol{x}_2,\boldsymbol{x}_1) & y_2y_2(\boldsymbol{x}_2,\boldsymbol{x}_2) & \dots & \dots & y_1y_nK(\boldsymbol{x}_2,\boldsymbol{x}_n) \\
\dots & \dots & \dots & \dots & \dots \\
\dots & \dots & \dots & \dots & \dots \\
y_ny_1K(\boldsymbol{x}_n,\boldsymbol{x}_1) & y_ny_2K(\boldsymbol{x}_n\boldsymbol{x}_2) & \dots & \dots & y_ny_nK(\boldsymbol{x}_n,\boldsymbol{x}_n) \\
\end{bmatrix}\boldsymbol{\lambda}-\mathbb{1}\boldsymbol{\lambda},
$$
<p>subject to \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \). Here we defined the vectors \( \boldsymbol{\lambda} =[\lambda_1,\lambda_2,\dots,\lambda_n] \) and
\( \boldsymbol{y}=[y_1,y_2,\dots,y_n] \).
If we add the slack constants this leads to the additional constraint \( 0\leq \lambda_i \leq C \).
</p>
<p>We can rewrite this (see the solutions below) in terms of a convex optimization problem of the type</p>
$$
\begin{align*}
&\mathrm{min}_{\lambda}\hspace{0.2cm} \frac{1}{2}\boldsymbol{\lambda}^T\boldsymbol{P}\boldsymbol{\lambda}+\boldsymbol{q}^T\boldsymbol{\lambda},\\ \nonumber
&\mathrm{subject\hspace{0.1cm}to} \hspace{0.2cm} \boldsymbol{G}\boldsymbol{\lambda} \preceq \boldsymbol{h} \hspace{0.2cm} \wedge \boldsymbol{A}\boldsymbol{\lambda}=f.
\end{align*}
$$
<p>Below we discuss how to solve these equations. Here we note that the matrix \( \boldsymbol{P} \) has matrix elements \( p_{ij}=y_iy_jK(\boldsymbol{x}_i,\boldsymbol{x}_j) \).
Given a kernel \( K \) and the targets \( y_i \) this matrix is easy to set up. The constraint \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \) leads to \( f=0 \) and \( \boldsymbol{A}=\boldsymbol{y} \). How to set up the matrix \( \boldsymbol{G} \) is discussed later. Here note that the inequalities \( 0\leq \lambda_i \leq C \) can be split up into
\( 0\leq \lambda_i \) and \( \lambda_i \leq C \). These two inequalities define then the matrix \( \boldsymbol{G} \) and the vector \( \boldsymbol{h} \).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="different-kernels-and-mercer-s-theorem">Different kernels and Mercer's theorem </h2>
<p>There are several popular kernels being used. These are</p>
<ol>
<li> Linear: \( K(\boldsymbol{x},\boldsymbol{y})=\boldsymbol{x}^T\boldsymbol{y} \),</li>
<li> Polynomial: \( K(\boldsymbol{x},\boldsymbol{y})=(\boldsymbol{x}^T\boldsymbol{y}+\gamma)^d \),</li>
<li> Gaussian Radial Basis Function: \( K(\boldsymbol{x},\boldsymbol{y})=\exp{\left(-\gamma\vert\vert\boldsymbol{x}-\boldsymbol{y}\vert\vert^2\right)} \),</li>
<li> Tanh: \( K(\boldsymbol{x},\boldsymbol{y})=\tanh{(\boldsymbol{x}^T\boldsymbol{y}+\gamma)} \),</li>
</ol>
<p>and many other ones.</p>
<p>An important theorem for us is <a href="https://en.wikipedia.org/wiki/Mercer%27s_theorem" target="_blank">Mercer's
theorem</a>. The
theorem states that if a kernel function \( K \) is symmetric, continuous
and leads to a positive semi-definite matrix \( \boldsymbol{P} \) then there
exists a function \( \phi \) that maps \( \boldsymbol{x}_i \) and \( \boldsymbol{x}_j \) into
another space (possibly with much higher dimensions) such that
</p>
$$
K(\boldsymbol{x}_i,\boldsymbol{x}_j)=\phi(\boldsymbol{x}_i)^T\phi(\boldsymbol{x}_j).
$$
<p>So you can use \( K \) as a kernel since you know \( \phi \) exists, even if
you don&#8217;t know what \( \phi \) is.
</p>
<p>Note that some frequently used kernels (such as the Sigmoid kernel)
don&#8217;t respect all of Mercer&#8217;s conditions, yet they generally work well
in practice.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-moons-example">The moons example </h2>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">__future__</span> <span style="color: #008000; font-weight: bold">import</span> division, print_function, unicode_literals
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>seed(<span style="color: #666666">42</span>)
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;axes.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">14</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;xtick.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">12</span>
plt<span style="color: #666666">.</span>rcParams[<span style="color: #BA2121">&#39;ytick.labelsize&#39;</span>] <span style="color: #666666">=</span> <span style="color: #666666">12</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.svm</span> <span style="color: #008000; font-weight: bold">import</span> SVC
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn</span> <span style="color: #008000; font-weight: bold">import</span> datasets
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.pipeline</span> <span style="color: #008000; font-weight: bold">import</span> Pipeline
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.preprocessing</span> <span style="color: #008000; font-weight: bold">import</span> StandardScaler
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.svm</span> <span style="color: #008000; font-weight: bold">import</span> LinearSVC
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> make_moons
X, y <span style="color: #666666">=</span> make_moons(n_samples<span style="color: #666666">=100</span>, noise<span style="color: #666666">=0.15</span>, random_state<span style="color: #666666">=42</span>)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">plot_dataset</span>(X, y, axes):
plt<span style="color: #666666">.</span>plot(X[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==0</span>], X[:, <span style="color: #666666">1</span>][y<span style="color: #666666">==0</span>], <span style="color: #BA2121">&quot;bs&quot;</span>)
plt<span style="color: #666666">.</span>plot(X[:, <span style="color: #666666">0</span>][y<span style="color: #666666">==1</span>], X[:, <span style="color: #666666">1</span>][y<span style="color: #666666">==1</span>], <span style="color: #BA2121">&quot;g^&quot;</span>)
plt<span style="color: #666666">.</span>axis(axes)
plt<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>, which<span style="color: #666666">=</span><span style="color: #BA2121">&#39;both&#39;</span>)
plt<span style="color: #666666">.</span>xlabel(<span style="color: #BA2121">r&quot;$x_1$&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>ylabel(<span style="color: #BA2121">r&quot;$x_2$&quot;</span>, fontsize<span style="color: #666666">=20</span>, rotation<span style="color: #666666">=0</span>)
plot_dataset(X, y, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plt<span style="color: #666666">.</span>show()
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> make_moons
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.pipeline</span> <span style="color: #008000; font-weight: bold">import</span> Pipeline
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.preprocessing</span> <span style="color: #008000; font-weight: bold">import</span> PolynomialFeatures
polynomial_svm_clf <span style="color: #666666">=</span> Pipeline([
(<span style="color: #BA2121">&quot;poly_features&quot;</span>, PolynomialFeatures(degree<span style="color: #666666">=3</span>)),
(<span style="color: #BA2121">&quot;scaler&quot;</span>, StandardScaler()),
(<span style="color: #BA2121">&quot;svm_clf&quot;</span>, LinearSVC(C<span style="color: #666666">=10</span>, loss<span style="color: #666666">=</span><span style="color: #BA2121">&quot;hinge&quot;</span>, random_state<span style="color: #666666">=42</span>))
])
polynomial_svm_clf<span style="color: #666666">.</span>fit(X, y)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">plot_predictions</span>(clf, axes):
x0s <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linspace(axes[<span style="color: #666666">0</span>], axes[<span style="color: #666666">1</span>], <span style="color: #666666">100</span>)
x1s <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linspace(axes[<span style="color: #666666">2</span>], axes[<span style="color: #666666">3</span>], <span style="color: #666666">100</span>)
x0, x1 <span style="color: #666666">=</span> np<span style="color: #666666">.</span>meshgrid(x0s, x1s)
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>c_[x0<span style="color: #666666">.</span>ravel(), x1<span style="color: #666666">.</span>ravel()]
y_pred <span style="color: #666666">=</span> clf<span style="color: #666666">.</span>predict(X)<span style="color: #666666">.</span>reshape(x0<span style="color: #666666">.</span>shape)
y_decision <span style="color: #666666">=</span> clf<span style="color: #666666">.</span>decision_function(X)<span style="color: #666666">.</span>reshape(x0<span style="color: #666666">.</span>shape)
plt<span style="color: #666666">.</span>contourf(x0, x1, y_pred, cmap<span style="color: #666666">=</span>plt<span style="color: #666666">.</span>cm<span style="color: #666666">.</span>brg, alpha<span style="color: #666666">=0.2</span>)
plt<span style="color: #666666">.</span>contourf(x0, x1, y_decision, cmap<span style="color: #666666">=</span>plt<span style="color: #666666">.</span>cm<span style="color: #666666">.</span>brg, alpha<span style="color: #666666">=0.1</span>)
plot_predictions(polynomial_svm_clf, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plot_dataset(X, y, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plt<span style="color: #666666">.</span>show()
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.svm</span> <span style="color: #008000; font-weight: bold">import</span> SVC
poly_kernel_svm_clf <span style="color: #666666">=</span> Pipeline([
(<span style="color: #BA2121">&quot;scaler&quot;</span>, StandardScaler()),
(<span style="color: #BA2121">&quot;svm_clf&quot;</span>, SVC(kernel<span style="color: #666666">=</span><span style="color: #BA2121">&quot;poly&quot;</span>, degree<span style="color: #666666">=3</span>, coef0<span style="color: #666666">=1</span>, C<span style="color: #666666">=5</span>))
])
poly_kernel_svm_clf<span style="color: #666666">.</span>fit(X, y)
poly100_kernel_svm_clf <span style="color: #666666">=</span> Pipeline([
(<span style="color: #BA2121">&quot;scaler&quot;</span>, StandardScaler()),
(<span style="color: #BA2121">&quot;svm_clf&quot;</span>, SVC(kernel<span style="color: #666666">=</span><span style="color: #BA2121">&quot;poly&quot;</span>, degree<span style="color: #666666">=10</span>, coef0<span style="color: #666666">=100</span>, C<span style="color: #666666">=5</span>))
])
poly100_kernel_svm_clf<span style="color: #666666">.</span>fit(X, y)
plt<span style="color: #666666">.</span>figure(figsize<span style="color: #666666">=</span>(<span style="color: #666666">11</span>, <span style="color: #666666">4</span>))
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">121</span>)
plot_predictions(poly_kernel_svm_clf, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plot_dataset(X, y, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plt<span style="color: #666666">.</span>title(<span style="color: #BA2121">r&quot;$d=3, r=1, C=5$&quot;</span>, fontsize<span style="color: #666666">=18</span>)
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">122</span>)
plot_predictions(poly100_kernel_svm_clf, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plot_dataset(X, y, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plt<span style="color: #666666">.</span>title(<span style="color: #BA2121">r&quot;$d=10, r=100, C=5$&quot;</span>, fontsize<span style="color: #666666">=18</span>)
plt<span style="color: #666666">.</span>show()
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">gaussian_rbf</span>(x, landmark, gamma):
<span style="color: #008000; font-weight: bold">return</span> np<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>gamma <span style="color: #666666">*</span> np<span style="color: #666666">.</span>linalg<span style="color: #666666">.</span>norm(x <span style="color: #666666">-</span> landmark, axis<span style="color: #666666">=1</span>)<span style="color: #666666">**2</span>)
gamma <span style="color: #666666">=</span> <span style="color: #666666">0.3</span>
x1s <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linspace(<span style="color: #666666">-4.5</span>, <span style="color: #666666">4.5</span>, <span style="color: #666666">200</span>)<span style="color: #666666">.</span>reshape(<span style="color: #666666">-1</span>, <span style="color: #666666">1</span>)
x2s <span style="color: #666666">=</span> gaussian_rbf(x1s, <span style="color: #666666">-2</span>, gamma)
x3s <span style="color: #666666">=</span> gaussian_rbf(x1s, <span style="color: #666666">1</span>, gamma)
XK <span style="color: #666666">=</span> np<span style="color: #666666">.</span>c_[gaussian_rbf(X1D, <span style="color: #666666">-2</span>, gamma), gaussian_rbf(X1D, <span style="color: #666666">1</span>, gamma)]
yk <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>])
plt<span style="color: #666666">.</span>figure(figsize<span style="color: #666666">=</span>(<span style="color: #666666">11</span>, <span style="color: #666666">4</span>))
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">121</span>)
plt<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>, which<span style="color: #666666">=</span><span style="color: #BA2121">&#39;both&#39;</span>)
plt<span style="color: #666666">.</span>axhline(y<span style="color: #666666">=0</span>, color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;k&#39;</span>)
plt<span style="color: #666666">.</span>scatter(x<span style="color: #666666">=</span>[<span style="color: #666666">-2</span>, <span style="color: #666666">1</span>], y<span style="color: #666666">=</span>[<span style="color: #666666">0</span>, <span style="color: #666666">0</span>], s<span style="color: #666666">=150</span>, alpha<span style="color: #666666">=0.5</span>, c<span style="color: #666666">=</span><span style="color: #BA2121">&quot;red&quot;</span>)
plt<span style="color: #666666">.</span>plot(X1D[:, <span style="color: #666666">0</span>][yk<span style="color: #666666">==0</span>], np<span style="color: #666666">.</span>zeros(<span style="color: #666666">4</span>), <span style="color: #BA2121">&quot;bs&quot;</span>)
plt<span style="color: #666666">.</span>plot(X1D[:, <span style="color: #666666">0</span>][yk<span style="color: #666666">==1</span>], np<span style="color: #666666">.</span>zeros(<span style="color: #666666">5</span>), <span style="color: #BA2121">&quot;g^&quot;</span>)
plt<span style="color: #666666">.</span>plot(x1s, x2s, <span style="color: #BA2121">&quot;g--&quot;</span>)
plt<span style="color: #666666">.</span>plot(x1s, x3s, <span style="color: #BA2121">&quot;b:&quot;</span>)
plt<span style="color: #666666">.</span>gca()<span style="color: #666666">.</span>get_yaxis()<span style="color: #666666">.</span>set_ticks([<span style="color: #666666">0</span>, <span style="color: #666666">0.25</span>, <span style="color: #666666">0.5</span>, <span style="color: #666666">0.75</span>, <span style="color: #666666">1</span>])
plt<span style="color: #666666">.</span>xlabel(<span style="color: #BA2121">r&quot;$x_1$&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>ylabel(<span style="color: #BA2121">r&quot;Similarity&quot;</span>, fontsize<span style="color: #666666">=14</span>)
plt<span style="color: #666666">.</span>annotate(<span style="color: #BA2121">r&#39;$\mathbf</span><span style="color: #BB6688; font-weight: bold">{x}</span><span style="color: #BA2121">$&#39;</span>,
xy<span style="color: #666666">=</span>(X1D[<span style="color: #666666">3</span>, <span style="color: #666666">0</span>], <span style="color: #666666">0</span>),
xytext<span style="color: #666666">=</span>(<span style="color: #666666">-0.5</span>, <span style="color: #666666">0.20</span>),
ha<span style="color: #666666">=</span><span style="color: #BA2121">&quot;center&quot;</span>,
arrowprops<span style="color: #666666">=</span><span style="color: #008000">dict</span>(facecolor<span style="color: #666666">=</span><span style="color: #BA2121">&#39;black&#39;</span>, shrink<span style="color: #666666">=0.1</span>),
fontsize<span style="color: #666666">=18</span>,
)
plt<span style="color: #666666">.</span>text(<span style="color: #666666">-2</span>, <span style="color: #666666">0.9</span>, <span style="color: #BA2121">&quot;$x_2$&quot;</span>, ha<span style="color: #666666">=</span><span style="color: #BA2121">&quot;center&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>text(<span style="color: #666666">1</span>, <span style="color: #666666">0.9</span>, <span style="color: #BA2121">&quot;$x_3$&quot;</span>, ha<span style="color: #666666">=</span><span style="color: #BA2121">&quot;center&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>axis([<span style="color: #666666">-4.5</span>, <span style="color: #666666">4.5</span>, <span style="color: #666666">-0.1</span>, <span style="color: #666666">1.1</span>])
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">122</span>)
plt<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>, which<span style="color: #666666">=</span><span style="color: #BA2121">&#39;both&#39;</span>)
plt<span style="color: #666666">.</span>axhline(y<span style="color: #666666">=0</span>, color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;k&#39;</span>)
plt<span style="color: #666666">.</span>axvline(x<span style="color: #666666">=0</span>, color<span style="color: #666666">=</span><span style="color: #BA2121">&#39;k&#39;</span>)
plt<span style="color: #666666">.</span>plot(XK[:, <span style="color: #666666">0</span>][yk<span style="color: #666666">==0</span>], XK[:, <span style="color: #666666">1</span>][yk<span style="color: #666666">==0</span>], <span style="color: #BA2121">&quot;bs&quot;</span>)
plt<span style="color: #666666">.</span>plot(XK[:, <span style="color: #666666">0</span>][yk<span style="color: #666666">==1</span>], XK[:, <span style="color: #666666">1</span>][yk<span style="color: #666666">==1</span>], <span style="color: #BA2121">&quot;g^&quot;</span>)
plt<span style="color: #666666">.</span>xlabel(<span style="color: #BA2121">r&quot;$x_2$&quot;</span>, fontsize<span style="color: #666666">=20</span>)
plt<span style="color: #666666">.</span>ylabel(<span style="color: #BA2121">r&quot;$x_3$ &quot;</span>, fontsize<span style="color: #666666">=20</span>, rotation<span style="color: #666666">=0</span>)
plt<span style="color: #666666">.</span>annotate(<span style="color: #BA2121">r&#39;$\phi\left(\mathbf</span><span style="color: #BB6688; font-weight: bold">{x}</span><span style="color: #BA2121">\right)$&#39;</span>,
xy<span style="color: #666666">=</span>(XK[<span style="color: #666666">3</span>, <span style="color: #666666">0</span>], XK[<span style="color: #666666">3</span>, <span style="color: #666666">1</span>]),
xytext<span style="color: #666666">=</span>(<span style="color: #666666">0.65</span>, <span style="color: #666666">0.50</span>),
ha<span style="color: #666666">=</span><span style="color: #BA2121">&quot;center&quot;</span>,
arrowprops<span style="color: #666666">=</span><span style="color: #008000">dict</span>(facecolor<span style="color: #666666">=</span><span style="color: #BA2121">&#39;black&#39;</span>, shrink<span style="color: #666666">=0.1</span>),
fontsize<span style="color: #666666">=18</span>,
)
plt<span style="color: #666666">.</span>plot([<span style="color: #666666">-0.1</span>, <span style="color: #666666">1.1</span>], [<span style="color: #666666">0.57</span>, <span style="color: #666666">-0.1</span>], <span style="color: #BA2121">&quot;r--&quot;</span>, linewidth<span style="color: #666666">=3</span>)
plt<span style="color: #666666">.</span>axis([<span style="color: #666666">-0.1</span>, <span style="color: #666666">1.1</span>, <span style="color: #666666">-0.1</span>, <span style="color: #666666">1.1</span>])
plt<span style="color: #666666">.</span>subplots_adjust(right<span style="color: #666666">=1</span>)
plt<span style="color: #666666">.</span>show()
x1_example <span style="color: #666666">=</span> X1D[<span style="color: #666666">3</span>, <span style="color: #666666">0</span>]
<span style="color: #008000; font-weight: bold">for</span> landmark <span style="color: #AA22FF; font-weight: bold">in</span> (<span style="color: #666666">-2</span>, <span style="color: #666666">1</span>):
k <span style="color: #666666">=</span> gaussian_rbf(np<span style="color: #666666">.</span>array([[x1_example]]), np<span style="color: #666666">.</span>array([[landmark]]), gamma)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Phi(</span><span style="color: #BB6688; font-weight: bold">{}</span><span style="color: #BA2121">, </span><span style="color: #BB6688; font-weight: bold">{}</span><span style="color: #BA2121">) = </span><span style="color: #BB6688; font-weight: bold">{}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(x1_example, landmark, k))
rbf_kernel_svm_clf <span style="color: #666666">=</span> Pipeline([
(<span style="color: #BA2121">&quot;scaler&quot;</span>, StandardScaler()),
(<span style="color: #BA2121">&quot;svm_clf&quot;</span>, SVC(kernel<span style="color: #666666">=</span><span style="color: #BA2121">&quot;rbf&quot;</span>, gamma<span style="color: #666666">=5</span>, C<span style="color: #666666">=0.001</span>))
])
rbf_kernel_svm_clf<span style="color: #666666">.</span>fit(X, y)
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.svm</span> <span style="color: #008000; font-weight: bold">import</span> SVC
gamma1, gamma2 <span style="color: #666666">=</span> <span style="color: #666666">0.1</span>, <span style="color: #666666">5</span>
C1, C2 <span style="color: #666666">=</span> <span style="color: #666666">0.001</span>, <span style="color: #666666">1000</span>
hyperparams <span style="color: #666666">=</span> (gamma1, C1), (gamma1, C2), (gamma2, C1), (gamma2, C2)
svm_clfs <span style="color: #666666">=</span> []
<span style="color: #008000; font-weight: bold">for</span> gamma, C <span style="color: #AA22FF; font-weight: bold">in</span> hyperparams:
rbf_kernel_svm_clf <span style="color: #666666">=</span> Pipeline([
(<span style="color: #BA2121">&quot;scaler&quot;</span>, StandardScaler()),
(<span style="color: #BA2121">&quot;svm_clf&quot;</span>, SVC(kernel<span style="color: #666666">=</span><span style="color: #BA2121">&quot;rbf&quot;</span>, gamma<span style="color: #666666">=</span>gamma, C<span style="color: #666666">=</span>C))
])
rbf_kernel_svm_clf<span style="color: #666666">.</span>fit(X, y)
svm_clfs<span style="color: #666666">.</span>append(rbf_kernel_svm_clf)
plt<span style="color: #666666">.</span>figure(figsize<span style="color: #666666">=</span>(<span style="color: #666666">11</span>, <span style="color: #666666">7</span>))
<span style="color: #008000; font-weight: bold">for</span> i, svm_clf <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">enumerate</span>(svm_clfs):
plt<span style="color: #666666">.</span>subplot(<span style="color: #666666">221</span> <span style="color: #666666">+</span> i)
plot_predictions(svm_clf, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
plot_dataset(X, y, [<span style="color: #666666">-1.5</span>, <span style="color: #666666">2.5</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">1.5</span>])
gamma, C <span style="color: #666666">=</span> hyperparams[i]
plt<span style="color: #666666">.</span>title(<span style="color: #BA2121">r&quot;$\gamma = </span><span style="color: #BB6688; font-weight: bold">{}</span><span style="color: #BA2121">, C = </span><span style="color: #BB6688; font-weight: bold">{}</span><span style="color: #BA2121">$&quot;</span><span style="color: #666666">.</span>format(gamma, C), fontsize<span style="color: #666666">=16</span>)
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-optimization-of-convex-functions">Mathematical optimization of convex functions </h2>
<p>A mathematical (quadratic) optimization problem, or just optimization problem, has the form</p>
$$
\begin{align*}
&\mathrm{min}_{\lambda}\hspace{0.2cm} \frac{1}{2}\boldsymbol{\lambda}^T\boldsymbol{P}\boldsymbol{\lambda}+\boldsymbol{q}^T\boldsymbol{\lambda},\\ \nonumber
&\mathrm{subject\hspace{0.1cm}to} \hspace{0.2cm} \boldsymbol{G}\boldsymbol{\lambda} \preceq \boldsymbol{h} \wedge \boldsymbol{A}\boldsymbol{\lambda}=f.
\end{align*}
$$
<p>subject to some constraints for say a selected set \( i=1,2,\dots, n \).
In our case we are optimizing with respect to the Lagrangian multipliers \( \lambda_i \), and the
vector \( \boldsymbol{\lambda}=[\lambda_1, \lambda_2,\dots, \lambda_n] \) is the optimization variable we are dealing with.
</p>
<p>In our case we are particularly interested in a class of optimization problems called convex optmization problems.
In our discussion on gradient descent methods we discussed at length the definition of a convex function.
</p>
<p>Convex optimization problems play a central role in applied mathematics and we recommend strongly <a href="http://web.stanford.edu/~boyd/cvxbook/" target="_blank">Boyd and Vandenberghe's text on the topics</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="how-do-we-solve-these-problems">How do we solve these problems? </h2>
<p>If we use Python as programming language and wish to venture beyond
<b>scikit-learn</b>, <b>tensorflow</b> and similar software which makes our
lives so much easier, we need to dive into the wonderful world of
quadratic programming. We can, if we wish, solve the minimization
problem using say standard gradient methods or conjugate gradient
methods. However, these methods tend to exhibit a rather slow
converge. So, welcome to the promised land of quadratic programming.
</p>
<p>The functions we need are contained in the <a href="https://cvxopt.org/userguide/coneprog.html" target="_blank">quadratic programming library CVXOPT</a> and we need to import it together with <b>numpy</b> as</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">cvxopt</span>
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>This will make our life much easier. You don't need t0 write your own optimizer.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-simple-example">A simple example </h2>
<p>We remind ourselves about the general problem we want to solve</p>
$$
\begin{align*}
&\mathrm{min}_{x}\hspace{0.2cm} \frac{1}{2}\boldsymbol{x}^T\boldsymbol{P}\boldsymbol{x}+\boldsymbol{q}^T\boldsymbol{x},\\ \nonumber
&\mathrm{subject\hspace{0.1cm} to} \hspace{0.2cm} \boldsymbol{G}\boldsymbol{x} \preceq \boldsymbol{h} \wedge \boldsymbol{A}\boldsymbol{x}=f.
\end{align*}
$$
<p>Let us show how to perform the optmization using a simple case. Assume we want to optimize the following problem</p>
$$
\begin{align*}
&\mathrm{min}_{x}\hspace{0.2cm} \frac{1}{2}x^2+5x+3y \\ \nonumber
&\mathrm{subject}\hspace{0.5cm} \mathrm{to} \\ \nonumber
&x, y \geq 0 \\ \nonumber
&x+3y \geq 15 \\ \nonumber
&2x+5y \leq 100 \\ \nonumber
&3x+4y \leq 80. \\ \nonumber
\end{align*}
$$
<p>The minimization problem can be rewritten in terms of vectors and matrices as (with \( x \) and \( y \) being the unknowns)</p>
$$
\frac{1}{2}\begin{bmatrix} x\\ y \end{bmatrix}^T \begin{bmatrix} 1 & 0\\ 0 & 0 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix}3\\ 4 \end{bmatrix}^T \begin{bmatrix}x \\ y \end{bmatrix}.
$$
<p>Similarly, we can now set up the inequalities (we need to change \( \geq \) to \( \leq \) by multiplying with \( -1 \) on bot sides) as the following matrix-vector equation</p>
$$
\begin{bmatrix} -1 & 0 \\ 0 & -1 \\ -1 & -3 \\ 2 & 5 \\ 3 & 4\end{bmatrix}\begin{bmatrix} x \\ y\end{bmatrix} \preceq \begin{bmatrix}0 \\ 0\\ -15 \\ 100 \\ 80\end{bmatrix}.
$$
<p>We have collapsed all the inequalities into a single matrix \( \boldsymbol{G} \). We see also that our matrix </p>
$$
\boldsymbol{P} =\begin{bmatrix} 1 & 0\\ 0 & 0 \end{bmatrix}
$$
<p>is clearly positive semi-definite (all eigenvalues larger or equal zero).
Finally, the vector \( \boldsymbol{h} \) is defined as
</p>
$$
\boldsymbol{h} = \begin{bmatrix}0 \\ 0\\ -15 \\ 100 \\ 80\end{bmatrix}.
$$
<p>Since we don't have any equalities the matrix \( \boldsymbol{A} \) is set to zero
The following code solves the equations for us
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># Import the necessary packages</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">cvxopt</span> <span style="color: #008000; font-weight: bold">import</span> matrix
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">cvxopt</span> <span style="color: #008000; font-weight: bold">import</span> solvers
P <span style="color: #666666">=</span> matrix(numpy<span style="color: #666666">.</span>diag([<span style="color: #666666">1</span>,<span style="color: #666666">0</span>]), tc<span style="color: #666666">=</span><span style="color: #BA2121">&#39;d&#39;</span>)
q <span style="color: #666666">=</span> matrix(numpy<span style="color: #666666">.</span>array([<span style="color: #666666">3</span>,<span style="color: #666666">4</span>]), tc<span style="color: #666666">=</span><span style="color: #BA2121">&#39;d&#39;</span>)
G <span style="color: #666666">=</span> matrix(numpy<span style="color: #666666">.</span>array([[<span style="color: #666666">-1</span>,<span style="color: #666666">0</span>],[<span style="color: #666666">0</span>,<span style="color: #666666">-1</span>],[<span style="color: #666666">-1</span>,<span style="color: #666666">-3</span>],[<span style="color: #666666">2</span>,<span style="color: #666666">5</span>],[<span style="color: #666666">3</span>,<span style="color: #666666">4</span>]]), tc<span style="color: #666666">=</span><span style="color: #BA2121">&#39;d&#39;</span>)
h <span style="color: #666666">=</span> matrix(numpy<span style="color: #666666">.</span>array([<span style="color: #666666">0</span>,<span style="color: #666666">0</span>,<span style="color: #666666">-15</span>,<span style="color: #666666">100</span>,<span style="color: #666666">80</span>]), tc<span style="color: #666666">=</span><span style="color: #BA2121">&#39;d&#39;</span>)
<span style="color: #408080; font-style: italic"># Construct the QP, invoke solver</span>
sol <span style="color: #666666">=</span> solvers<span style="color: #666666">.</span>qp(P,q,G,h)
<span style="color: #408080; font-style: italic"># Extract optimal value and solution</span>
sol[<span style="color: #BA2121">&#39;x&#39;</span>]
sol[<span style="color: #BA2121">&#39;primal objective&#39;</span>]
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="back-to-the-more-realistic-cases">Back to the more realistic cases </h2>
<p>We are now ready to return to our setup of the optmization problem for a more realistic case. Introducing the <b>slack</b> parameter \( C \) we have</p>
$$
\frac{1}{2} \boldsymbol{\lambda}^T\begin{bmatrix} y_1y_1K(\boldsymbol{x}_1,\boldsymbol{x}_1) & y_1y_2K(\boldsymbol{x}_1,\boldsymbol{x}_2) & \dots & \dots & y_1y_nK(\boldsymbol{x}_1,\boldsymbol{x}_n) \\
y_2y_1K(\boldsymbol{x}_2,\boldsymbol{x}_1) & y_2y_2K(\boldsymbol{x}_2,\boldsymbol{x}_2) & \dots & \dots & y_1y_nK(\boldsymbol{x}_2,\boldsymbol{x}_n) \\
\dots & \dots & \dots & \dots & \dots \\
\dots & \dots & \dots & \dots & \dots \\
y_ny_1K(\boldsymbol{x}_n,\boldsymbol{x}_1) & y_ny_2K(\boldsymbol{x}_n\boldsymbol{x}_2) & \dots & \dots & y_ny_nK(\boldsymbol{x}_n,\boldsymbol{x}_n) \\
\end{bmatrix}\boldsymbol{\lambda}-\mathbb{I}\boldsymbol{\lambda},
$$
<p>subject to \( \boldsymbol{y}^T\boldsymbol{\lambda}=0 \). Here we defined the vectors \( \boldsymbol{\lambda} =[\lambda_1,\lambda_2,\dots,\lambda_n] \) and
\( \boldsymbol{y}=[y_1,y_2,\dots,y_n] \).
With the slack constants this leads to the additional constraint \( 0\leq \lambda_i \leq C \).
</p>
<p>Using the <b>CVXOPT</b> library, the matrix \( P \) would then be defined by the </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="basic-ideas-of-the-principal-component-analysis-pca">Basic ideas of the Principal Component Analysis (PCA) </h2>
<p>The principal component analysis deals with the problem of fitting a
low-dimensional affine subspace \( S \) of dimension \( d \) much smaller than
the total dimension \( D \) of the problem at hand (our data
set). Mathematically it can be formulated as a statistical problem or
a geometric problem. In our discussion of the theorem for the
classical PCA, we will stay with a statistical approach.
Historically, the PCA was first formulated in a statistical setting in order to estimate the principal component of a multivariate random variable.
</p>
<p>We have a data set defined by a design/feature matrix \( \boldsymbol{X} \) (see below for its definition) </p>
<ul>
<li> Each data point is determined by \( p \) extrinsic (measurement) variables</li>
<li> We may want to ask the following question: Are there fewer intrinsic variables (say \( d < < p \)) that still approximately describe the data?</li>
<li> If so, these intrinsic variables may tell us something important and finding these intrinsic variables is what dimension reduction methods do.</li>
</ul>
<p>A good read is for example <a href="https://www.springer.com/gp/book/9780387878102" target="_blank">Vidal, Ma and Sastry</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="introducing-the-covariance-and-correlation-functions">Introducing the Covariance and Correlation functions </h2>
<p>Before we discuss the PCA theorem, we need to remind ourselves about
the definition of the covariance and the correlation function. These are quantities
</p>
<p>Suppose we have defined two vectors
\( \hat{x} \) and \( \hat{y} \) with \( n \) elements each. The covariance matrix \( \boldsymbol{C} \) is defined as
</p>
$$
\boldsymbol{C}[\boldsymbol{x},\boldsymbol{y}] = \begin{bmatrix} \mathrm{cov}[\boldsymbol{x},\boldsymbol{x}] & \mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] \\
\mathrm{cov}[\boldsymbol{y},\boldsymbol{x}] & \mathrm{cov}[\boldsymbol{y},\boldsymbol{y}] \\
\end{bmatrix},
$$
<p>where for example</p>
$$
\mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] =\frac{1}{n} \sum_{i=0}^{n-1}(x_i- \overline{x})(y_i- \overline{y}).
$$
<p>With this definition and recalling that the variance is defined as</p>
$$
\mathrm{var}[\boldsymbol{x}]=\frac{1}{n} \sum_{i=0}^{n-1}(x_i- \overline{x})^2,
$$
<p>we can rewrite the covariance matrix as </p>
$$
\boldsymbol{C}[\boldsymbol{x},\boldsymbol{y}] = \begin{bmatrix} \mathrm{var}[\boldsymbol{x}] & \mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] \\
\mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] & \mathrm{var}[\boldsymbol{y}] \\
\end{bmatrix}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-on-the-covariance">More on the covariance </h2>
<p>The covariance takes values between zero and infinity and may thus
lead to problems with loss of numerical precision for particularly
large values. It is common to scale the covariance matrix by
introducing instead the correlation matrix defined via the so-called
correlation function
</p>
$$
\mathrm{corr}[\boldsymbol{x},\boldsymbol{y}]=\frac{\mathrm{cov}[\boldsymbol{x},\boldsymbol{y}]}{\sqrt{\mathrm{var}[\boldsymbol{x}] \mathrm{var}[\boldsymbol{y}]}}.
$$
<p>The correlation function is then given by values \( \mathrm{corr}[\boldsymbol{x},\boldsymbol{y}]
\in [-1,1] \). This avoids eventual problems with too large values. We
can then define the correlation matrix for the two vectors \( \boldsymbol{x} \)
and \( \boldsymbol{y} \) as
</p>
$$
\boldsymbol{K}[\boldsymbol{x},\boldsymbol{y}] = \begin{bmatrix} 1 & \mathrm{corr}[\boldsymbol{x},\boldsymbol{y}] \\
\mathrm{corr}[\boldsymbol{y},\boldsymbol{x}] & 1 \\
\end{bmatrix},
$$
<p>In the above example this is the function we constructed using <b>pandas</b>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="reminding-ourselves-about-linear-regression">Reminding ourselves about Linear Regression </h2>
<p>In our derivation of the various regression algorithms like <b>Ordinary Least Squares</b> or <b>Ridge regression</b>
we defined the design/feature matrix \( \boldsymbol{X} \) as
</p>
$$
\boldsymbol{X}=\begin{bmatrix}
x_{0,0} & x_{0,1} & x_{0,2}& \dots & \dots x_{0,p-1}\\
x_{1,0} & x_{1,1} & x_{1,2}& \dots & \dots x_{1,p-1}\\
x_{2,0} & x_{2,1} & x_{2,2}& \dots & \dots x_{2,p-1}\\
\dots & \dots & \dots & \dots \dots & \dots \\
x_{n-2,0} & x_{n-2,1} & x_{n-2,2}& \dots & \dots x_{n-2,p-1}\\
x_{n-1,0} & x_{n-1,1} & x_{n-1,2}& \dots & \dots x_{n-1,p-1}\\
\end{bmatrix},
$$
<p>with \( \boldsymbol{X}\in {\mathbb{R}}^{n\times p} \), with the predictors/features \( p \) refering to the column numbers and the
entries \( n \) being the row elements.
We can rewrite the design/feature matrix in terms of its column vectors as
</p>
$$
\boldsymbol{X}=\begin{bmatrix} \boldsymbol{x}_0 & \boldsymbol{x}_1 & \boldsymbol{x}_2 & \dots & \dots & \boldsymbol{x}_{p-1}\end{bmatrix},
$$
<p>with a given vector</p>
$$
\boldsymbol{x}_i^T = \begin{bmatrix}x_{0,i} & x_{1,i} & x_{2,i}& \dots & \dots x_{n-1,i}\end{bmatrix}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="simple-example">Simple Example </h2>
<p>With these definitions, we can now rewrite our \( 2\times 2 \)
correlation/covariance matrix in terms of a moe general design/feature
matrix \( \boldsymbol{X}\in {\mathbb{R}}^{n\times p} \). This leads to a \( p\times p \)
covariance matrix for the vectors \( \boldsymbol{x}_i \) with \( i=0,1,\dots,p-1 \)
</p>
$$
\boldsymbol{C}[\boldsymbol{x}] = \begin{bmatrix}
\mathrm{var}[\boldsymbol{x}_0] & \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_1] & \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_2] & \dots & \dots & \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_{p-1}]\\
\mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_0] & \mathrm{var}[\boldsymbol{x}_1] & \mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_2] & \dots & \dots & \mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_{p-1}]\\
\mathrm{cov}[\boldsymbol{x}_2,\boldsymbol{x}_0] & \mathrm{cov}[\boldsymbol{x}_2,\boldsymbol{x}_1] & \mathrm{var}[\boldsymbol{x}_2] & \dots & \dots & \mathrm{cov}[\boldsymbol{x}_2,\boldsymbol{x}_{p-1}]\\
\dots & \dots & \dots & \dots & \dots & \dots \\
\dots & \dots & \dots & \dots & \dots & \dots \\
\mathrm{cov}[\boldsymbol{x}_{p-1},\boldsymbol{x}_0] & \mathrm{cov}[\boldsymbol{x}_{p-1},\boldsymbol{x}_1] & \mathrm{cov}[\boldsymbol{x}_{p-1},\boldsymbol{x}_{2}] & \dots & \dots & \mathrm{var}[\boldsymbol{x}_{p-1}]\\
\end{bmatrix},
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-correlation-matrix">The Correlation Matrix </h2>
<p>and the correlation matrix</p>
$$
\boldsymbol{K}[\boldsymbol{x}] = \begin{bmatrix}
1 & \mathrm{corr}[\boldsymbol{x}_0,\boldsymbol{x}_1] & \mathrm{corr}[\boldsymbol{x}_0,\boldsymbol{x}_2] & \dots & \dots & \mathrm{corr}[\boldsymbol{x}_0,\boldsymbol{x}_{p-1}]\\
\mathrm{corr}[\boldsymbol{x}_1,\boldsymbol{x}_0] & 1 & \mathrm{corr}[\boldsymbol{x}_1,\boldsymbol{x}_2] & \dots & \dots & \mathrm{corr}[\boldsymbol{x}_1,\boldsymbol{x}_{p-1}]\\
\mathrm{corr}[\boldsymbol{x}_2,\boldsymbol{x}_0] & \mathrm{corr}[\boldsymbol{x}_2,\boldsymbol{x}_1] & 1 & \dots & \dots & \mathrm{corr}[\boldsymbol{x}_2,\boldsymbol{x}_{p-1}]\\
\dots & \dots & \dots & \dots & \dots & \dots \\
\dots & \dots & \dots & \dots & \dots & \dots \\
\mathrm{corr}[\boldsymbol{x}_{p-1},\boldsymbol{x}_0] & \mathrm{corr}[\boldsymbol{x}_{p-1},\boldsymbol{x}_1] & \mathrm{corr}[\boldsymbol{x}_{p-1},\boldsymbol{x}_{2}] & \dots & \dots & 1\\
\end{bmatrix},
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="numpy-functionality">Numpy Functionality </h2>
<p>The Numpy function <b>np.cov</b> calculates the covariance elements using
the factor \( 1/(n-1) \) instead of \( 1/n \) since it assumes we do not have
the exact mean values. The following simple function uses the
<b>np.vstack</b> function which takes each vector of dimension \( 1\times n \)
and produces a \( 2\times n \) matrix \( \boldsymbol{W} \)
</p>
$$
\boldsymbol{W}^T = \begin{bmatrix} x_0 & y_0 \\
x_1 & y_1 \\
x_2 & y_2\\
\dots & \dots \\
x_{n-2} & y_{n-2}\\
x_{n-1} & y_{n-1} &
\end{bmatrix},
$$
<p>which in turn is converted into into the \( 2\times 2 \) covariance matrix
\( \boldsymbol{C} \) via the Numpy function <b>np.cov()</b>. We note that we can also calculate
the mean value of each set of samples \( \boldsymbol{x} \) etc using the Numpy
function <b>np.mean(x)</b>. We can also extract the eigenvalues of the
covariance matrix through the <b>np.linalg.eig()</b> function.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># Importing various packages</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
n <span style="color: #666666">=</span> <span style="color: #666666">100</span>
x <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>normal(size<span style="color: #666666">=</span>n)
<span style="color: #008000">print</span>(np<span style="color: #666666">.</span>mean(x))
y <span style="color: #666666">=</span> <span style="color: #666666">4+3*</span>x<span style="color: #666666">+</span>np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>normal(size<span style="color: #666666">=</span>n)
<span style="color: #008000">print</span>(np<span style="color: #666666">.</span>mean(y))
W <span style="color: #666666">=</span> np<span style="color: #666666">.</span>vstack((x, y))
C <span style="color: #666666">=</span> np<span style="color: #666666">.</span>cov(W)
<span style="color: #008000">print</span>(C)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="correlation-matrix-again">Correlation Matrix again </h2>
<p>The previous example can be converted into the correlation matrix by
simply scaling the matrix elements with the variances. We should also
subtract the mean values for each column. This leads to the following
code which sets up the correlations matrix for the previous example in
a more brute force way. Here we scale the mean values for each column of the design matrix, calculate the relevant mean values and variances and then finally set up the \( 2\times 2 \) correlation matrix (since we have only two vectors).
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
n <span style="color: #666666">=</span> <span style="color: #666666">100</span>
<span style="color: #408080; font-style: italic"># define two vectors </span>
x <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>random(size<span style="color: #666666">=</span>n)
y <span style="color: #666666">=</span> <span style="color: #666666">4+3*</span>x<span style="color: #666666">+</span>np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>normal(size<span style="color: #666666">=</span>n)
<span style="color: #408080; font-style: italic">#scaling the x and y vectors </span>
x <span style="color: #666666">=</span> x <span style="color: #666666">-</span> np<span style="color: #666666">.</span>mean(x)
y <span style="color: #666666">=</span> y <span style="color: #666666">-</span> np<span style="color: #666666">.</span>mean(y)
variance_x <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(x<span style="color: #AA22FF">@x</span>)<span style="color: #666666">/</span>n
variance_y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(y<span style="color: #AA22FF">@y</span>)<span style="color: #666666">/</span>n
<span style="color: #008000">print</span>(variance_x)
<span style="color: #008000">print</span>(variance_y)
cov_xy <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(x<span style="color: #AA22FF">@y</span>)<span style="color: #666666">/</span>n
cov_xx <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(x<span style="color: #AA22FF">@x</span>)<span style="color: #666666">/</span>n
cov_yy <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(y<span style="color: #AA22FF">@y</span>)<span style="color: #666666">/</span>n
C <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros((<span style="color: #666666">2</span>,<span style="color: #666666">2</span>))
C[<span style="color: #666666">0</span>,<span style="color: #666666">0</span>]<span style="color: #666666">=</span> cov_xx<span style="color: #666666">/</span>variance_x
C[<span style="color: #666666">1</span>,<span style="color: #666666">1</span>]<span style="color: #666666">=</span> cov_yy<span style="color: #666666">/</span>variance_y
C[<span style="color: #666666">0</span>,<span style="color: #666666">1</span>]<span style="color: #666666">=</span> cov_xy<span style="color: #666666">/</span>np<span style="color: #666666">.</span>sqrt(variance_y<span style="color: #666666">*</span>variance_x)
C[<span style="color: #666666">1</span>,<span style="color: #666666">0</span>]<span style="color: #666666">=</span> C[<span style="color: #666666">0</span>,<span style="color: #666666">1</span>]
<span style="color: #008000">print</span>(C)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>We see that the matrix elements along the diagonal are one as they
should be and that the matrix is symmetric. Furthermore, diagonalizing
this matrix we easily see that it is a positive definite matrix.
</p>
<p>The above procedure with <b>numpy</b> can be made more compact if we use <b>pandas</b>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="using-pandas">Using Pandas </h2>
<p>We whow here how we can set up the correlation matrix using <b>pandas</b>, as done in this simple code</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pandas</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">pd</span>
n <span style="color: #666666">=</span> <span style="color: #666666">10</span>
x <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>normal(size<span style="color: #666666">=</span>n)
x <span style="color: #666666">=</span> x <span style="color: #666666">-</span> np<span style="color: #666666">.</span>mean(x)
y <span style="color: #666666">=</span> <span style="color: #666666">4+3*</span>x<span style="color: #666666">+</span>np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>normal(size<span style="color: #666666">=</span>n)
y <span style="color: #666666">=</span> y <span style="color: #666666">-</span> np<span style="color: #666666">.</span>mean(y)
X <span style="color: #666666">=</span> (np<span style="color: #666666">.</span>vstack((x, y)))<span style="color: #666666">.</span>T
<span style="color: #008000">print</span>(X)
Xpd <span style="color: #666666">=</span> pd<span style="color: #666666">.</span>DataFrame(X)
<span style="color: #008000">print</span>(Xpd)
correlation_matrix <span style="color: #666666">=</span> Xpd<span style="color: #666666">.</span>corr()
<span style="color: #008000">print</span>(correlation_matrix)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="and-then-the-franke-function">And then the Franke Function </h2>
<p>We expand this model to the Franke function discussed above.</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># Common imports</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pandas</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">pd</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">FrankeFunction</span>(x,y):
term1 <span style="color: #666666">=</span> <span style="color: #666666">0.75*</span>np<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>(<span style="color: #666666">0.25*</span>(<span style="color: #666666">9*</span>x<span style="color: #666666">-2</span>)<span style="color: #666666">**2</span>) <span style="color: #666666">-</span> <span style="color: #666666">0.25*</span>((<span style="color: #666666">9*</span>y<span style="color: #666666">-2</span>)<span style="color: #666666">**2</span>))
term2 <span style="color: #666666">=</span> <span style="color: #666666">0.75*</span>np<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>((<span style="color: #666666">9*</span>x<span style="color: #666666">+1</span>)<span style="color: #666666">**2</span>)<span style="color: #666666">/49.0</span> <span style="color: #666666">-</span> <span style="color: #666666">0.1*</span>(<span style="color: #666666">9*</span>y<span style="color: #666666">+1</span>))
term3 <span style="color: #666666">=</span> <span style="color: #666666">0.5*</span>np<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>(<span style="color: #666666">9*</span>x<span style="color: #666666">-7</span>)<span style="color: #666666">**2/4.0</span> <span style="color: #666666">-</span> <span style="color: #666666">0.25*</span>((<span style="color: #666666">9*</span>y<span style="color: #666666">-3</span>)<span style="color: #666666">**2</span>))
term4 <span style="color: #666666">=</span> <span style="color: #666666">-0.2*</span>np<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>(<span style="color: #666666">9*</span>x<span style="color: #666666">-4</span>)<span style="color: #666666">**2</span> <span style="color: #666666">-</span> (<span style="color: #666666">9*</span>y<span style="color: #666666">-7</span>)<span style="color: #666666">**2</span>)
<span style="color: #008000; font-weight: bold">return</span> term1 <span style="color: #666666">+</span> term2 <span style="color: #666666">+</span> term3 <span style="color: #666666">+</span> term4
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">create_X</span>(x, y, n ):
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">len</span>(x<span style="color: #666666">.</span>shape) <span style="color: #666666">&gt;</span> <span style="color: #666666">1</span>:
x <span style="color: #666666">=</span> np<span style="color: #666666">.</span>ravel(x)
y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>ravel(y)
N <span style="color: #666666">=</span> <span style="color: #008000">len</span>(x)
l <span style="color: #666666">=</span> <span style="color: #008000">int</span>((n<span style="color: #666666">+1</span>)<span style="color: #666666">*</span>(n<span style="color: #666666">+2</span>)<span style="color: #666666">/2</span>) <span style="color: #408080; font-style: italic"># Number of elements in beta</span>
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>ones((N,l))
<span style="color: #008000; font-weight: bold">for</span> i <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(<span style="color: #666666">1</span>,n<span style="color: #666666">+1</span>):
q <span style="color: #666666">=</span> <span style="color: #008000">int</span>((i)<span style="color: #666666">*</span>(i<span style="color: #666666">+1</span>)<span style="color: #666666">/2</span>)
<span style="color: #008000; font-weight: bold">for</span> k <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(i<span style="color: #666666">+1</span>):
X[:,q<span style="color: #666666">+</span>k] <span style="color: #666666">=</span> (x<span style="color: #666666">**</span>(i<span style="color: #666666">-</span>k))<span style="color: #666666">*</span>(y<span style="color: #666666">**</span>k)
<span style="color: #008000; font-weight: bold">return</span> X
<span style="color: #408080; font-style: italic"># Making meshgrid of datapoints and compute Franke&#39;s function</span>
n <span style="color: #666666">=</span> <span style="color: #666666">4</span>
N <span style="color: #666666">=</span> <span style="color: #666666">100</span>
x <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sort(np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>uniform(<span style="color: #666666">0</span>, <span style="color: #666666">1</span>, N))
y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sort(np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>uniform(<span style="color: #666666">0</span>, <span style="color: #666666">1</span>, N))
z <span style="color: #666666">=</span> FrankeFunction(x, y)
X <span style="color: #666666">=</span> create_X(x, y, n<span style="color: #666666">=</span>n)
Xpd <span style="color: #666666">=</span> pd<span style="color: #666666">.</span>DataFrame(X)
<span style="color: #408080; font-style: italic"># subtract the mean values and set up the covariance matrix</span>
Xpd <span style="color: #666666">=</span> Xpd <span style="color: #666666">-</span> Xpd<span style="color: #666666">.</span>mean()
covariance_matrix <span style="color: #666666">=</span> Xpd<span style="color: #666666">.</span>cov()
<span style="color: #008000">print</span>(covariance_matrix)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>We note here that the covariance is zero for the first rows and
columns since all matrix elements in the design matrix were set to one
(we are fitting the function in terms of a polynomial of degree \( n \)). We would however not include the intercept
and wee can simply
drop these elements and construct a correlation
matrix without them by centering our matrix elements by subtracting the mean of each column.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="links-with-the-design-matrix">Links with the Design Matrix </h2>
<p>We can rewrite the covariance matrix in a more compact form in terms of the design/feature matrix \( \boldsymbol{X} \) as </p>
$$
\boldsymbol{C}[\boldsymbol{x}] = \frac{1}{n}\boldsymbol{X}^T\boldsymbol{X}= \mathbb{E}[\boldsymbol{X}^T\boldsymbol{X}].
$$
<p>To see this let us simply look at a design matrix \( \boldsymbol{X}\in {\mathbb{R}}^{2\times 2} \)</p>
$$
\boldsymbol{X}=\begin{bmatrix}
x_{00} & x_{01}\\
x_{10} & x_{11}\\
\end{bmatrix}=\begin{bmatrix}
\boldsymbol{x}_{0} & \boldsymbol{x}_{1}\\
\end{bmatrix}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="computing-the-expectation-values">Computing the Expectation Values </h2>
<p>If we then compute the expectation value</p>
$$
\mathbb{E}[\boldsymbol{X}^T\boldsymbol{X}] = \frac{1}{n}\boldsymbol{X}^T\boldsymbol{X}=\begin{bmatrix}
x_{00}^2+x_{01}^2 & x_{00}x_{10}+x_{01}x_{11}\\
x_{10}x_{00}+x_{11}x_{01} & x_{10}^2+x_{11}^2\\
\end{bmatrix},
$$
<p>which is just </p>
$$
\boldsymbol{C}[\boldsymbol{x}_0,\boldsymbol{x}_1] = \boldsymbol{C}[\boldsymbol{x}]=\begin{bmatrix} \mathrm{var}[\boldsymbol{x}_0] & \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_1] \\
\mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_0] & \mathrm{var}[\boldsymbol{x}_1] \\
\end{bmatrix},
$$
<p>where we wrote $$\boldsymbol{C}[\boldsymbol{x}_0,\boldsymbol{x}_1] = \boldsymbol{C}[\boldsymbol{x}]$$ to indicate that this the covariance of the vectors \( \boldsymbol{x} \) of the design/feature matrix \( \boldsymbol{X} \).</p>
<p>It is easy to generalize this to a matrix \( \boldsymbol{X}\in {\mathbb{R}}^{n\times p} \).</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="towards-the-pca-theorem">Towards the PCA theorem </h2>
<p>We have that the covariance matrix (the correlation matrix involves a simple rescaling) is given as</p>
$$
\boldsymbol{C}[\boldsymbol{x}] = \frac{1}{n}\boldsymbol{X}^T\boldsymbol{X}= \mathbb{E}[\boldsymbol{X}^T\boldsymbol{X}].
$$
<p>Let us now assume that we can perform a series of orthogonal transformations where we employ some orthogonal matrices \( \boldsymbol{S} \).
These matrices are defined as \( \boldsymbol{S}\in {\mathbb{R}}^{p\times p} \) and obey the orthogonality requirements \( \boldsymbol{S}\boldsymbol{S}^T=\boldsymbol{S}^T\boldsymbol{S}=\boldsymbol{I} \). The matrix can be written out in terms of the column vectors \( \boldsymbol{s}_i \) as \( \boldsymbol{S}=[\boldsymbol{s}_0,\boldsymbol{s}_1,\dots,\boldsymbol{s}_{p-1}] \) and \( \boldsymbol{s}_i \in {\mathbb{R}}^{p} \).
</p>
<p>Assume also that there is a transformation \( \boldsymbol{S}^T\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S}=\boldsymbol{C}[\boldsymbol{y}] \) such that the new matrix \( \boldsymbol{C}[\boldsymbol{y}] \) is diagonal with elements \( [\lambda_0,\lambda_1,\lambda_2,\dots,\lambda_{p-1}] \). </p>
<p>That is we have</p>
$$
\boldsymbol{C}[\boldsymbol{y}] = \mathbb{E}[\boldsymbol{S}^T\boldsymbol{X}^T\boldsymbol{X}T\boldsymbol{S}]=\boldsymbol{S}^T\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S},
$$
<p>since the matrix \( \boldsymbol{S} \) is not a data dependent matrix. Multiplying with \( \boldsymbol{S} \) from the left we have</p>
$$
\boldsymbol{S}\boldsymbol{C}[\boldsymbol{y}] = \boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S},
$$
<p>and since \( \boldsymbol{C}[\boldsymbol{y}] \) is diagonal we have for a given eigenvalue \( i \) of the covariance matrix that</p>
$$
\boldsymbol{S}_i\lambda_i = \boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S}_i.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-on-the-pca-theorem">More on the PCA Theorem </h2>
<p>In the derivation of the PCA theorem we will assume that the
eigenvalues are ordered in descending order, that is \( \lambda_0 > \lambda_1 > \dots > \lambda_{p-1} \).
</p>
<p>The eigenvalues tell us then how much we need to stretch the
corresponding eigenvectors. Dimensions with large eigenvalues have
thus large variations (large variance) and define therefore useful
dimensions. The data points are more spread out in the direction of
these eigenvectors. Smaller eigenvalues mean on the other hand that
the corresponding eigenvectors are shrunk accordingly and the data
points are tightly bunched together and there is not much variation in
these specific directions. Hopefully then we could leave it out
dimensions where the eigenvalues are very small. If \( p \) is very large,
we could then aim at reducing \( p \) to \( l < < p \) and handle only \( l \)
features/predictors.
</p>
<p>Here is how we would proceed in setting up the algorithm for the PCA, see also discussion below here. </p>
<ul>
<li> Set up the datapoints for the design/feature matrix with the predictors/features \( p \) referring to the column numbers and the entries \( n \) being the row elements.</li>
<li> Center the data by subtracting the mean value for each column.</li>
<li> Compute then the covariance/correlation matrix.</li>
<li> Find the eigenpairs of the covariance matrix with eigenvalues \( [\lambda_0,\lambda_1,\dots,\lambda_{p-1}] \) and eigenvectors \( [\boldsymbol{s}_0,\boldsymbol{s}_1,\dots,\boldsymbol{s}_{p-1}] \).</li>
<li> Order the eigenvalue (and the eigenvectors accordingly) in order of decreasing eigenvalues.</li>
<li> Keep only those \( l \) eigenvalues larger than a selected threshold value, discarding thus \( p-l \) features since we expect small variations in the data here.</li>
</ul>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="writing-our-own-pca-code">Writing our own PCA code </h2>
<p>We will use a simple example first with two-dimensional data
drawn from a multivariate normal distribution with the following mean and covariance matrix (we have fixed these quantities but will play around with them below):
</p>
$$
\mu = (-1,2) \qquad \Sigma = \begin{bmatrix} 4 & 2 \\
2 & 2
\end{bmatrix}
$$
<p>Note that the mean refers to each column of data.
We will generate \( n = 10000 \) points \( X = \{ x_1, \ldots, x_N \} \) from
this distribution, and store them in the \( 1000 \times 2 \) matrix \( \boldsymbol{X} \). This is our design matrix where we have forced the covariance and mean values to take specific values.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="implementing-it">Implementing it </h2>
<p>The following Python code aids in setting up the data and writing out the design matrix.
Note that the function <b>multivariate</b> returns also the covariance discussed above and that it is defined by dividing by \( n-1 \) instead of \( n \).
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pandas</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">pd</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">IPython.display</span> <span style="color: #008000; font-weight: bold">import</span> display
n <span style="color: #666666">=</span> <span style="color: #666666">10000</span>
mean <span style="color: #666666">=</span> (<span style="color: #666666">-1</span>, <span style="color: #666666">2</span>)
cov <span style="color: #666666">=</span> [[<span style="color: #666666">4</span>, <span style="color: #666666">2</span>], [<span style="color: #666666">2</span>, <span style="color: #666666">2</span>]]
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>multivariate_normal(mean, cov, n)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>Now we are going to implement the PCA algorithm. We will break it down into various substeps.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="first-step">First Step </h2>
<p>The first step of PCA is to compute the sample mean of the data and use it to center the data. Recall that the sample mean is</p>
$$
\mu_n = \frac{1}{n} \sum_{i=1}^n x_i
$$
<p>and the mean-centered data \( \bar{X} = \{ \bar{x}_1, \ldots, \bar{x}_n \} \) takes the form</p>
$$
\bar{x}_i = x_i - \mu_n.
$$
<p>When you are done with these steps, print out \( \mu_n \) to verify it is
close to \( \mu \) and plot your mean centered data to verify it is
centered at the origin!
The following code elements perform these operations using <b>pandas</b> or using our own functionality for doing so. The latter, using <b>numpy</b> is rather simple through the <b>mean()</b> function.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">df <span style="color: #666666">=</span> pd<span style="color: #666666">.</span>DataFrame(X)
<span style="color: #408080; font-style: italic"># Pandas does the centering for us</span>
df <span style="color: #666666">=</span> df <span style="color: #666666">-</span>df<span style="color: #666666">.</span>mean()
<span style="color: #408080; font-style: italic"># we center it ourselves</span>
X_centered <span style="color: #666666">=</span> X <span style="color: #666666">-</span> X<span style="color: #666666">.</span>mean(axis<span style="color: #666666">=0</span>)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="scaling">Scaling </h2>
<p>Alternatively, we could use the functions we discussed
earlier for scaling the data set. That is, we could have used the
<b>StandardScaler</b> function in <b>Scikit-Learn</b>, a function which ensures
that for each feature/predictor we study the mean value is zero and
the variance is one (every column in the design/feature matrix). You
would then not get the same results, since we divide by the
variance. The diagonal covariance matrix elements will then be one,
while the non-diagonal ones need to be divided by \( 2\sqrt{2} \) for our
specific case.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="centered-data">Centered Data </h2>
<p>Now we are going to use the mean centered data to compute the sample covariance of the data by using the following equation</p>
$$
\begin{equation*}
\Sigma_n = \frac{1}{n-1} \sum_{i=1}^n \bar{x}_i^T \bar{x}_i = \frac{1}{n-1} \sum_{i=1}^n (x_i - \mu_n)^T (x_i - \mu_n)
\end{equation*}
$$
<p>where the data points \( x_i \in \mathbb{R}^p \) (here in this example \( p = 2 \)) are column vectors and \( x^T \) is the transpose of \( x \).
We can write our own code or simply use either the functionaly of <b>numpy</b> or that of <b>pandas</b>, as follows
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000">print</span>(df<span style="color: #666666">.</span>cov())
<span style="color: #008000">print</span>(np<span style="color: #666666">.</span>cov(X_centered<span style="color: #666666">.</span>T))
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>Note that the way we define the covariance matrix here has a factor \( n-1 \) instead of \( n \). This is included in the <b>cov()</b> function by <b>numpy</b> and <b>pandas</b>.
Our own code here is not very elegant and asks for obvious improvements. It is tailored to this specific \( 2\times 2 \) covariance matrix.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># extract the relevant columns from the centered design matrix of dim n x 2</span>
x <span style="color: #666666">=</span> X_centered[:,<span style="color: #666666">0</span>]
y <span style="color: #666666">=</span> X_centered[:,<span style="color: #666666">1</span>]
Cov <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros((<span style="color: #666666">2</span>,<span style="color: #666666">2</span>))
Cov[<span style="color: #666666">0</span>,<span style="color: #666666">1</span>] <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(x<span style="color: #666666">.</span>T<span style="color: #AA22FF">@y</span>)<span style="color: #666666">/</span>(n<span style="color: #666666">-1.0</span>)
Cov[<span style="color: #666666">0</span>,<span style="color: #666666">0</span>] <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(x<span style="color: #666666">.</span>T<span style="color: #AA22FF">@x</span>)<span style="color: #666666">/</span>(n<span style="color: #666666">-1.0</span>)
Cov[<span style="color: #666666">1</span>,<span style="color: #666666">1</span>] <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(y<span style="color: #666666">.</span>T<span style="color: #AA22FF">@y</span>)<span style="color: #666666">/</span>(n<span style="color: #666666">-1.0</span>)
Cov[<span style="color: #666666">1</span>,<span style="color: #666666">0</span>]<span style="color: #666666">=</span> Cov[<span style="color: #666666">0</span>,<span style="color: #666666">1</span>]
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Centered covariance using own code&quot;</span>)
<span style="color: #008000">print</span>(Cov)
plt<span style="color: #666666">.</span>plot(x, y, <span style="color: #BA2121">&#39;x&#39;</span>)
plt<span style="color: #666666">.</span>axis(<span style="color: #BA2121">&#39;equal&#39;</span>)
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="exploring">Exploring </h2>
<p>Depending on the number of points \( n \), we will get results that are close to the covariance values defined above.
The plot shows how the data are clustered around a line with slope close to one. Is this expected? Try to change the covariance and the mean values. For example, try to make the variance of the first element much larger than that of the second diagonal element. Try also to shrink the covariance (the non-diagonal elements) and see how the data points are distributed.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="diagonalize-the-sample-covariance-matrix-to-obtain-the-principal-components">Diagonalize the sample covariance matrix to obtain the principal components </h2>
<p>Now we are ready to solve for the principal components! To do so we
diagonalize the sample covariance matrix \( \Sigma \). We can use the
function <b>np.linalg.eig</b> to do so. It will return the eigenvalues and
eigenvectors of \( \Sigma \). Once we have these we can perform the
following tasks:
</p>
<ul>
<li> We compute the percentage of the total variance captured by the first principal component</li>
<li> We plot the mean centered data and lines along the first and second principal components</li>
<li> Then we project the mean centered data onto the first and second principal components, and plot the projected data.</li>
<li> Finally, we approximate the data as</li>
</ul>
$$
\begin{equation*}
x_i \approx \tilde{x}_i = \mu_n + \langle x_i, v_0 \rangle v_0
\end{equation*}
$$
<p>where \( v_0 \) is the first principal component. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="collecting-all-steps">Collecting all Steps </h2>
<p>Collecting all these steps we can write our own PCA function and
compare this with the functionality included in <b>Scikit-Learn</b>.
</p>
<p>The code here outlines some of the elements we could include in the
analysis. Feel free to extend upon this in order to address the above
questions.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># diagonalize and obtain eigenvalues, not necessarily sorted</span>
EigValues, EigVectors <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linalg<span style="color: #666666">.</span>eig(Cov)
<span style="color: #408080; font-style: italic"># sort eigenvectors and eigenvalues</span>
<span style="color: #408080; font-style: italic">#permute = EigValues.argsort()</span>
<span style="color: #408080; font-style: italic">#EigValues = EigValues[permute]</span>
<span style="color: #408080; font-style: italic">#EigVectors = EigVectors[:,permute]</span>
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Eigenvalues of Covariance matrix&quot;</span>)
<span style="color: #008000; font-weight: bold">for</span> i <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(<span style="color: #666666">2</span>):
<span style="color: #008000">print</span>(EigValues[i])
FirstEigvector <span style="color: #666666">=</span> EigVectors[:,<span style="color: #666666">0</span>]
SecondEigvector <span style="color: #666666">=</span> EigVectors[:,<span style="color: #666666">1</span>]
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;First eigenvector&quot;</span>)
<span style="color: #008000">print</span>(FirstEigvector)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Second eigenvector&quot;</span>)
<span style="color: #008000">print</span>(SecondEigvector)
<span style="color: #408080; font-style: italic">#thereafter we do a PCA with Scikit-learn</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.decomposition</span> <span style="color: #008000; font-weight: bold">import</span> PCA
pca <span style="color: #666666">=</span> PCA(n_components <span style="color: #666666">=</span> <span style="color: #666666">2</span>)
X2Dsl <span style="color: #666666">=</span> pca<span style="color: #666666">.</span>fit_transform(X)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Eigenvector of largest eigenvalue&quot;</span>)
<span style="color: #008000">print</span>(pca<span style="color: #666666">.</span>components_<span style="color: #666666">.</span>T[:, <span style="color: #666666">0</span>])
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>This code does not contain all the above elements, but it shows how we can use <b>Scikit-Learn</b> to extract the eigenvector which corresponds to the largest eigenvalue. Try to address the questions we pose before the above code. Try also to change the values of the covariance matrix by making one of the diagonal elements much larger than the other. What do you observe then? </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="classical-pca-theorem">Classical PCA Theorem </h2>
<p>We assume now that we have a design matrix \( \boldsymbol{X} \) which has been
centered as discussed above. For the sake of simplicity we skip the
overline symbol. The matrix is defined in terms of the various column
vectors \( [\boldsymbol{x}_0,\boldsymbol{x}_1,\dots, \boldsymbol{x}_{p-1}] \) each with dimension
\( \boldsymbol{x}\in {\mathbb{R}}^{n} \).
</p>
<p>The PCA theorem states that minimizing the above reconstruction error
corresponds to setting \( \boldsymbol{W}=\boldsymbol{S} \), the orthogonal matrix which
diagonalizes the empirical covariance(correlation) matrix. The optimal
low-dimensional encoding of the data is then given by a set of vectors
\( \boldsymbol{z}_i \) with at most \( l \) vectors, with \( l < < p \), defined by the
orthogonal projection of the data onto the columns spanned by the
eigenvectors of the covariance(correlations matrix).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-pca-theorem">The PCA Theorem </h2>
<p>To show the PCA theorem let us start with the assumption that there is one vector \( \boldsymbol{s}_0 \) which corresponds to a solution which minimized the reconstruction error \( J \). This is an orthogonal vector. It means that we now approximate the reconstruction error in terms of \( \boldsymbol{w}_0 \) and \( \boldsymbol{z}_0 \) as</p>
<p>We are almost there, we have obtained a relation between minimizing
the reconstruction error and the variance and the covariance
matrix. Minimizing the error is equivalent to maximizing the variance
of the projected data.
</p>
<p>We could trivially maximize the variance of the projection (and
thereby minimize the error in the reconstruction function) by letting
the norm-2 of \( \boldsymbol{w}_0 \) go to infinity. However, this norm since we
want the matrix \( \boldsymbol{W} \) to be an orthogonal matrix, is constrained by
\( \vert\vert \boldsymbol{w}_0 \vert\vert_2^2=1 \). Imposing this condition via a
Lagrange multiplier we can then in turn maximize
</p>
$$
J(\boldsymbol{w}_0)= \boldsymbol{w}_0^T\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{w}_0+\lambda_0(1-\boldsymbol{w}_0^T\boldsymbol{w}_0).
$$
<p>Taking the derivative with respect to \( \boldsymbol{w}_0 \) we obtain</p>
$$
\frac{\partial J(\boldsymbol{w}_0)}{\partial \boldsymbol{w}_0}= 2\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{w}_0-2\lambda_0\boldsymbol{w}_0=0,
$$
<p>meaning that</p>
$$
\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{w}_0=\lambda_0\boldsymbol{w}_0.
$$
<p><b>The direction that maximizes the variance (or minimizes the construction error) is an eigenvector of the covariance matrix</b>! If we left multiply with \( \boldsymbol{w}_0^T \) we have the variance of the projected data is</p>
$$
\boldsymbol{w}_0^T\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{w}_0=\lambda_0.
$$
<p>If we want to maximize the variance (minimize the construction error)
we simply pick the eigenvector of the covariance matrix with the
largest eigenvalue. This establishes the link between the minimization
of the reconstruction function \( J \) in terms of an orthogonal matrix
and the maximization of the variance and thereby the covariance of our
observations encoded in the design/feature matrix \( \boldsymbol{X} \).
</p>
<p>The proof
for the other eigenvectors \( \boldsymbol{w}_1,\boldsymbol{w}_2,\dots \) can be
established by applying the above arguments and using the fact that
our basis of eigenvectors is orthogonal, see <a href="https://mitpress.mit.edu/books/machine-learning-1" target="_blank">Murphy chapter
12.2</a>. The
discussion in chapter 12.2 of Murphy's text has also a nice link with
the Singular Value Decomposition theorem. For categorical data, see
chapter 12.4 and discussion therein.
</p>
<p>For more details, see for example <a href="https://www.springer.com/gp/book/9780387878102" target="_blank">Vidal, Ma and Sastry, chapter 2</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="geometric-interpretation-and-link-with-singular-value-decomposition">Geometric Interpretation and link with Singular Value Decomposition </h2>
<p>For a detailed demonstration of the geometric interpretation, see <a href="https://www.springer.com/gp/book/9780387878102" target="_blank">Vidal, Ma and Sastry, section 2.1.2</a>.</p>
<p>Principal Component Analysis (PCA) is by far the most popular dimensionality reduction algorithm.
First it identifies the hyperplane that lies closest to the data, and then it projects the data onto it.
</p>
<p>The following Python code uses NumPy&#8217;s <b>svd()</b> function to obtain all the principal components of the
training set, then extracts the first two principal components. First we center the data using either <b>pandas</b> or our own code
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pandas</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">pd</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">IPython.display</span> <span style="color: #008000; font-weight: bold">import</span> display
np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>seed(<span style="color: #666666">100</span>)
<span style="color: #408080; font-style: italic"># setting up a 10 x 5 vanilla matrix </span>
rows <span style="color: #666666">=</span> <span style="color: #666666">10</span>
cols <span style="color: #666666">=</span> <span style="color: #666666">5</span>
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>randn(rows,cols)
df <span style="color: #666666">=</span> pd<span style="color: #666666">.</span>DataFrame(X)
<span style="color: #408080; font-style: italic"># Pandas does the centering for us</span>
df <span style="color: #666666">=</span> df <span style="color: #666666">-</span>df<span style="color: #666666">.</span>mean()
display(df)
<span style="color: #408080; font-style: italic"># we center it ourselves</span>
X_centered <span style="color: #666666">=</span> X <span style="color: #666666">-</span> X<span style="color: #666666">.</span>mean(axis<span style="color: #666666">=0</span>)
<span style="color: #408080; font-style: italic"># Then check the difference between pandas and our own set up</span>
<span style="color: #008000">print</span>(X_centered<span style="color: #666666">-</span>df)
<span style="color: #408080; font-style: italic">#Now we do an SVD</span>
U, s, V <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linalg<span style="color: #666666">.</span>svd(X_centered)
c1 <span style="color: #666666">=</span> V<span style="color: #666666">.</span>T[:, <span style="color: #666666">0</span>]
c2 <span style="color: #666666">=</span> V<span style="color: #666666">.</span>T[:, <span style="color: #666666">1</span>]
W2 <span style="color: #666666">=</span> V<span style="color: #666666">.</span>T[:, :<span style="color: #666666">2</span>]
X2D <span style="color: #666666">=</span> X_centered<span style="color: #666666">.</span>dot(W2)
<span style="color: #008000">print</span>(X2D)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>PCA assumes that the dataset is centered around the origin. Scikit-Learn&#8217;s PCA classes take care of centering
the data for you. However, if you implement PCA yourself (as in the preceding example), or if you use other libraries, don&#8217;t
forget to center the data first.
</p>
<p>Once you have identified all the principal components, you can reduce the dimensionality of the dataset
down to \( d \) dimensions by projecting it onto the hyperplane defined by the first \( d \) principal components.
Selecting this hyperplane ensures that the projection will preserve as much variance as possible.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">W2 <span style="color: #666666">=</span> V<span style="color: #666666">.</span>T[:, :<span style="color: #666666">2</span>]
X2D <span style="color: #666666">=</span> X_centered<span style="color: #666666">.</span>dot(W2)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="pca-and-scikit-learn">PCA and scikit-learn </h2>
<p>Scikit-Learn&#8217;s PCA class implements PCA using SVD decomposition just like we did before. The
following code applies PCA to reduce the dimensionality of the dataset down to two dimensions (note
that it automatically takes care of centering the data):
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic">#thereafter we do a PCA with Scikit-learn</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.decomposition</span> <span style="color: #008000; font-weight: bold">import</span> PCA
pca <span style="color: #666666">=</span> PCA(n_components <span style="color: #666666">=</span> <span style="color: #666666">2</span>)
X2D <span style="color: #666666">=</span> pca<span style="color: #666666">.</span>fit_transform(X)
<span style="color: #008000">print</span>(X2D)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>After fitting the PCA transformer to the dataset, you can access the principal components using the
components variable (note that it contains the PCs as horizontal vectors, so, for example, the first
principal component is equal to
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">pca<span style="color: #666666">.</span>components_<span style="color: #666666">.</span>T[:, <span style="color: #666666">0</span>]
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>Another very useful piece of information is the explained variance ratio of each principal component,
available via the \( explained\_variance\_ratio \) variable. It indicates the proportion of the dataset&#8217;s
variance that lies along the axis of each principal component.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="back-to-the-cancer-data">Back to the Cancer Data </h2>
<p>We can now repeat the above but applied to real data, in this case our breast cancer data.
Here we compute performance scores on the training data using logistic regression.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.model_selection</span> <span style="color: #008000; font-weight: bold">import</span> train_test_split
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> load_breast_cancer
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.linear_model</span> <span style="color: #008000; font-weight: bold">import</span> LogisticRegression
cancer <span style="color: #666666">=</span> load_breast_cancer()
X_train, X_test, y_train, y_test <span style="color: #666666">=</span> train_test_split(cancer<span style="color: #666666">.</span>data,cancer<span style="color: #666666">.</span>target,random_state<span style="color: #666666">=0</span>)
logreg <span style="color: #666666">=</span> LogisticRegression()
logreg<span style="color: #666666">.</span>fit(X_train, y_train)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Train set accuracy from Logistic Regression: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X_train,y_train)))
<span style="color: #408080; font-style: italic"># We scale the data</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.preprocessing</span> <span style="color: #008000; font-weight: bold">import</span> StandardScaler
scaler <span style="color: #666666">=</span> StandardScaler()
scaler<span style="color: #666666">.</span>fit(X_train)
X_train_scaled <span style="color: #666666">=</span> scaler<span style="color: #666666">.</span>transform(X_train)
X_test_scaled <span style="color: #666666">=</span> scaler<span style="color: #666666">.</span>transform(X_test)
<span style="color: #408080; font-style: italic"># Then perform again a log reg fit</span>
logreg<span style="color: #666666">.</span>fit(X_train_scaled, y_train)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Train set accuracy scaled data: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X_train_scaled,y_train)))
<span style="color: #408080; font-style: italic">#thereafter we do a PCA with Scikit-learn</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.decomposition</span> <span style="color: #008000; font-weight: bold">import</span> PCA
pca <span style="color: #666666">=</span> PCA(n_components <span style="color: #666666">=</span> <span style="color: #666666">2</span>)
X2D_train <span style="color: #666666">=</span> pca<span style="color: #666666">.</span>fit_transform(X_train_scaled)
<span style="color: #408080; font-style: italic"># and finally compute the log reg fit and the score on the training data </span>
logreg<span style="color: #666666">.</span>fit(X2D_train,y_train)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Train set accuracy scaled and PCA data: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X2D_train,y_train)))
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>We see that our training data after the PCA decomposition has a performance similar to the non-scaled data. </p>
<p>Instead of arbitrarily choosing the number of dimensions to reduce down to, it is generally preferable to
choose the number of dimensions that add up to a sufficiently large portion of the variance (e.g., 95%).
Unless, of course, you are reducing dimensionality for data visualization &#8212; in that case you will
generally want to reduce the dimensionality down to 2 or 3.
The following code computes PCA without reducing dimensionality, then computes the minimum number
of dimensions required to preserve 95% of the training set&#8217;s variance:
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">pca <span style="color: #666666">=</span> PCA()
pca<span style="color: #666666">.</span>fit(X)
cumsum <span style="color: #666666">=</span> np<span style="color: #666666">.</span>cumsum(pca<span style="color: #666666">.</span>explained_variance_ratio_)
d <span style="color: #666666">=</span> np<span style="color: #666666">.</span>argmax(cumsum <span style="color: #666666">&gt;=</span> <span style="color: #666666">0.95</span>) <span style="color: #666666">+</span> <span style="color: #666666">1</span>
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>You could then set \( n\_components=d \) and run PCA again. However, there is a much better option: instead
of specifying the number of principal components you want to preserve, you can set \( n\_components \) to be
a float between 0.0 and 1.0, indicating the ratio of variance you wish to preserve:
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">pca <span style="color: #666666">=</span> PCA(n_components<span style="color: #666666">=0.95</span>)
X_reduced <span style="color: #666666">=</span> pca<span style="color: #666666">.</span>fit_transform(X)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="incremental-pca">Incremental PCA </h2>
<p>One problem with the preceding implementation of PCA is that it requires the whole training set to fit in
memory in order for the SVD algorithm to run. Fortunately, Incremental PCA (IPCA) algorithms have
been developed: you can split the training set into mini-batches and feed an IPCA algorithm one minibatch
at a time. This is useful for large training sets, and also to apply PCA online (i.e., on the fly, as new
instances arrive).
</p>
<h3 id="randomized-pca">Randomized PCA </h3>
<p>Scikit-Learn offers yet another option to perform PCA, called Randomized PCA. This is a stochastic
algorithm that quickly finds an approximation of the first d principal components. Its computational
complexity is \( O(m \times d^2)+O(d^3) \), instead of \( O(m \times n^2) + O(n^3) \), so it is dramatically faster than the
previous algorithms when \( d \) is much smaller than \( n \).
</p>
<h3 id="kernel-pca">Kernel PCA </h3>
<p>The kernel trick is a mathematical technique that implicitly maps instances into a
very high-dimensional space (called the feature space), enabling nonlinear classification and regression
with Support Vector Machines. Recall that a linear decision boundary in the high-dimensional feature
space corresponds to a complex nonlinear decision boundary in the original space.
It turns out that the same trick can be applied to PCA, making it possible to perform complex nonlinear
projections for dimensionality reduction. This is called Kernel PCA (kPCA). It is often good at
preserving clusters of instances after projection, or sometimes even unrolling datasets that lie close to a
twisted manifold.
For example, the following code uses Scikit-Learn&#8217;s KernelPCA class to perform kPCA with an
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.decomposition</span> <span style="color: #008000; font-weight: bold">import</span> KernelPCA
rbf_pca <span style="color: #666666">=</span> KernelPCA(n_components <span style="color: #666666">=</span> <span style="color: #666666">2</span>, kernel<span style="color: #666666">=</span><span style="color: #BA2121">&quot;rbf&quot;</span>, gamma<span style="color: #666666">=0.04</span>)
X_reduced <span style="color: #666666">=</span> rbf_pca<span style="color: #666666">.</span>fit_transform(X)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="other-techniques">Other techniques </h2>
<p>There are many other dimensionality reduction techniques, several of which are available in Scikit-Learn.</p>
<p>Here are some of the most popular:</p>
<ul>
<li> <b>Multidimensional Scaling (MDS)</b> reduces dimensionality while trying to preserve the distances between the instances.</li>
<li> <b>Isomap</b> creates a graph by connecting each instance to its nearest neighbors, then reduces dimensionality while trying to preserve the geodesic distances between the instances.</li>
<li> <b>t-Distributed Stochastic Neighbor Embedding</b> (t-SNE) reduces dimensionality while trying to keep similar instances close and dissimilar instances apart. It is mostly used for visualization, in particular to visualize clusters of instances in high-dimensional space (e.g., to visualize the MNIST images in 2D).</li>
<li> Linear Discriminant Analysis (LDA) is actually a classification algorithm, but during training it learns the most discriminative axes between the classes, and these axes can then be used to define a hyperplane onto which to project the data. The benefit is that the projection will keep classes as far apart as possible, so LDA is a good technique to reduce dimensionality before running another classification algorithm such as a Support Vector Machine (SVM) classifier discussed in the SVM lectures.</li>
</ul>
<!-- ------------------- end of main content --------------- -->
<center style="font-size:80%">
<!-- copyright --> &copy; 1999-2022, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
</center>
</body>
</html>