Files
FYS-STK4155/doc/pub/week47/html/week47.html
T
Morten Hjorth-Jensen 50a5b1eeae update
2022-11-25 23:26:26 +01:00

3146 lines
172 KiB
HTML

<!--
HTML file automatically generated from DocOnce source
(https://github.com/doconce/doconce/)
doconce format html week47.do.txt --pygments_html_style=default --html_style=bloodish --html_links_in_new_window --html_output=week47 --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 47: Unsupervised learning (PCA and Clustering) and Summary of Course">
<title>Week 47: Unsupervised learning (PCA and Clustering) and Summary of Course</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 47', 2, None, 'overview-of-week-47'),
('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'),
("A kind of Bird's view on PCA",
2,
None,
'a-kind-of-bird-s-view-on-pca'),
('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'),
('Clustering and Unsupervised Learning',
2,
None,
'clustering-and-unsupervised-learning'),
('Basic Idea of the $k$-means Clustering Algorithm',
2,
None,
'basic-idea-of-the-k-means-clustering-algorithm'),
('The $k$-means Algorithm', 2, None, 'the-k-means-algorithm'),
('Basic Math of the $k$-means Algorithm',
2,
None,
'basic-math-of-the-k-means-algorithm'),
('Within Cluster Point Scatter',
2,
None,
'within-cluster-point-scatter'),
('More Details', 2, None, 'more-details'),
('Total Cluster Variance', 2, None, 'total-cluster-variance'),
('The $k$-means Clustering Algorithm',
2,
None,
'the-k-means-clustering-algorithm'),
('Summarizing', 2, None, 'summarizing'),
('Writing our own Code, the Data Set',
2,
None,
'writing-our-own-code-the-data-set'),
('Implementing the $k$-means Algorithm',
2,
None,
'implementing-the-k-means-algorithm'),
('Plotting', 2, None, 'plotting'),
('Continuing', 2, None, 'continuing'),
('Wrapping it up', 2, None, 'wrapping-it-up'),
('Summary of course', 2, None, 'summary-of-course'),
('What? Me worry? No final exam in this course!',
2,
None,
'what-me-worry-no-final-exam-in-this-course'),
('What is the link between Artificial Intelligence and Machine '
'Learning and some general Remarks',
2,
None,
'what-is-the-link-between-artificial-intelligence-and-machine-learning-and-some-general-remarks'),
('Going back to the beginning of the semester',
2,
None,
'going-back-to-the-beginning-of-the-semester'),
('Not so sharp distinctions',
2,
None,
'not-so-sharp-distinctions'),
('Topics we have covered this year',
2,
None,
'topics-we-have-covered-this-year'),
('Statistical analysis and optimization of data',
2,
None,
'statistical-analysis-and-optimization-of-data'),
('Machine learning', 2, None, 'machine-learning'),
('Learning outcomes and overarching aims of this course',
2,
None,
'learning-outcomes-and-overarching-aims-of-this-course'),
('Perspective on Machine Learning',
2,
None,
'perspective-on-machine-learning'),
('Machine Learning Research',
2,
None,
'machine-learning-research'),
('Starting your Machine Learning Project',
2,
None,
'starting-your-machine-learning-project'),
('Choose a Model and Algorithm',
2,
None,
'choose-a-model-and-algorithm'),
('Preparing Your Data', 2, None, 'preparing-your-data'),
('Which Activation and Weights to Choose in Neural Networks',
2,
None,
'which-activation-and-weights-to-choose-in-neural-networks'),
('Optimization Methods and Hyperparameters',
2,
None,
'optimization-methods-and-hyperparameters'),
('Resampling', 2, None, 'resampling'),
('Other courses on Data science and Machine Learning at UiO',
2,
None,
'other-courses-on-data-science-and-machine-learning-at-uio'),
('Additional courses of interest',
2,
None,
'additional-courses-of-interest'),
("What's the future like?", 2, None, 'what-s-the-future-like'),
('Types of Machine Learning, a repetition',
2,
None,
'types-of-machine-learning-a-repetition'),
('Why Boltzmann machines?', 2, None, 'why-boltzmann-machines'),
('Boltzmann Machines', 2, None, 'boltzmann-machines'),
('Some similarities and differences from DNNs',
2,
None,
'some-similarities-and-differences-from-dnns'),
('Boltzmann machines (BM)', 2, None, 'boltzmann-machines-bm'),
('A standard BM setup', 2, None, 'a-standard-bm-setup'),
('The structure of the RBM network',
2,
None,
'the-structure-of-the-rbm-network'),
('The network', 2, None, 'the-network'),
('Goals', 2, None, 'goals'),
('Joint distribution', 2, None, 'joint-distribution'),
('Network Elements, the energy function',
2,
None,
'network-elements-the-energy-function'),
('Defining different types of RBMs',
2,
None,
'defining-different-types-of-rbms'),
('More about RBMs', 2, None, 'more-about-rbms'),
('Autoencoders: Overarching view',
2,
None,
'autoencoders-overarching-view'),
('Bayesian Machine Learning',
2,
None,
'bayesian-machine-learning'),
('Reinforcement Learning', 2, None, 'reinforcement-learning'),
('Transfer learning', 2, None, 'transfer-learning'),
('Adversarial learning', 2, None, 'adversarial-learning'),
('Dual learning', 2, None, 'dual-learning'),
('Distributed machine learning',
2,
None,
'distributed-machine-learning'),
('Meta learning', 2, None, 'meta-learning'),
('The Challenges Facing Machine Learning',
2,
None,
'the-challenges-facing-machine-learning'),
('Explainable machine learning',
2,
None,
'explainable-machine-learning'),
('Scientific Machine Learning',
2,
None,
'scientific-machine-learning'),
('Quantum machine learning', 2, None, 'quantum-machine-learning'),
('Quantum machine learning algorithms based on linear algebra',
2,
None,
'quantum-machine-learning-algorithms-based-on-linear-algebra'),
('Quantum reinforcement learning',
2,
None,
'quantum-reinforcement-learning'),
('Quantum deep learning', 2, None, 'quantum-deep-learning'),
('Social machine learning', 2, None, 'social-machine-learning'),
('The last words?', 2, None, 'the-last-words'),
('AI/ML and some statements you may have heard (and what do they '
'mean?)',
2,
None,
'ai-ml-and-some-statements-you-may-have-heard-and-what-do-they-mean'),
('Best wishes to you all and thanks so much for your heroic '
'efforts this semester',
2,
None,
'best-wishes-to-you-all-and-thanks-so-much-for-your-heroic-efforts-this-semester')]}
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 47: Unsupervised learning (PCA and Clustering) and Summary of Course</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 25, 2022</h4>
</center> <!-- date -->
<br>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="overview-of-week-47">Overview of week 47 </h2>
<ul>
<li> <b>Thursday</b>: Dimensionality reduction and unsupervised learning: Principal Component analysis (PCA) and clustering</li>
<ul>
<li> <a href="https://youtu.be/VJIsEQM2lCI" target="_blank">Video of lecture</a></li>
</ul>
<li> <b>Friday</b>: PCA and clustering and Summary of Course</li>
<ul>
<li> <a href="https://youtu.be/olXksEL3P4A" target="_blank">Video of lecture</a></li>
</ul>
</ul>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<ol>
<li> We recommend highly the video on PCA by <a href="http://www.databookuw.com/page-2/page-4/" target="_blank">Brunton and Kutz</a>, see in particular the video of section 1.5. Repeating about the singular value discussion is also very useful as we will use this material as background.</li>
<li> <a href="https://www.youtube.com/watch?v=FgakZw6K1QQ" target="_blank">And another good video on PCA</a></li>
<li> <a href="https://www.youtube.com/watch?v=4b5d3muPQmA" target="_blank">k-means clustering video</a></li>
</ol>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b>Reading recommendations:</b>
<p>
<ol>
<li> Geron's chapter 9 on PCA</li>
<li> Hastie et al Chapter 13 (sections 13.1-13.2 are the most relevant ones)</li>
</ol>
</div>
<!-- !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="a-kind-of-bird-s-view-on-pca">A kind of Bird's view on PCA </h2>
<b>Why do we maximize variance during Principal Component Analysis?</b>
<p>Variance is a measure of the <em>variability</em> of the data you
have. Potentially the number of components is infinite, so you want to "squeeze" the most
information in each component of the finite set you build.
</p>
<p>If, to exaggerate, you were to select a single principal component,
you would want it to account for the most variability possible: hence
the search for maximum variance, so that the one component collects
the most "uniqueness" from the data set.
</p>
<p>Maximizing the component vector variances is the same as maximizing
the 'uniqueness' of those vectors. The vectors are as distant
from each other as possible (orthogonal to each other).
</p>
<p>Take for example a situation where you have 2 lines that are
orthogonal in a 3D space. You can capture the environment much more
completely with those orthogonal lines than 2 lines that are parallel
(or nearly parallel). When applied to very high dimensional states
using very few vectors, this becomes a much more important
relationship among the vectors to maintain. In a linear algebra sense
you want independent rows to be produced by PCA, otherwise some of
those rows will be redundant.
</p>
<!-- !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>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="clustering-and-unsupervised-learning">Clustering and Unsupervised Learning </h2>
<p>In general terms cluster analysis, or clustering, is the task of grouping a
data-set into different distinct categories based on some measure of equality of
the data. This measure is often referred to as a <b>metric</b> or <b>similarity
measure</b> in the literature (note: sometimes we deal with a <b>dissimilarity
measure</b> instead). Usually, these metrics are formulated as some kind of
distance function between points in a high-dimensional space.
</p>
<p>The simplest, and also the most
common is the <b>Euclidean distance</b>.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="basic-idea-of-the-k-means-clustering-algorithm">Basic Idea of the \( k \)-means Clustering Algorithm </h2>
<p>The simplest of all clustering algorithms is the <b>k-means algorithm</b>
, sometimes also referred to as <em>Lloyds algorithm</em>. It is the simplest and also
the most common. From its simplicity it obtains both strengths and weaknesses.
These will be discussed in more detail later. The \( k \)-means algorithm is a
<b>centroid based</b> clustering algorithm.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-k-means-algorithm">The \( k \)-means Algorithm </h2>
<p>Assume, we are given \( n \) data points and we wish to split the data into \( K < n \)
different categories, or clusters. We label each cluster by an integer
</p>
$$ k\in\{1, \cdots, K \}.
$$
<p>In the basic k-means algorithm each point is assigned to only
one cluster \( k \), and these assignments are <em>non-injective</em> i.e. many-to-one. We
can think of these mappings as an encoder \( k = C(i) \), which assigns the \( i \)-th
data-point \( \bf x_i \) to the \( k \)-th cluster.
</p>
<p>\( k \)-means algorithm in words:</p>
<ol>
<li> We start with guesses / random initializations of our \( k \) cluster centers/centroids</li>
<li> For each centroid the points that are most similar are identified</li>
<li> Then we move / replace each centroid with a coordinate average of all the points that were assigned to that centroid.</li>
<li> Iterate 2-3 until the centroids no longer move (to some tolerance)</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="basic-math-of-the-k-means-algorithm">Basic Math of the \( k \)-means Algorithm </h2>
<p>We assume we have \( n \) data-points</p>
$$
\begin{equation}\label{eq:kmeanspoints}
\boldsymbol{x_i} = \{x_{i, 1}, \cdots, x_{i, p}\}\in\mathbb{R}^p.
\end{equation}
$$
<p>which we wish to group into \( K < n \) clusters. For our dissimilarity measure we
use the <em>squared Euclidean distance</em>
</p>
$$
\begin{equation}\label{eq:squaredeuclidean}
d(\boldsymbol{x_i}, \boldsymbol{x_i'}) = \sum_{j=1}^p(x_{ij} - x_{i'j})^2
= ||\boldsymbol{x_i} - \boldsymbol{x_{i'}}||^2
\end{equation}
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="within-cluster-point-scatter">Within Cluster Point Scatter </h2>
<p>We define the so called <em>within-cluster point scatter</em> which gives us a
measure of how close each data point assigned to the same cluster tends to be to
the all the others.
</p>
$$
\begin{equation}\label{eq:withincluster}
W(C) = \frac{1}{2}\sum_{k=1}^K\sum_{C(i)=k}
\sum_{C(i')=k}d(\boldsymbol{x_i}, \boldsymbol{x_{i'}}) =
\sum_{k=1}^KN_k\sum_{C(i)=k}||\boldsymbol{x_i} - \boldsymbol{\overline{x_k}}||^2
\end{equation}
$$
<p>where \( \boldsymbol{\overline{x_k}} \) is the mean vector associated with the \( k \)-th
cluster, and \( N_k = \sum_{i=1}^nI(C(i) = k) \), where the \( I() \) notation is
similar to the Kronecker delta (<em>Commonly used in statistics, it just means that
when \( i = k \) we have the encoder \( C(i) \)</em>). In other words, the within-cluster
scatter measures the compactness of each cluster with respect to the data points
assigned to each cluster. This is the quantity that the \( k \)-means algorithm aims
to minimize. We refer to this quantity \( W(C) \) as the within cluster scatter
because of its relation to the <em>total scatter</em>.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-details">More Details </h2>
<p>We have</p>
$$
\begin{equation}\label{eq:totalscatter}
T = W(C) + B(C) = \frac{1}{2}\sum_{i=1}^n
\sum_{i'=1}^nd(\boldsymbol{x_i}, \boldsymbol{x_{i'}})
= \frac{1}{2}\sum_{k=1}^K\sum_{C(i)=k}
\Big(\sum_{C(i') = k}d(\boldsymbol{x_i}, \boldsymbol{x_{i'}})
+ \sum_{C(i')\neq k}d(\boldsymbol{x_i}, \boldsymbol{x_{i'}})\Big).
\end{equation}
$$
<p>This is a quantity that is conserved throughout the \( k \)-means algorithm. It can
be thought of as the total amount of information in the data, and it is composed
of the aforementioned within-cluster scatter and the <em>between-cluster scatter</em>
\( B(C) \). In methods such as principle component analysis the total scatter is not
conserved.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="total-cluster-variance">Total Cluster Variance </h2>
<p>Given a cluster mean \( \boldsymbol{m_k} \) we define the <b>total cluster variance</b></p>
$$
\begin{equation}\label{eq:totalclustervariance}
\min_{C, \{\boldsymbol{m_k}\}_1^K}\sum_{k=1}^KN_k\sum||\boldsymbol{x_i} - \boldsymbol{m_k}||^2
\end{equation}
$$
<p>Now we have all the pieces necessary to formally revisit the \( k \)-means algorithm.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-k-means-clustering-algorithm">The \( k \)-means Clustering Algorithm </h2>
<p>The \( k \)-means clustering algorithm goes as follows </p>
<ol>
<li> For a given cluster assignment \( C \), and \( k \) cluster means \( \left\{m_1, \cdots, m_k\right\} \). We minimize the total cluster variance with respect to the cluster means \( \{m_k\} \) yielding the means of the currently assigned clusters.</li>
<li> Given a current set of \( k \) means \( \{m_k\} \) the total cluster variance is minimized by assigning each observation to the closest (current) cluster mean. That is $$C(i) = \underset{1\leq k\leq K}{\mathrm{argmin}} ||\boldsymbol{x_i} - \boldsymbol{m_k}||^2$$</li>
<li> Steps 1 and 2 are repeated until the assignments do not change.</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="summarizing">Summarizing </h2>
<ol>
<li> Before we start we specify a number \( k \) which is the number of clusters we want to try to separate our data into.</li>
<li> We initially choose \( k \) random data points in our data as our initial centroids, <em>or means</em> (this is where the name comes from).</li>
<li> Assign each data point to their closest centroid, based on the squared Euclidean distance.</li>
<li> For each of the \( k \) cluster we update the centroid by calculating new mean values for all the data points in the cluster.</li>
<li> Iteratively minimize the within cluster scatter by performing steps (3, 4) until the new assignments stop changing (can be to some tolerance) or until a maximum number of iterations have passed.</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="writing-our-own-code-the-data-set">Writing our own Code, the Data Set </h2>
<p>Let us now program the most basic version of the algorithm using nothing but
Python with numpy arrays. This code is kept intentionally simple to gradually
progress our understanding. There is no vectorization of any kind, and even most
helper functions are not utilized.
</p>
<p>We need first a dataset to do our cluster analysis on. In our case
this is a plain <em>vanilla</em> data set using random numbers using a
Gaussian distribution.
</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">time</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">tensorflow</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">tf</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">matplotlib</span> <span style="color: #008000; font-weight: bold">import</span> image
<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">sklearn.cluster</span> <span style="color: #008000; font-weight: bold">import</span> KMeans
<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">2021</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>Next we define functions, for ease of use later, to generate Gaussians and to
set up our toy data 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">def</span> <span style="color: #0000FF">gaussian_points</span>(dim<span style="color: #666666">=2</span>, n_points<span style="color: #666666">=1000</span>, mean_vector<span style="color: #666666">=</span>np<span style="color: #666666">.</span>array([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>]),
sample_variance<span style="color: #666666">=1</span>):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Very simple custom function to generate gaussian distributed point clusters</span>
<span style="color: #BA2121; font-style: italic"> with variable dimension, number of points, means in each direction</span>
<span style="color: #BA2121; font-style: italic"> (must match dim) and sample variance.</span>
<span style="color: #BA2121; font-style: italic"> Inputs:</span>
<span style="color: #BA2121; font-style: italic"> dim (int)</span>
<span style="color: #BA2121; font-style: italic"> n_points (int)</span>
<span style="color: #BA2121; font-style: italic"> mean_vector (np.array) (where index 0 is x, index 1 is y etc.)</span>
<span style="color: #BA2121; font-style: italic"> sample_variance (float)</span>
<span style="color: #BA2121; font-style: italic"> Returns:</span>
<span style="color: #BA2121; font-style: italic"> data (np.array): with dimensions (dim x n_points)</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
mean_matrix <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros(dim) <span style="color: #666666">+</span> mean_vector
covariance_matrix <span style="color: #666666">=</span> np<span style="color: #666666">.</span>eye(dim) <span style="color: #666666">*</span> sample_variance
data <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>multivariate_normal(mean_matrix, covariance_matrix,
n_points)
<span style="color: #008000; font-weight: bold">return</span> data
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">generate_simple_clustering_dataset</span>(dim<span style="color: #666666">=2</span>, n_points<span style="color: #666666">=1000</span>, plotting<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>,
return_data<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Toy model to illustrate k-means clustering</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
data1 <span style="color: #666666">=</span> gaussian_points(mean_vector<span style="color: #666666">=</span>np<span style="color: #666666">.</span>array([<span style="color: #666666">5</span>, <span style="color: #666666">5</span>]))
data2 <span style="color: #666666">=</span> gaussian_points()
data3 <span style="color: #666666">=</span> gaussian_points(mean_vector<span style="color: #666666">=</span>np<span style="color: #666666">.</span>array([<span style="color: #666666">1</span>, <span style="color: #666666">4.5</span>]))
data4 <span style="color: #666666">=</span> gaussian_points(mean_vector<span style="color: #666666">=</span>np<span style="color: #666666">.</span>array([<span style="color: #666666">5</span>, <span style="color: #666666">1</span>]))
data <span style="color: #666666">=</span> np<span style="color: #666666">.</span>concatenate((data1, data2, data3, data4), axis<span style="color: #666666">=0</span>)
<span style="color: #008000; font-weight: bold">if</span> plotting:
fig, ax <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>subplots()
ax<span style="color: #666666">.</span>scatter(data[:, <span style="color: #666666">0</span>], data[:, <span style="color: #666666">1</span>], alpha<span style="color: #666666">=0.2</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&#39;Toy Model Dataset&#39;</span>)
plt<span style="color: #666666">.</span>show()
<span style="color: #008000; font-weight: bold">if</span> return_data:
<span style="color: #008000; font-weight: bold">return</span> data
data <span style="color: #666666">=</span> generate_simple_clustering_dataset()
</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="implementing-the-k-means-algorithm">Implementing the \( k \)-means Algorithm </h2>
<p>With the above dataset we start
implementing the \( k \)-means algorithm.
</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%;">n_samples, dimensions <span style="color: #666666">=</span> data<span style="color: #666666">.</span>shape
n_clusters <span style="color: #666666">=</span> <span style="color: #666666">4</span>
<span style="color: #408080; font-style: italic"># we randomly initialize our centroids</span>
np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>seed(<span style="color: #666666">2021</span>)
centroids <span style="color: #666666">=</span> data[np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>choice(n_samples, n_clusters, replace<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">False</span>), :]
distances <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros((n_samples, n_clusters))
<span style="color: #408080; font-style: italic"># first we need to calculate the distance to each centroid from our data</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>(n_clusters):
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
dist <span style="color: #666666">=</span> <span style="color: #666666">0</span>
<span style="color: #008000; font-weight: bold">for</span> d <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(dimensions):
dist <span style="color: #666666">+=</span> np<span style="color: #666666">.</span>abs(data[n, d] <span style="color: #666666">-</span> centroids[k, d])<span style="color: #666666">**2</span>
distances[n, k] <span style="color: #666666">=</span> dist
<span style="color: #408080; font-style: italic"># we initialize an array to keep track of to which cluster each point belongs</span>
<span style="color: #408080; font-style: italic"># the way we set it up here the index tracks which point and the value which</span>
<span style="color: #408080; font-style: italic"># cluster the point belongs to</span>
cluster_labels <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros(n_samples, dtype<span style="color: #666666">=</span><span style="color: #BA2121">&#39;int&#39;</span>)
<span style="color: #408080; font-style: italic"># next we loop through our samples and for every point assign it to the cluster</span>
<span style="color: #408080; font-style: italic"># to which it has the smallest distance to</span>
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
<span style="color: #408080; font-style: italic"># tracking variables (all of this is basically just an argmin)</span>
smallest <span style="color: #666666">=</span> <span style="color: #666666">1e10</span>
smallest_row_index <span style="color: #666666">=</span> <span style="color: #666666">1e10</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>(n_clusters):
<span style="color: #008000; font-weight: bold">if</span> distances[n, k] <span style="color: #666666">&lt;</span> smallest:
smallest <span style="color: #666666">=</span> distances[n, k]
smallest_row_index <span style="color: #666666">=</span> k
cluster_labels[n] <span style="color: #666666">=</span> smallest_row_index
</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="plotting">Plotting </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%;">fig <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>figure()
ax <span style="color: #666666">=</span> fig<span style="color: #666666">.</span>add_subplot()
unique_cluster_labels <span style="color: #666666">=</span> np<span style="color: #666666">.</span>unique(cluster_labels)
<span style="color: #008000; font-weight: bold">for</span> i <span style="color: #AA22FF; font-weight: bold">in</span> unique_cluster_labels:
ax<span style="color: #666666">.</span>scatter(data[cluster_labels <span style="color: #666666">==</span> i, <span style="color: #666666">0</span>],
data[cluster_labels <span style="color: #666666">==</span> i, <span style="color: #666666">1</span>],
label <span style="color: #666666">=</span> i,
alpha <span style="color: #666666">=</span> <span style="color: #666666">0.2</span>)
ax<span style="color: #666666">.</span>scatter(centroids[:, <span style="color: #666666">0</span>], centroids[:, <span style="color: #666666">1</span>], c<span style="color: #666666">=</span><span style="color: #BA2121">&#39;black&#39;</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&quot;First Grouping of Points to Centroids&quot;</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>
<p>So what do we have so far? We have 'picked' \( k \) centroids at random from our
data points. There are other ways of more intelligently choosing their
initializations, however for our purposes randomly is fine. Then we have
initialized an array 'distances' which holds the information of the distance,
<em>or dissimilarity</em>, of every point to of our centroids. Finally, we have
initialized an array 'cluster_labels' which according to our distances array
holds the information of to which centroid every point is assigned. This was the
first pass of our algorithm. Essentially, all we need to do now is repeat the
distance and assignment steps above until we have reached a desired convergence
or a maximum amount of iterations.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="continuing">Continuing </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%;">max_iterations <span style="color: #666666">=</span> <span style="color: #666666">100</span>
tolerance <span style="color: #666666">=</span> <span style="color: #666666">1e-8</span>
<span style="color: #008000; font-weight: bold">for</span> iteration <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(max_iterations):
prev_centroids <span style="color: #666666">=</span> centroids<span style="color: #666666">.</span>copy()
<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>(n_clusters):
<span style="color: #408080; font-style: italic"># this array will be used to update our centroid positions</span>
vector_mean <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros(dimensions)
mean_divisor <span style="color: #666666">=</span> <span style="color: #666666">0</span>
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
<span style="color: #008000; font-weight: bold">if</span> cluster_labels[n] <span style="color: #666666">==</span> k:
vector_mean <span style="color: #666666">+=</span> data[n, :]
mean_divisor <span style="color: #666666">+=</span> <span style="color: #666666">1</span>
<span style="color: #408080; font-style: italic"># update according to the k means</span>
centroids[k, :] <span style="color: #666666">=</span> vector_mean <span style="color: #666666">/</span> mean_divisor
<span style="color: #408080; font-style: italic"># we find the dissimilarity</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>(n_clusters):
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
dist <span style="color: #666666">=</span> <span style="color: #666666">0</span>
<span style="color: #008000; font-weight: bold">for</span> d <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(dimensions):
dist <span style="color: #666666">+=</span> np<span style="color: #666666">.</span>abs(data[n, d] <span style="color: #666666">-</span> centroids[k, d])<span style="color: #666666">**2</span>
distances[n, k] <span style="color: #666666">=</span> dist
<span style="color: #408080; font-style: italic"># assign each point</span>
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
smallest <span style="color: #666666">=</span> <span style="color: #666666">1e10</span>
smallest_row_index <span style="color: #666666">=</span> <span style="color: #666666">1e10</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>(n_clusters):
<span style="color: #008000; font-weight: bold">if</span> distances[n, k] <span style="color: #666666">&lt;</span> smallest:
smallest <span style="color: #666666">=</span> distances[n, k]
smallest_row_index <span style="color: #666666">=</span> k
cluster_labels[n] <span style="color: #666666">=</span> smallest_row_index
<span style="color: #408080; font-style: italic"># convergence criteria</span>
centroid_difference <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(np<span style="color: #666666">.</span>abs(centroids <span style="color: #666666">-</span> prev_centroids))
<span style="color: #008000; font-weight: bold">if</span> centroid_difference <span style="color: #666666">&lt;</span> tolerance:
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&#39;Converged at iteration </span><span style="color: #BB6688; font-weight: bold">{</span>iteration<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&#39;</span>)
<span style="color: #008000; font-weight: bold">break</span>
<span style="color: #008000; font-weight: bold">elif</span> iteration <span style="color: #666666">==</span> max_iterations:
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&#39;Did not converge in </span><span style="color: #BB6688; font-weight: bold">{</span>max_iterations<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121"> iterations&#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="wrapping-it-up">Wrapping it up </h2>
<p>We now have a simple , un-optimized \( k \)-means
clustering implementation. Lets plot the final result
</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%;">fig <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>figure()
ax <span style="color: #666666">=</span> fig<span style="color: #666666">.</span>add_subplot()
unique_cluster_labels <span style="color: #666666">=</span> np<span style="color: #666666">.</span>unique(cluster_labels)
<span style="color: #008000; font-weight: bold">for</span> i <span style="color: #AA22FF; font-weight: bold">in</span> unique_cluster_labels:
ax<span style="color: #666666">.</span>scatter(data[cluster_labels <span style="color: #666666">==</span> i, <span style="color: #666666">0</span>],
data[cluster_labels <span style="color: #666666">==</span> i, <span style="color: #666666">1</span>],
label <span style="color: #666666">=</span> i,
alpha <span style="color: #666666">=</span> <span style="color: #666666">0.2</span>)
ax<span style="color: #666666">.</span>scatter(centroids[:, <span style="color: #666666">0</span>], centroids[:, <span style="color: #666666">1</span>], c<span style="color: #666666">=</span><span style="color: #BA2121">&#39;black&#39;</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&quot;Final Result of K-means Clustering&quot;</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>
<!-- 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">def</span> <span style="color: #0000FF">naive_kmeans</span>(data, n_clusters<span style="color: #666666">=4</span>, max_iterations<span style="color: #666666">=100</span>, tolerance<span style="color: #666666">=1e-8</span>):
start_time <span style="color: #666666">=</span> time<span style="color: #666666">.</span>time()
n_samples, dimensions <span style="color: #666666">=</span> data<span style="color: #666666">.</span>shape
n_clusters <span style="color: #666666">=</span> <span style="color: #666666">4</span>
<span style="color: #408080; font-style: italic">#np.random.seed(2021)</span>
centroids <span style="color: #666666">=</span> data[np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>choice(n_samples, n_clusters, replace<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">False</span>), :]
distances <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros((n_samples, n_clusters))
<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>(n_clusters):
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
dist <span style="color: #666666">=</span> <span style="color: #666666">0</span>
<span style="color: #008000; font-weight: bold">for</span> d <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(dimensions):
dist <span style="color: #666666">+=</span> np<span style="color: #666666">.</span>abs(data[n, d] <span style="color: #666666">-</span> centroids[k, d])<span style="color: #666666">**2</span>
distances[n, k] <span style="color: #666666">=</span> dist
cluster_labels <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros(n_samples, dtype<span style="color: #666666">=</span><span style="color: #BA2121">&#39;int&#39;</span>)
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
smallest <span style="color: #666666">=</span> <span style="color: #666666">1e10</span>
smallest_row_index <span style="color: #666666">=</span> <span style="color: #666666">1e10</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>(n_clusters):
<span style="color: #008000; font-weight: bold">if</span> distances[n, k] <span style="color: #666666">&lt;</span> smallest:
smallest <span style="color: #666666">=</span> distances[n, k]
smallest_row_index <span style="color: #666666">=</span> k
cluster_labels[n] <span style="color: #666666">=</span> smallest_row_index
<span style="color: #008000; font-weight: bold">for</span> iteration <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(max_iterations):
prev_centroids <span style="color: #666666">=</span> centroids<span style="color: #666666">.</span>copy()
<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>(n_clusters):
vector_mean <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros(dimensions)
mean_divisor <span style="color: #666666">=</span> <span style="color: #666666">0</span>
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
<span style="color: #008000; font-weight: bold">if</span> cluster_labels[n] <span style="color: #666666">==</span> k:
vector_mean <span style="color: #666666">+=</span> data[n, :]
mean_divisor <span style="color: #666666">+=</span> <span style="color: #666666">1</span>
centroids[k, :] <span style="color: #666666">=</span> vector_mean <span style="color: #666666">/</span> mean_divisor
<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>(n_clusters):
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
dist <span style="color: #666666">=</span> <span style="color: #666666">0</span>
<span style="color: #008000; font-weight: bold">for</span> d <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(dimensions):
dist <span style="color: #666666">+=</span> np<span style="color: #666666">.</span>abs(data[n, d] <span style="color: #666666">-</span> centroids[k, d])<span style="color: #666666">**2</span>
distances[n, k] <span style="color: #666666">=</span> dist
<span style="color: #008000; font-weight: bold">for</span> n <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_samples):
smallest <span style="color: #666666">=</span> <span style="color: #666666">1e10</span>
smallest_row_index <span style="color: #666666">=</span> <span style="color: #666666">1e10</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>(n_clusters):
<span style="color: #008000; font-weight: bold">if</span> distances[n, k] <span style="color: #666666">&lt;</span> smallest:
smallest <span style="color: #666666">=</span> distances[n, k]
smallest_row_index <span style="color: #666666">=</span> k
cluster_labels[n] <span style="color: #666666">=</span> smallest_row_index
centroid_difference <span style="color: #666666">=</span> np<span style="color: #666666">.</span>sum(np<span style="color: #666666">.</span>abs(centroids <span style="color: #666666">-</span> prev_centroids))
<span style="color: #008000; font-weight: bold">if</span> centroid_difference <span style="color: #666666">&lt;</span> tolerance:
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&#39;Converged at iteration </span><span style="color: #BB6688; font-weight: bold">{</span>iteration<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&#39;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&#39;Runtime: </span><span style="color: #BB6688; font-weight: bold">{</span>time<span style="color: #666666">.</span>time() <span style="color: #666666">-</span> start_time<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121"> seconds&#39;</span>)
<span style="color: #008000; font-weight: bold">return</span> cluster_labels, centroids
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&#39;Did not converge in </span><span style="color: #BB6688; font-weight: bold">{</span>max_iterations<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121"> iterations&#39;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&#39;Runtime: </span><span style="color: #BB6688; font-weight: bold">{</span>time<span style="color: #666666">.</span>time() <span style="color: #666666">-</span> start_time<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121"> seconds&#39;</span>)
<span style="color: #008000; font-weight: bold">return</span> cluster_labels, centroids
</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="summary-of-course">Summary of course </h2>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="what-me-worry-no-final-exam-in-this-course">What? Me worry? No final exam in this course! </h2>
<br/><br/>
<center>
<p><img src="figures/exam1.jpeg" width="500" align="bottom"></p>
</center>
<br/><br/>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="what-is-the-link-between-artificial-intelligence-and-machine-learning-and-some-general-remarks">What is the link between Artificial Intelligence and Machine Learning and some general Remarks </h2>
<p>Artificial intelligence is built upon integrated machine learning
algorithms as discussed in this course, which in turn are fundamentally rooted in optimization and
statistical learning.
</p>
<p>Can we have Artificial Intelligence without Machine Learning? See <a href="https://www.linkedin.com/pulse/what-artificial-intelligence-without-machine-learning-claudia-pohlink" target="_blank">this post for inspiration</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="going-back-to-the-beginning-of-the-semester">Going back to the beginning of the semester </h2>
<p>Traditionally the field of machine learning has had its main focus on
predictions and correlations. These concepts outline in some sense
the difference between machine learning and what is normally called
Bayesian statistics or Bayesian inference.
</p>
<p>In machine learning and prediction based tasks, we are often
interested in developing algorithms that are capable of learning
patterns from given data in an automated fashion, and then using these
learned patterns to make predictions or assessments of newly given
data. In many cases, our primary concern is the quality of the
predictions or assessments, and we are less concerned with the
underlying patterns that were learned in order to make these
predictions. This leads to what normally has been labeled as a
frequentist approach.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="not-so-sharp-distinctions">Not so sharp distinctions </h2>
<p>You should keep in mind that the division between a traditional
frequentist approach with focus on predictions and correlations only
and a Bayesian approach with an emphasis on estimations and
causations, is not that sharp. Machine learning can be frequentist
with ensemble methods (EMB) as examples and Bayesian with Gaussian
Processes as examples.
</p>
<p>If one views ML from a statistical learning
perspective, one is then equally interested in estimating errors as
one is in finding correlations and making predictions. It is important
to keep in mind that the frequentist and Bayesian approaches differ
mainly in their interpretations of probability. In the frequentist
world, we can only assign probabilities to repeated random
phenomena. From the observations of these phenomena, we can infer the
probability of occurrence of a specific event. In Bayesian
statistics, we assign probabilities to specific events and the
probability represents the measure of belief/confidence for that
event. The belief can be updated in the light of new evidence.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="topics-we-have-covered-this-year">Topics we have covered this year </h2>
<p>The course has two central parts</p>
<ol>
<li> Statistical analysis and optimization of data</li>
<li> Machine learning</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="statistical-analysis-and-optimization-of-data">Statistical analysis and optimization of data </h2>
<p>The following topics have been discussed:</p>
<ol>
<li> Basic concepts, expectation values, variance, covariance, correlation functions and errors;</li>
<li> Simpler models, binomial distribution, the Poisson distribution, simple and multivariate normal distributions;</li>
<li> Central elements from linear algebra, matrix inversion and SVD</li>
<li> Gradient methods for data optimization</li>
<li> Estimation of errors using cross-validation, bootstrapping and jackknife methods;</li>
<li> Practical optimization using Singular-value decomposition and least squares for parameterizing data.</li>
<li> Principal Component Analysis to reduce the number of features.</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="machine-learning">Machine learning </h2>
<p>The following topics will be covered</p>
<ol>
<li> Linear methods for regression and classification:
<ol type="a"></li>
<li> Ordinary Least Squares</li>
<li> Ridge regression</li>
<li> Lasso regression</li>
<li> Logistic regression</li>
</ol>
<li> Neural networks and deep learning:
<ol type="a"></li>
<li> Feed Forward Neural Networks</li>
<li> Convolutional Neural Networks</li>
<li> Recurrent Neural Networks</li>
</ol>
<li> Decisions trees and ensemble methods:
<ol type="a"></li>
<li> Decision trees</li>
<li> Bagging and voting</li>
<li> Random forests</li>
<li> Boosting and gradient boosting</li>
</ol>
<li> Support vector machines
<ol type="a"></li>
<li> Binary classification and multiclass classification</li>
<li> Kernel methods</li>
<li> Regression</li>
</ol>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="learning-outcomes-and-overarching-aims-of-this-course">Learning outcomes and overarching aims of this course </h2>
<p>The course introduces a variety of central algorithms and methods
essential for studies of data analysis and machine learning. The
course is project based and through the various projects, normally
three, you will be exposed to fundamental research problems
in these fields, with the aim to reproduce state of the art scientific
results. The students will learn to develop and structure large codes
for studying these systems, get acquainted with computing facilities
and learn to handle large scientific projects. A good scientific and
ethical conduct is emphasized throughout the course.
</p>
<ul>
<li> Understand linear methods for regression and classification;</li>
<li> Learn about neural network;</li>
<li> Learn about bagging, boosting and trees</li>
<li> Support vector machines</li>
<li> Learn about basic data analysis;</li>
<li> Be capable of extending the acquired knowledge to other systems and cases;</li>
<li> Have an understanding of central algorithms used in data analysis and machine learning;</li>
<li> Work on numerical projects to illustrate the theory. The projects play a central role and you are expected to know modern programming languages like Python or C++.</li>
</ul>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="perspective-on-machine-learning">Perspective on Machine Learning </h2>
<ol>
<li> Rapidly emerging application area</li>
<li> Experiment AND theory are evolving in many many fields. Still many low-hanging fruits.</li>
<li> Requires education/retraining for more widespread adoption</li>
<li> A lot of &#8220;word-of-mouth&#8221; development methods</li>
</ol>
<p>Huge amounts of data sets require automation, classical analysis tools often inadequate.
High energy physics hit this wall in the 90&#8217;s.
In 2009 single top quark production was determined via <a href="https://arxiv.org/pdf/0903.0850.pdf" target="_blank">Boosted decision trees, Bayesian
Neural Networks, etc.</a>. Similarly, the search for Higgs was a statistical learning tour de force. See this link on <a href="https://www.kaggle.com/c/higgs-boson" target="_blank">Kaggle.com</a>.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="machine-learning-research">Machine Learning Research </h2>
<p>Where to find recent results:</p>
<ol>
<li> Conference proceedings, arXiv and blog posts!</li>
<li> <b>NIPS</b>: <a href="https://papers.nips.cc" target="_blank">Neural Information Processing Systems</a></li>
<li> <b>ICLR</b>: <a href="https://openreview.net/group?id=ICLR.cc/2018/Conference#accepted-oral-papers" target="_blank">International Conference on Learning Representations</a></li>
<li> <b>ICML</b>: International Conference on Machine Learning</li>
<li> <a href="http://www.jmlr.org/papers/v19/" target="_blank">Journal of Machine Learning Research</a></li>
<li> <a href="https://arxiv.org/list/cs.LG/recent" target="_blank">Follow ML on ArXiv</a></li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="starting-your-machine-learning-project">Starting your Machine Learning Project </h2>
<ol>
<li> Identify problem type: classification, regression</li>
<li> Consider your data carefully</li>
<li> Choose a simple model that fits 1. and 2.</li>
<li> Consider your data carefully again! Think of data representation more carefully.</li>
<li> Based on your results, feedback loop to earliest possible point</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="choose-a-model-and-algorithm">Choose a Model and Algorithm </h2>
<ol>
<li> Supervised?</li>
<li> Start with the simplest model that fits your problem</li>
<li> Start with minimal processing of data</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="preparing-your-data">Preparing Your Data </h2>
<ol>
<li> Shuffle your data</li>
<li> Mean center your data</li>
<ul>
<li> Why?</li>
</ul>
<li> Normalize the variance</li>
<ul>
<li> Why?</li>
</ul>
<li> <a href="https://multivariatestatsjl.readthedocs.io/en/latest/whiten.html" target="_blank">Whitening</a></li>
<ul>
<li> Decorrelates data</li>
<li> Can be hit or miss</li>
</ul>
<li> When to do train/test split?</li>
</ol>
<p>Whitening is a decorrelation transformation that transforms a set of
random variables into a set of new random variables with identity
covariance (uncorrelated with unit variances).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="which-activation-and-weights-to-choose-in-neural-networks">Which Activation and Weights to Choose in Neural Networks </h2>
<ol>
<li> RELU? ELU?</li>
<li> Sigmoid or Tanh?</li>
<li> Set all weights to 0?</li>
<ul>
<li> Terrible idea</li>
</ul>
<li> Set all weights to random values?</li>
<ul>
<li> Small random values</li>
</ul>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="optimization-methods-and-hyperparameters">Optimization Methods and Hyperparameters </h2>
<ol>
<li> Stochastic gradient descent
<ol type="a"></li>
<li> Stochastic gradient descent + momentum</li>
</ol>
<li> State-of-the-art approaches:</li>
<ul>
<li> RMSProp</li>
<li> Adam</li>
<li> and more</li>
</ul>
</ol>
<p>Which regularization and hyperparameters? \( L_1 \) or \( L_2 \), soft
classifiers, depths of trees and many other. Need to explore a large
set of hyperparameters and regularization methods.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="resampling">Resampling </h2>
<p>When do we resample?</p>
<ol>
<li> <a href="https://www.cambridge.org/core/books/bootstrap-methods-and-their-application/ED2FD043579F27952363566DC09CBD6A" target="_blank">Bootstrap</a></li>
<li> <a href="https://www.youtube.com/watch?v=fSytzGwwBVw&ab_channel=StatQuestwithJoshStarmer" target="_blank">Cross-validation</a></li>
<li> Jackknife and many other</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="other-courses-on-data-science-and-machine-learning-at-uio">Other courses on Data science and Machine Learning at UiO </h2>
<p>The link here <a href="https://www.mn.uio.no/english/research/about/centre-focus/innovation/data-science/studies/" target="_blank"><tt>https://www.mn.uio.no/english/research/about/centre-focus/innovation/data-science/studies/</tt></a> gives an excellent overview of courses on Machine learning at UiO.</p>
<ol>
<li> <a href="http://www.uio.no/studier/emner/matnat/math/STK2100/index-eng.html" target="_blank">STK2100 Machine learning and statistical methods for prediction and classification</a>.</li>
<li> <a href="https://www.uio.no/studier/emner/matnat/ifi/IN3050/index-eng.html" target="_blank">IN3050/IN4050 Introduction to Artificial Intelligence and Machine Learning</a>. Introductory course in machine learning and AI with an algorithmic approach.</li>
<li> <a href="http://www.uio.no/studier/emner/matnat/math/STK-INF3000/index-eng.html" target="_blank">STK-INF3000/4000 Selected Topics in Data Science</a>. The course provides insight into selected contemporary relevant topics within Data Science.</li>
<li> <a href="https://www.uio.no/studier/emner/matnat/ifi/IN4080/index.html" target="_blank">IN4080 Natural Language Processing</a>. Probabilistic and machine learning techniques applied to natural language processing.</li>
<li> <a href="https://www.uio.no/studier/emner/matnat/math/STK-IN4300/index-eng.html" target="_blank">STK-IN4300 &#8211; Statistical learning methods in Data Science</a>. An advanced introduction to statistical and machine learning. For students with a good mathematics and statistics background.</li>
<li> <a href="https://www.uio.no/studier/emner/matnat/ifi/IN-STK5000/index-eng.html" target="_blank">IN-STK5000 Adaptive Methods for Data-Based Decision Making</a>. Methods for adaptive collection and processing of data based on machine learning techniques.</li>
<li> <a href="https://www.uio.no/studier/emner/matnat/ifi/IN5400/" target="_blank">IN5400/INF5860 &#8211; Machine Learning for Image Analysis</a>. An introduction to deep learning with particular emphasis on applications within Image analysis, but useful for other application areas too.</li>
<li> <a href="https://www.uio.no/studier/emner/matnat/its/TEK5040/" target="_blank">TEK5040 &#8211; Dyp l&#230;ring for autonome systemer</a>. The course addresses advanced algorithms and architectures for deep learning with neural networks. The course provides an introduction to how deep-learning techniques can be used in the construction of key parts of advanced autonomous systems that exist in physical environments and cyber environments.</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="additional-courses-of-interest">Additional courses of interest </h2>
<ol>
<li> <a href="https://www.uio.no/studier/emner/matnat/math/STK4051/index-eng.html" target="_blank">STK4051 Computational Statistics</a></li>
<li> <a href="https://www.uio.no/studier/emner/matnat/math/STK4021/index-eng.html" target="_blank">STK4021 Applied Bayesian Analysis and Numerical Methods</a></li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="what-s-the-future-like">What's the future like? </h2>
<p>Based on multi-layer nonlinear neural networks, deep learning can
learn directly from raw data, automatically extract and abstract
features from layer to layer, and then achieve the goal of regression,
classification, or ranking. Deep learning has made breakthroughs in
computer vision, speech processing and natural language, and reached
or even surpassed human level. The success of deep learning is mainly
due to the three factors: big data, big model, and big computing.
</p>
<p>In the past few decades, many different architectures of deep neural
networks have been proposed, such as
</p>
<ol>
<li> Convolutional neural networks, which are mostly used in image and video data processing, and have also been applied to sequential data such as text processing;</li>
<li> Recurrent neural networks, which can process sequential data of variable length and have been widely used in natural language understanding and speech processing;</li>
<li> Encoder-decoder framework, which is mostly used for image or sequence generation, such as machine translation, text summarization, and image captioning.</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="types-of-machine-learning-a-repetition">Types of Machine Learning, a repetition </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>The approaches to machine learning are many, but are often split into two main categories.
In <em>supervised learning</em> we know the answer to a problem,
and let the computer deduce the logic behind it. On the other hand, <em>unsupervised learning</em>
is a method for finding patterns and relationship in data sets without any prior knowledge of the system.
Some authours also operate with a third category, namely <em>reinforcement learning</em>. This is a paradigm
of learning inspired by behavioural psychology, where learning is achieved by trial-and-error,
solely from rewards and punishment.
</p>
<p>Another way to categorize machine learning tasks is to consider the desired output of a system.
Some of the most common tasks are:
</p>
<ul>
<li> Classification: Outputs are divided into two or more classes. The goal is to produce a model that assigns inputs into one of these classes. An example is to identify digits based on pictures of hand-written ones. Classification is typically supervised learning.</li>
<li> Regression: Finding a functional relationship between an input data set and a reference data set. The goal is to construct a function that maps input data to continuous output values.</li>
<li> Clustering: Data are divided into groups with certain common traits, without knowing the different groups beforehand. It is thus a form of unsupervised learning.</li>
<li> Other unsupervised learning algortihms like <b>Boltzmann machines</b></li>
</ul>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="why-boltzmann-machines">Why Boltzmann machines? </h2>
<p>What is known as restricted Boltzmann Machines (RMB) have received a lot of attention lately.
One of the major reasons is that they can be stacked layer-wise to build deep neural networks that capture complicated statistics.
</p>
<p>The original RBMs had just one visible layer and a hidden layer, but recently so-called Gaussian-binary RBMs have gained quite some popularity in imaging since they are capable of modeling continuous data that are common to natural images. </p>
<p>Furthermore, they have been used to solve complicated <a href="https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.91.045002" target="_blank">quantum mechanical many-particle problems or classical statistical physics problems like the Ising and Potts classes of models</a>. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="boltzmann-machines">Boltzmann Machines </h2>
<p>Why use a generative model rather than the more well known discriminative deep neural networks (DNN)? </p>
<ul>
<li> Discriminitave methods have several limitations: They are mainly supervised learning methods, thus requiring labeled data. And there are tasks they cannot accomplish, like drawing new examples from an unknown probability distribution.</li>
<li> A generative model can learn to represent and sample from a probability distribution. The core idea is to learn a parametric model of the probability distribution from which the training data was drawn. As an example
<ol type="a"></li>
<li> A model for images could learn to draw new examples of cats and dogs, given a training dataset of images of cats and dogs.</li>
<li> Generate a sample of an ordered or disordered phase, having been given samples of such phases.</li>
<li> Model the trial function for <a href="https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.91.045002" target="_blank">Monte Carlo calculations</a>.</li>
</ol>
</ul>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="some-similarities-and-differences-from-dnns">Some similarities and differences from DNNs </h2>
<ol>
<li> Both use gradient-descent based learning procedures for minimizing cost functions</li>
<li> Energy based models don't use backpropagation and automatic differentiation for computing gradients, instead turning to Markov Chain Monte Carlo methods.</li>
<li> DNNs often have several hidden layers. A restricted Boltzmann machine has only one hidden layer, however several RBMs can be stacked to make up Deep Belief Networks, of which they constitute the building blocks.</li>
</ol>
<p>History: The RBM was developed by amongst others <a href="https://en.wikipedia.org/wiki/Geoffrey_Hinton" target="_blank">Geoffrey Hinton</a>, called by some the "Godfather of Deep Learning", working with the University of Toronto and Google.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="boltzmann-machines-bm">Boltzmann machines (BM) </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>A BM is what we would call an undirected probabilistic graphical model
with stochastic continuous or discrete units.
</p>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>It is interpreted as a stochastic recurrent neural network where the
state of each unit(neurons/nodes) depends on the units it is connected
to. The weights in the network represent thus the strength of the
interaction between various units/nodes.
</p>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>It turns into a Hopfield network if we choose deterministic rather
than stochastic units. In contrast to a Hopfield network, a BM is a
so-called generative model. It allows us to generate new samples from
the learned distribution.
</p>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-standard-bm-setup">A standard BM setup </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>A standard BM network is divided into a set of observable and visible units \( \hat{x} \) and a set of unknown hidden units/nodes \( \hat{h} \).</p>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>Additionally there can be bias nodes for the hidden and visible layers. These biases are normally set to \( 1 \).</p>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>BMs are stackable, meaning they cwe can train a BM which serves as input to another BM. We can construct deep networks for learning complex PDFs. The layers can be trained one after another, a feature which makes them popular in deep learning</p>
</div>
<p>However, they are often hard to train. This leads to the introduction of so-called restricted BMs, or RBMS.
Here we take away all lateral connections between nodes in the visible layer as well as connections between nodes in the hidden layer. The network is illustrated in the figure below.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-structure-of-the-rbm-network">The structure of the RBM network </h2>
<br/><br/>
<center>
<p><img src="figures/RBM.png" width="800" align="bottom"></p>
</center>
<br/><br/>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-network">The network </h2>
<b>The network layers</b>:
<ol>
<li> A function \( \mathbf{x} \) that represents the visible layer, a vector of \( M \) elements (nodes). This layer represents both what the RBM might be given as training input, and what we want it to be able to reconstruct. This might for example be given by the pixels of an image or coefficients representing speech, or the coordinates of a quantum mechanical state function.</li>
<li> The function \( \mathbf{h} \) represents the hidden, or latent, layer. A vector of \( N \) elements (nodes). Also called "feature detectors".</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="goals">Goals </h2>
<p>The goal of the hidden layer is to increase the model's expressive
power. We encode complex interactions between visible variables by
introducing additional, hidden variables that interact with visible
degrees of freedom in a simple manner, yet still reproduce the complex
correlations between visible degrees in the data once marginalized
over (integrated out).
</p>
<b>The network parameters, to be optimized/learned</b>:
<ol>
<li> \( \mathbf{a} \) represents the visible bias, a vector of same length as \( \mathbf{x} \).</li>
<li> \( \mathbf{b} \) represents the hidden bias, a vector of same lenght as \( \mathbf{h} \).</li>
<li> \( W \) represents the interaction weights, a matrix of size \( M\times N \).</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="joint-distribution">Joint distribution </h2>
<p>The restricted Boltzmann machine is described by a Boltzmann distribution</p>
$$
\begin{align}
P_{rbm}(\mathbf{x},\mathbf{h}) = \frac{1}{Z} e^{-\frac{1}{T_0}E(\mathbf{x},\mathbf{h})},
\label{_auto1}
\end{align}
$$
<p>where \( Z \) is the normalization constant or partition function, defined as </p>
$$
\begin{align}
Z = \int \int e^{-\frac{1}{T_0}E(\mathbf{x},\mathbf{h})} d\mathbf{x} d\mathbf{h}.
\label{_auto2}
\end{align}
$$
<p>It is common to ignore \( T_0 \) by setting it to one. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="network-elements-the-energy-function">Network Elements, the energy function </h2>
<p>The function \( E(\mathbf{x},\mathbf{h}) \) gives the <b>energy</b> of a
configuration (pair of vectors) \( (\mathbf{x}, \mathbf{h}) \). The lower
the energy of a configuration, the higher the probability of it. This
function also depends on the parameters \( \mathbf{a} \), \( \mathbf{b} \) and
\( W \). Thus, when we adjust them during the learning procedure, we are
adjusting the energy function to best fit our problem.
</p>
<p>An expression for the energy function is</p>
$$
E(\hat{x},\hat{h}) = -\sum_{ia}^{NA}b_i^a \alpha_i^a(x_i)-\sum_{jd}^{MD}c_j^d \beta_j^d(h_j)-\sum_{ijad}^{NAMD}b_i^a \alpha_i^a(x_i)c_j^d \beta_j^d(h_j)w_{ij}^{ad}.
$$
<p>Here \( \beta_j^d(h_j) \) and \( \alpha_i^a(x_j) \) are so-called transfer functions that map a given input value to a desired feature value. The labels \( a \) and \( d \) denote that there can be multiple transfer functions per variable. The first sum depends only on the visible units. The second on the hidden ones. <b>Note</b> that there is no connection between nodes in a layer.</p>
<p>The quantities \( b \) and \( c \) can be interpreted as the visible and hidden biases, respectively.</p>
<p>The connection between the nodes in the two layers is given by the weights \( w_{ij} \). </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="defining-different-types-of-rbms">Defining different types of RBMs </h2>
<p>There are different variants of RBMs, and the differences lie in the types of visible and hidden units we choose as well as in the implementation of the energy function \( E(\mathbf{x},\mathbf{h}) \). </p>
<div class="alert alert-block alert-block alert-text-normal">
<b>Binary-Binary RBM:</b>
<p>
<p>RBMs were first developed using binary units in both the visible and hidden layer. The corresponding energy function is defined as follows:</p>
$$
\begin{align}
E(\mathbf{x}, \mathbf{h}) = - \sum_i^M x_i a_i- \sum_j^N b_j h_j - \sum_{i,j}^{M,N} x_i w_{ij} h_j,
\label{_auto3}
\end{align}
$$
<p>where the binary values taken on by the nodes are most commonly 0 and 1.</p>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b>Gaussian-Binary RBM:</b>
<p>
<p>Another varient is the RBM where the visible units are Gaussian while the hidden units remain binary:</p>
$$
\begin{align}
E(\mathbf{x}, \mathbf{h}) = \sum_i^M \frac{(x_i - a_i)^2}{2\sigma_i^2} - \sum_j^N b_j h_j - \sum_{i,j}^{M,N} \frac{x_i w_{ij} h_j}{\sigma_i^2}.
\label{_auto4}
\end{align}
$$
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-about-rbms">More about RBMs </h2>
<ol>
<li> Useful when we model continuous data (i.e., we wish \( \mathbf{x} \) to be continuous)</li>
<li> Requires a smaller learning rate, since there's no upper bound to the value a component might take in the reconstruction</li>
</ol>
<p>Other types of units include:</p>
<ol>
<li> Softmax and multinomial units</li>
<li> Gaussian visible and hidden units</li>
<li> Binomial units</li>
<li> Rectified linear units</li>
</ol>
<p>To read more, see <a href="https://github.com/CompPhysics/ComputationalPhysics2/blob/gh-pages/doc/pub/notebook2/ipynb/notebook2.ipynb" target="_blank">Lectures on Boltzmann machines in Physics</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="autoencoders-overarching-view">Autoencoders: Overarching view </h2>
<p>Autoencoders are artificial neural networks capable of learning
efficient representations of the input data (these representations are called codings) without
any supervision (i.e., the training set is unlabeled). These codings
typically have a much lower dimensionality than the input data, making
autoencoders useful for dimensionality reduction.
</p>
<p>More importantly, autoencoders act as powerful feature detectors, and
they can be used for unsupervised pretraining of deep neural networks.
</p>
<p>Lastly, they are capable of randomly generating new data that looks
very similar to the training data; this is called a generative
model. For example, you could train an autoencoder on pictures of
faces, and it would then be able to generate new faces. Surprisingly,
autoencoders work by simply learning to copy their inputs to their
outputs. This may sound like a trivial task, but we will see that
constraining the network in various ways can make it rather
difficult. For example, you can limit the size of the internal
representation, or you can add noise to the inputs and train the
network to recover the original inputs. These constraints prevent the
autoencoder from trivially copying the inputs directly to the outputs,
which forces it to learn efficient ways of representing the data. In
short, the codings are byproducts of the autoencoder&#8217;s attempt to
learn the identity function under some constraints.
</p>
<a href="https://www.coursera.org/lecture/building-deep-learning-models-with-tensorflow/autoencoders-1U4L3" target="_blank">Video on autoencoders</a>
<p>See also A. Geron's textbook, chapter 15.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="bayesian-machine-learning">Bayesian Machine Learning </h2>
<p>This is an important topic if we aim at extracting a probability
distribution. This gives us also a confidence interval and error
estimates.
</p>
<p>Bayesian machine learning allows us to encode our prior beliefs about
what those models should look like, independent of what the data tells
us. This is especially useful when we don&#8217;t have a ton of data to
confidently learn our model.
</p>
<a href="https://www.youtube.com/watch?v=E1qhGw8QxqY&ab_channel=AndrewGordonWilson" target="_blank">Video on Bayesian deep learning</a>
<p>See also the <a href="https://github.com/CompPhysics/MachineLearning/blob/master/doc/Articles/lec03.pdf" target="_blank">slides here</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="reinforcement-learning">Reinforcement Learning </h2>
<p>Reinforcement Learning (RL) is one of the most exciting fields of
Machine Learning today, and also one of the oldest. It has been around
since the 1950s, producing many interesting applications over the
years.
</p>
<p>It studies
how agents take actions based on trial and error, so as to maximize
some notion of cumulative reward in a dynamic system or
environment. Due to its generality, the problem has also been studied
in many other disciplines, such as game theory, control theory,
operations research, information theory, multi-agent systems, swarm
intelligence, statistics, and genetic algorithms.
</p>
<p>In March 2016, AlphaGo, a computer program that plays the board game
Go, beat Lee Sedol in a five-game match. This was the first time a
computer Go program had beaten a 9-dan (highest rank) professional
without handicaps. AlphaGo is based on deep convolutional neural
networks and reinforcement learning. AlphaGo&#8217;s victory was a major
milestone in artificial intelligence and it has also made
reinforcement learning a hot research area in the field of machine
learning.
</p>
<p><a href="https://www.youtube.com/watch?v=FgzM3zpZ55o&ab_channel=stanfordonline" target="_blank">Lecture on Reinforcement Learning</a>.</p>
<p>See also A. Geron's textbook, chapter 16.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="transfer-learning">Transfer learning </h2>
<p>The goal of transfer learning is to transfer the model or knowledge
obtained from a source task to the target task, in order to resolve
the issues of insufficient training data in the target task. The
rationality of doing so lies in that usually the source and target
tasks have inter-correlations, and therefore either the features,
samples, or models in the source task might provide useful information
for us to better solve the target task. Transfer learning is a hot
research topic in recent years, with many problems still waiting to be studied.
</p>
<p><a href="https://www.ias.edu/video/machinelearning/2020/0331-SamoryKpotufe" target="_blank">Lecture on transfer learning</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="adversarial-learning">Adversarial learning </h2>
<p>The conventional deep generative model has a potential problem: the
model tends to generate extreme instances to maximize the
probabilistic likelihood, which will hurt its performance. Adversarial
learning utilizes the adversarial behaviors (e.g., generating
adversarial instances or training an adversarial model) to enhance the
robustness of the model and improve the quality of the generated
data. In recent years, one of the most promising unsupervised learning
technologies, generative adversarial networks (GAN), has already been
successfully applied to image, speech, and text.
</p>
<p><a href="https://www.youtube.com/watch?v=CIfsB_EYsVI&ab_channel=StanfordUniversitySchoolofEngineering" target="_blank">Lecture on adversial learning</a>.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="dual-learning">Dual learning </h2>
<p>Dual learning is a new learning paradigm, the basic idea of which is
to use the primal-dual structure between machine learning tasks to
obtain effective feedback/regularization, and guide and strengthen the
learning process, thus reducing the requirement of large-scale labeled
data for deep learning. The idea of dual learning has been applied to
many problems in machine learning, including machine translation,
image style conversion, question answering and generation, image
classification and generation, text classification and generation,
image-to-text, and text-to-image.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="distributed-machine-learning">Distributed machine learning </h2>
<p>Distributed computation will speed up machine learning algorithms,
significantly improve their efficiency, and thus enlarge their
application. When distributed meets machine learning, more than just
implementing the machine learning algorithms in parallel is required.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="meta-learning">Meta learning </h2>
<p>Meta learning is an emerging research direction in machine
learning. Roughly speaking, meta learning concerns learning how to
learn, and focuses on the understanding and adaptation of the learning
itself, instead of just completing a specific learning task. That is,
a meta learner needs to be able to evaluate its own learning methods
and adjust its own learning methods according to specific learning
tasks.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-challenges-facing-machine-learning">The Challenges Facing Machine Learning </h2>
<p>While there has been much progress in machine learning, there are also challenges.</p>
<p>For example, the mainstream machine learning technologies are
black-box approaches, making us concerned about their potential
risks. To tackle this challenge, we may want to make machine learning
more explainable and controllable. As another example, the
computational complexity of machine learning algorithms is usually
very high and we may want to invent lightweight algorithms or
implementations. Furthermore, in many domains such as physics,
chemistry, biology, and social sciences, people usually seek elegantly
simple equations (e.g., the Schr&#246;dinger equation) to uncover the
underlying laws behind various phenomena. In the field of machine
learning, can we reveal simple laws instead of designing more complex
models for data fitting? Although there are many challenges, we are
still very optimistic about the future of machine learning. As we look
forward to the future, here are what we think the research hotspots in
the next ten years will be.
</p>
<p>See the article on <a href="https://www.frontiersin.org/articles/10.3389/frai.2020.00025/full" target="_blank">Discovery of Physics From Data: Universal Laws and Discrepancies</a></p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="explainable-machine-learning">Explainable machine learning </h2>
<p>Machine learning, especially deep learning, evolves rapidly. The
ability gap between machine and human on many complex cognitive tasks
becomes narrower and narrower. However, we are still in the very early
stage in terms of explaining why those effective models work and how
they work.
</p>
<p><b>What is missing: the gap between correlation and causation</b>. Standard Machine Learning is based on what e have called a frequentist approach. </p>
<p>Most
machine learning techniques, especially the statistical ones, depend
highly on correlations in data sets to make predictions and analyses. In
contrast, rational humans tend to reply on clear and trustworthy
causality relations obtained via logical reasoning on real and clear
facts. It is one of the core goals of explainable machine learning to
transition from solving problems by data correlation to solving
problems by logical reasoning.
</p>
<b>Bayesian Machine Learning is one of the exciting research directions in this field</b>.
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="scientific-machine-learning">Scientific Machine Learning </h2>
<p>An important and emerging field is what has been dubbed as scientific ML, see the article by Deiana et al <a href="https://arxiv.org/abs/2110.13041" target="_blank">Applications and Techniques for Fast Machine Learning in Science, arXiv:2110.13041</a></p>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>The authors discuss applications and techniques for fast machine
learning (ML) in science &ndash; the concept of integrating power ML
methods into the real-time experimental data processing loop to
accelerate scientific discovery. The report covers three main areas
</p>
<ol>
<li> applications for fast ML across a number of scientific domains;</li>
<li> techniques for training and implementing performant and resource-efficient ML algorithms;</li>
<li> and computing architectures, platforms, and technologies for deploying these algorithms.</li>
</ol>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="quantum-machine-learning">Quantum machine learning </h2>
<p>Quantum machine learning is an emerging interdisciplinary research
area at the intersection of quantum computing and machine learning.
</p>
<p>Quantum computers use effects such as quantum coherence and quantum
entanglement to process information, which is fundamentally different
from classical computers. Quantum algorithms have surpassed the best
classical algorithms in several problems (e.g., searching for an
unsorted database, inverting a sparse matrix), which we call quantum
acceleration.
</p>
<p>When quantum computing meets machine learning, it can be a mutually
beneficial and reinforcing process, as it allows us to take advantage
of quantum computing to improve the performance of classical machine
learning algorithms. In addition, we can also use the machine learning
algorithms (on classic computers) to analyze and improve quantum
computing systems.
</p>
<p><a href="https://www.youtube.com/watch?v=Xh9pUu3-WxM&ab_channel=InstituteforPure%26AppliedMathematics%28IPAM%29" target="_blank">Lecture on Quantum ML</a>.</p>
<p><a href="https://physics.aps.org/articles/v13/179?utm_campaign=weekly&utm_medium=email&utm_source=emailalert" target="_blank">Read interview with Maria Schuld on her work on Quantum Machine Learning</a>. See also <a href="https://www.springer.com/gp/book/9783319964232" target="_blank">her recent textbook</a>. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="quantum-machine-learning-algorithms-based-on-linear-algebra">Quantum machine learning algorithms based on linear algebra </h2>
<p>Many quantum machine learning algorithms are based on variants of
quantum algorithms for solving linear equations, which can efficiently
solve N-variable linear equations with complexity of O(log2 N) under
certain conditions. The quantum matrix inversion algorithm can
accelerate many machine learning methods, such as least square linear
regression, least square version of support vector machine, Gaussian
process, and more. The training of these algorithms can be simplified
to solve linear equations. The key bottleneck of this type of quantum
machine learning algorithms is data input&#8212;that is, how to initialize
the quantum system with the entire data set. Although efficient
data-input algorithms exist for certain situations, how to efficiently
input data into a quantum system is as yet unknown for most cases.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="quantum-reinforcement-learning">Quantum reinforcement learning </h2>
<p>In quantum reinforcement learning, a quantum agent interacts with the
classical environment to obtain rewards from the environment, so as to
adjust and improve its behavioral strategies. In some cases, it
achieves quantum acceleration by the quantum processing capabilities
of the agent or the possibility of exploring the environment through
quantum superposition. Such algorithms have been proposed in
superconducting circuits and systems of trapped ions.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="quantum-deep-learning">Quantum deep learning </h2>
<p>Dedicated quantum information processors, such as quantum annealers
and programmable photonic circuits, are well suited for building deep
quantum networks. The simplest deep quantum network is the Boltzmann
machine. The classical Boltzmann machine consists of bits with tunable
interactions and is trained by adjusting the interaction of these bits
so that the distribution of its expression conforms to the statistics
of the data. To quantize the Boltzmann machine, the neural network can
simply be represented as a set of interacting quantum spins that
correspond to an adjustable Ising model. Then, by initializing the
input neurons in the Boltzmann machine to a fixed state and allowing
the system to heat up, we can read out the output qubits to get the
result.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="social-machine-learning">Social machine learning </h2>
<p>Machine learning aims to imitate how humans
learn. While we have developed successful machine learning algorithms,
until now we have ignored one important fact: humans are social. Each
of us is one part of the total society and it is difficult for us to
live, learn, and improve ourselves, alone and isolated. Therefore, we
should design machines with social properties. Can we let machines
evolve by imitating human society so as to achieve more effective,
intelligent, interpretable &#8220;social machine learning&#8221;?
</p>
<p>And much more.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-last-words">The last words? </h2>
<p>Early computer scientist Alan Kay said, <b>The best way to predict the
future is to create it</b>. Therefore, all machine learning
practitioners, whether scholars or engineers, professors or students,
need to work together to advance these important research
topics. Together, we will not just predict the future, but create it.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="ai-ml-and-some-statements-you-may-have-heard-and-what-do-they-mean">AI/ML and some statements you may have heard (and what do they mean?) </h2>
<ol>
<li> Fei-Fei Li on ImageNet: <b>map out the entire world of objects</b> (<a href="https://cacm.acm.org/news/219702-the-data-that-transformed-ai-research-and-possibly-the-world/fulltext" target="_blank">The data that transformed AI research</a>)</li>
<li> Russell and Norvig in their popular textbook: <b>relevant to any intellectual task; it is truly a universal field</b> (<a href="http://aima.cs.berkeley.edu/" target="_blank">Artificial Intelligence, A modern approach</a>)</li>
<li> Woody Bledsoe puts it more bluntly: <b>in the long run, AI is the only science</b> (quoted in Pamilla McCorduck, <a href="https://www.pamelamccorduck.com/machines-who-think" target="_blank">Machines who think</a>)</li>
</ol>
<p>If you wish to have a critical read on AI/ML from a societal point of view, see <a href="https://www.katecrawford.net/" target="_blank">Kate Crawford's recent text Atlas of AI</a></p>
<b>Here: with AI/ML we intend a collection of machine learning methods with an emphasis on statistical learning and data analysis</b>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="best-wishes-to-you-all-and-thanks-so-much-for-your-heroic-efforts-this-semester">Best wishes to you all and thanks so much for your heroic efforts this semester </h2>
<br/><br/>
<center>
<p><img src="figures/Nebbdyr2.png" width="500" align="bottom"></p>
</center>
<br/><br/>
<!-- ------------------- 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>