Files
FYS-STK4155/doc/LectureNotes/_build/html/chapter8.html
T
Morten Hjorth-Jensen 676a3d78a0 update book
2024-09-02 21:13:52 +02:00

1653 lines
113 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>11. Basic ideas of the Principal Component Analysis (PCA) &#8212; Applied Data Analysis and Machine Learning</title>
<link href="_static/css/theme.css" rel="stylesheet">
<link href="_static/css/index.ff1ffe594081f20da1ef19478df9384b.css" rel="stylesheet">
<link rel="stylesheet"
href="_static/vendor/fontawesome/5.13.0/css/all.min.css">
<link rel="preload" as="font" type="font/woff2" crossorigin
href="_static/vendor/fontawesome/5.13.0/webfonts/fa-solid-900.woff2">
<link rel="preload" as="font" type="font/woff2" crossorigin
href="_static/vendor/fontawesome/5.13.0/webfonts/fa-brands-400.woff2">
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/sphinx-book-theme.css?digest=c3fdc42140077d1ad13ad2f1588a4309" />
<link rel="stylesheet" type="text/css" href="_static/togglebutton.css" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="_static/mystnb.css" />
<link rel="stylesheet" type="text/css" href="_static/sphinx-thebe.css" />
<link rel="stylesheet" type="text/css" href="_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css" />
<link rel="stylesheet" type="text/css" href="_static/panels-variables.06eb56fa6e07937060861dad626602ad.css" />
<link rel="preload" as="script" href="_static/js/index.be7d3bbb2ef33a8344ce.js">
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/clipboard.min.js"></script>
<script src="_static/copybutton.js"></script>
<script>let toggleHintShow = 'Click to show';</script>
<script>let toggleHintHide = 'Click to hide';</script>
<script>let toggleOpenOnPrint = 'true';</script>
<script src="_static/togglebutton.js"></script>
<script>var togglebuttonSelector = '.toggle, .admonition.dropdown, .tag_hide_input div.cell_input, .tag_hide-input div.cell_input, .tag_hide_output div.cell_output, .tag_hide-output div.cell_output, .tag_hide_cell.cell, .tag_hide-cell.cell';</script>
<script src="_static/sphinx-book-theme.d59cb220de22ca1c485ebbdc042f0030.js"></script>
<script>const THEBE_JS_URL = "https://unpkg.com/thebe@0.8.2/lib/index.js"
const thebe_selector = ".thebe,.cell"
const thebe_selector_input = "pre"
const thebe_selector_output = ".output, .cell_output"
</script>
<script async="async" src="_static/sphinx-thebe.js"></script>
<script>window.MathJax = {"options": {"processHtmlClass": "tex2jax_process|mathjax_process|math|output_area"}}</script>
<script defer="defer" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="12. Clustering and Unsupervised Learning" href="clustering.html" />
<link rel="prev" title="10. Ensemble Methods: From a Single Tree to Many Trees and Extreme Boosting, Meet the Jungle of Methods" href="chapter7.html" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="docsearch:language" content="None">
<!-- Google Analytics -->
</head>
<body data-spy="scroll" data-target="#bd-toc-nav" data-offset="80">
<div class="container-fluid" id="banner"></div>
<div class="container-xl">
<div class="row">
<div class="col-12 col-md-3 bd-sidebar site-navigation show" id="site-navigation">
<div class="navbar-brand-box">
<a class="navbar-brand text-wrap" href="index.html">
<!-- `logo` is deprecated in Sphinx 4.0, so remove this when we stop supporting 3 -->
<img src="_static/logo.png" class="logo" alt="logo">
<h1 class="site-logo" id="site-title">Applied Data Analysis and Machine Learning</h1>
</a>
</div><form class="bd-search d-flex align-items-center" action="search.html" method="get">
<i class="icon fas fa-search"></i>
<input type="search" class="form-control" name="q" id="search-input" placeholder="Search this book..." aria-label="Search this book..." autocomplete="off" >
</form><nav class="bd-links" id="bd-docs-nav" aria-label="Main">
<div class="bd-toc-item active">
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="intro.html">
Applied Data Analysis and Machine Learning
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
About the course
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="schedule.html">
Teaching schedule with links to material
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="teachers.html">
Teachers and Grading
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="textbooks.html">
Textbooks
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
Review of Statistics with Resampling Techniques and Linear Algebra
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="statistics.html">
1. Elements of Probability Theory and Statistical Data Analysis
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="linalg.html">
2. Linear Algebra, Handling of Arrays and more Python Features
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
From Regression to Support Vector Machines
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="chapter1.html">
3. Linear Regression
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter2.html">
4. Ridge and Lasso Regression
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter3.html">
5. Resampling Methods
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter4.html">
6. Logistic Regression
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapteroptimization.html">
7. Optimization, the central part of any Machine Learning algortithm
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter5.html">
8. Support Vector Machines, overarching aims
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
Decision Trees, Ensemble Methods and Boosting
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="chapter6.html">
9. Decision trees, overarching aims
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter7.html">
10. Ensemble Methods: From a Single Tree to Many Trees and Extreme Boosting, Meet the Jungle of Methods
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
Dimensionality Reduction
</span>
</p>
<ul class="current nav bd-sidenav">
<li class="toctree-l1 current active">
<a class="current reference internal" href="#">
11. Basic ideas of the Principal Component Analysis (PCA)
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="clustering.html">
12. Clustering and Unsupervised Learning
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
Deep Learning Methods
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="chapter9.html">
13. Neural networks
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter10.html">
14. Building a Feed Forward Neural Network
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter11.html">
15. Solving Differential Equations with Deep Learning
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter12.html">
16. Convolutional Neural Networks
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="chapter13.html">
17. Recurrent neural networks: Overarching view
</a>
</li>
</ul>
<p aria-level="2" class="caption" role="heading">
<span class="caption-text">
Weekly material, notes and exercises
</span>
</p>
<ul class="nav bd-sidenav">
<li class="toctree-l1">
<a class="reference internal" href="exercisesweek34.html">
Exercises week 34
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="week34.html">
Week 34: Introduction to the course, Logistics and Practicalities
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="exercisesweek35.html">
Exercises week 35
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="week35.html">
Week 35: From Ordinary Linear Regression to Ridge and Lasso Regression
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="exercisesweek36.html">
Exercises week 36
</a>
</li>
<li class="toctree-l1">
<a class="reference internal" href="week36.html">
Week 36: Linear Rgeression and Statistical interpretations
</a>
</li>
</ul>
</div>
</nav> <!-- To handle the deprecated key -->
<div class="navbar_extra_footer">
Powered by <a href="https://jupyterbook.org">Jupyter Book</a>
</div>
</div>
<main class="col py-md-3 pl-md-4 bd-content overflow-auto" role="main">
<div class="topbar container-xl fixed-top">
<div class="topbar-contents row">
<div class="col-12 col-md-3 bd-topbar-whitespace site-navigation show"></div>
<div class="col pl-md-4 topbar-main">
<button id="navbar-toggler" class="navbar-toggler ml-0" type="button" data-toggle="collapse"
data-toggle="tooltip" data-placement="bottom" data-target=".site-navigation" aria-controls="navbar-menu"
aria-expanded="true" aria-label="Toggle navigation" aria-controls="site-navigation"
title="Toggle navigation" data-toggle="tooltip" data-placement="left">
<i class="fas fa-bars"></i>
<i class="fas fa-arrow-left"></i>
<i class="fas fa-arrow-up"></i>
</button>
<div class="dropdown-buttons-trigger">
<button id="dropdown-buttons-trigger" class="btn btn-secondary topbarbtn" aria-label="Download this page"><i
class="fas fa-download"></i></button>
<div class="dropdown-buttons">
<!-- ipynb file if we had a myst markdown file -->
<!-- Download raw file -->
<a class="dropdown-buttons" href="_sources/chapter8.ipynb"><button type="button"
class="btn btn-secondary topbarbtn" title="Download source file" data-toggle="tooltip"
data-placement="left">.ipynb</button></a>
<!-- Download PDF via print -->
<button type="button" id="download-print" class="btn btn-secondary topbarbtn" title="Print to PDF"
onclick="printPdf(this)" data-toggle="tooltip" data-placement="left">.pdf</button>
</div>
</div>
<!-- Source interaction buttons -->
<!-- Full screen (wrap in <a> to have style consistency -->
<a class="full-screen-button"><button type="button" class="btn btn-secondary topbarbtn" data-toggle="tooltip"
data-placement="bottom" onclick="toggleFullScreen()" aria-label="Fullscreen mode"
title="Fullscreen mode"><i
class="fas fa-expand"></i></button></a>
<!-- Launch buttons -->
</div>
<!-- Table of contents -->
<div class="d-none d-md-block col-md-2 bd-toc show noprint">
<div class="tocsection onthispage pt-5 pb-3">
<i class="fas fa-list"></i> Contents
</div>
<nav id="bd-toc-nav" aria-label="Page">
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#introducing-the-covariance-and-correlation-functions">
11.1. Introducing the Covariance and Correlation functions
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#correlation-matrix">
11.2. Correlation Matrix
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#towards-the-pca-theorem">
11.3. Towards the PCA theorem
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#the-algorithm-before-theorem">
11.3.1. The Algorithm before theorem
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#writing-our-own-pca-code">
11.3.2. Writing our own PCA code
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#diagonalize-the-sample-covariance-matrix-to-obtain-the-principal-components">
11.3.3. Diagonalize the sample covariance matrix to obtain the principal components
</a>
</li>
</ul>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#classical-pca-theorem">
11.4. Classical PCA Theorem
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#geometric-interpretation-and-link-with-singular-value-decomposition">
11.5. Geometric Interpretation and link with Singular Value Decomposition
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#pca-and-scikit-learn">
11.6. PCA and scikit-learn
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#back-to-the-cancer-data">
11.7. Back to the Cancer Data
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#incremental-pca">
11.7.1. Incremental PCA
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#randomized-pca">
11.7.2. Randomized PCA
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#kernel-pca">
11.7.3. Kernel PCA
</a>
</li>
</ul>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#other-techniques">
11.8. Other techniques
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div id="main-content" class="row">
<div class="col-12 col-md-9 pl-md-3 pr-md-0">
<!-- Table of contents that is only displayed when printing the page -->
<div id="jb-print-docs-body" class="onlyprint">
<h1>Basic ideas of the Principal Component Analysis (PCA)</h1>
<!-- Table of contents -->
<div id="print-main-content">
<div id="jb-print-toc">
<div>
<h2> Contents </h2>
</div>
<nav aria-label="Page">
<ul class="visible nav section-nav flex-column">
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#introducing-the-covariance-and-correlation-functions">
11.1. Introducing the Covariance and Correlation functions
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#correlation-matrix">
11.2. Correlation Matrix
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#towards-the-pca-theorem">
11.3. Towards the PCA theorem
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#the-algorithm-before-theorem">
11.3.1. The Algorithm before theorem
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#writing-our-own-pca-code">
11.3.2. Writing our own PCA code
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#diagonalize-the-sample-covariance-matrix-to-obtain-the-principal-components">
11.3.3. Diagonalize the sample covariance matrix to obtain the principal components
</a>
</li>
</ul>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#classical-pca-theorem">
11.4. Classical PCA Theorem
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#geometric-interpretation-and-link-with-singular-value-decomposition">
11.5. Geometric Interpretation and link with Singular Value Decomposition
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#pca-and-scikit-learn">
11.6. PCA and scikit-learn
</a>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#back-to-the-cancer-data">
11.7. Back to the Cancer Data
</a>
<ul class="nav section-nav flex-column">
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#incremental-pca">
11.7.1. Incremental PCA
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#randomized-pca">
11.7.2. Randomized PCA
</a>
</li>
<li class="toc-h3 nav-item toc-entry">
<a class="reference internal nav-link" href="#kernel-pca">
11.7.3. Kernel PCA
</a>
</li>
</ul>
</li>
<li class="toc-h2 nav-item toc-entry">
<a class="reference internal nav-link" href="#other-techniques">
11.8. Other techniques
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div>
<div class="tex2jax_ignore mathjax_ignore section" id="basic-ideas-of-the-principal-component-analysis-pca">
<h1><span class="section-number">11. </span>Basic ideas of the Principal Component Analysis (PCA)<a class="headerlink" href="#basic-ideas-of-the-principal-component-analysis-pca" title="Permalink to this headline"></a></h1>
<p>The principal component analysis deals with the problem of fitting a
low-dimensional affine subspace <span class="math notranslate nohighlight">\(S\)</span> of dimension <span class="math notranslate nohighlight">\(d\)</span> much smaller than
the total dimension <span class="math notranslate nohighlight">\(D\)</span> 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 <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span> (see below for its definition)</p>
<ul class="simple">
<li><p>Each data point is determined by <span class="math notranslate nohighlight">\(p\)</span> extrinsic (measurement) variables</p></li>
<li><p>We may want to ask the following question: Are there fewer intrinsic variables (say <span class="math notranslate nohighlight">\(d &lt;&lt; p\)</span>) that still approximately describe the data?</p></li>
<li><p>If so, these intrinsic variables may tell us something important and finding these intrinsic variables is what dimension reduction methods do.</p></li>
</ul>
<p>A good read is for example <a class="reference external" href="https://www.springer.com/gp/book/9780387878102">Vidal, Ma and Sastry</a>.</p>
<div class="section" id="introducing-the-covariance-and-correlation-functions">
<h2><span class="section-number">11.1. </span>Introducing the Covariance and Correlation functions<a class="headerlink" href="#introducing-the-covariance-and-correlation-functions" title="Permalink to this headline"></a></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
<span class="math notranslate nohighlight">\(\hat{x}\)</span> and <span class="math notranslate nohighlight">\(\hat{y}\)</span> with <span class="math notranslate nohighlight">\(n\)</span> elements each. The covariance matrix <span class="math notranslate nohighlight">\(\boldsymbol{C}\)</span> is defined as</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{C}[\boldsymbol{x},\boldsymbol{y}] = \begin{bmatrix} \mathrm{cov}[\boldsymbol{x},\boldsymbol{x}] &amp; \mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] \\
\mathrm{cov}[\boldsymbol{y},\boldsymbol{x}] &amp; \mathrm{cov}[\boldsymbol{y},\boldsymbol{y}] \\
\end{bmatrix},
\end{split}\]</div>
<p>where for example</p>
<div class="math notranslate nohighlight">
\[
\mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] =\frac{1}{n} \sum_{i=0}^{n-1}(x_i- \overline{x})(y_i- \overline{y}).
\]</div>
<p>With this definition and recalling that the variance is defined as</p>
<div class="math notranslate nohighlight">
\[
\mathrm{var}[\boldsymbol{x}]=\frac{1}{n} \sum_{i=0}^{n-1}(x_i- \overline{x})^2,
\]</div>
<p>we can rewrite the covariance matrix as</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{C}[\boldsymbol{x},\boldsymbol{y}] = \begin{bmatrix} \mathrm{var}[\boldsymbol{x}] &amp; \mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] \\
\mathrm{cov}[\boldsymbol{x},\boldsymbol{y}] &amp; \mathrm{var}[\boldsymbol{y}] \\
\end{bmatrix}.
\end{split}\]</div>
<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>
<div class="math notranslate nohighlight">
\[
\mathrm{corr}[\boldsymbol{x},\boldsymbol{y}]=\frac{\mathrm{cov}[\boldsymbol{x},\boldsymbol{y}]}{\sqrt{\mathrm{var}[\boldsymbol{x}] \mathrm{var}[\boldsymbol{y}]}}.
\]</div>
<p>The correlation function is then given by values <span class="math notranslate nohighlight">\(\mathrm{corr}[\boldsymbol{x},\boldsymbol{y}]
\in [-1,1]\)</span>. This avoids eventual problems with too large values. We
can then define the correlation matrix for the two vectors <span class="math notranslate nohighlight">\(\boldsymbol{x}\)</span>
and <span class="math notranslate nohighlight">\(\boldsymbol{y}\)</span> as</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{K}[\boldsymbol{x},\boldsymbol{y}] = \begin{bmatrix} 1 &amp; \mathrm{corr}[\boldsymbol{x},\boldsymbol{y}] \\
\mathrm{corr}[\boldsymbol{y},\boldsymbol{x}] &amp; 1 \\
\end{bmatrix},
\end{split}\]</div>
<p>In the above example this is the function we constructed using <strong>pandas</strong>.</p>
<p>In our derivation of the various regression algorithms like <strong>Ordinary Least Squares</strong> or <strong>Ridge regression</strong>
we defined the design/feature matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span> as</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{X}=\begin{bmatrix}
x_{0,0} &amp; x_{0,1} &amp; x_{0,2}&amp; \dots &amp; \dots x_{0,p-1}\\
x_{1,0} &amp; x_{1,1} &amp; x_{1,2}&amp; \dots &amp; \dots x_{1,p-1}\\
x_{2,0} &amp; x_{2,1} &amp; x_{2,2}&amp; \dots &amp; \dots x_{2,p-1}\\
\dots &amp; \dots &amp; \dots &amp; \dots \dots &amp; \dots \\
x_{n-2,0} &amp; x_{n-2,1} &amp; x_{n-2,2}&amp; \dots &amp; \dots x_{n-2,p-1}\\
x_{n-1,0} &amp; x_{n-1,1} &amp; x_{n-1,2}&amp; \dots &amp; \dots x_{n-1,p-1}\\
\end{bmatrix},
\end{split}\]</div>
<p>with <span class="math notranslate nohighlight">\(\boldsymbol{X}\in {\mathbb{R}}^{n\times p}\)</span>, with the predictors/features <span class="math notranslate nohighlight">\(p\)</span> refering to the column numbers and the
entries <span class="math notranslate nohighlight">\(n\)</span> being the row elements.
We can rewrite the design/feature matrix in terms of its column vectors as</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{X}=\begin{bmatrix} \boldsymbol{x}_0 &amp; \boldsymbol{x}_1 &amp; \boldsymbol{x}_2 &amp; \dots &amp; \dots &amp; \boldsymbol{x}_{p-1}\end{bmatrix},
\]</div>
<p>with a given vector</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{x}_i^T = \begin{bmatrix}x_{0,i} &amp; x_{1,i} &amp; x_{2,i}&amp; \dots &amp; \dots x_{n-1,i}\end{bmatrix}.
\]</div>
<p>With these definitions, we can now rewrite our <span class="math notranslate nohighlight">\(2\times 2\)</span>
correaltion/covariance matrix in terms of a moe general design/feature
matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\in {\mathbb{R}}^{n\times p}\)</span>. This leads to a <span class="math notranslate nohighlight">\(p\times p\)</span>
covariance matrix for the vectors <span class="math notranslate nohighlight">\(\boldsymbol{x}_i\)</span> with <span class="math notranslate nohighlight">\(i=0,1,\dots,p-1\)</span></p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{C}[\boldsymbol{x}] = \begin{bmatrix}
\mathrm{var}[\boldsymbol{x}_0] &amp; \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_1] &amp; \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_2] &amp; \dots &amp; \dots &amp; \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_{p-1}]\\
\mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_0] &amp; \mathrm{var}[\boldsymbol{x}_1] &amp; \mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_2] &amp; \dots &amp; \dots &amp; \mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_{p-1}]\\
\mathrm{cov}[\boldsymbol{x}_2,\boldsymbol{x}_0] &amp; \mathrm{cov}[\boldsymbol{x}_2,\boldsymbol{x}_1] &amp; \mathrm{var}[\boldsymbol{x}_2] &amp; \dots &amp; \dots &amp; \mathrm{cov}[\boldsymbol{x}_2,\boldsymbol{x}_{p-1}]\\
\dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots \\
\dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots \\
\mathrm{cov}[\boldsymbol{x}_{p-1},\boldsymbol{x}_0] &amp; \mathrm{cov}[\boldsymbol{x}_{p-1},\boldsymbol{x}_1] &amp; \mathrm{cov}[\boldsymbol{x}_{p-1},\boldsymbol{x}_{2}] &amp; \dots &amp; \dots &amp; \mathrm{var}[\boldsymbol{x}_{p-1}]\\
\end{bmatrix},
\end{split}\]</div>
<p>and the correlation matrix</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{K}[\boldsymbol{x}] = \begin{bmatrix}
1 &amp; \mathrm{corr}[\boldsymbol{x}_0,\boldsymbol{x}_1] &amp; \mathrm{corr}[\boldsymbol{x}_0,\boldsymbol{x}_2] &amp; \dots &amp; \dots &amp; \mathrm{corr}[\boldsymbol{x}_0,\boldsymbol{x}_{p-1}]\\
\mathrm{corr}[\boldsymbol{x}_1,\boldsymbol{x}_0] &amp; 1 &amp; \mathrm{corr}[\boldsymbol{x}_1,\boldsymbol{x}_2] &amp; \dots &amp; \dots &amp; \mathrm{corr}[\boldsymbol{x}_1,\boldsymbol{x}_{p-1}]\\
\mathrm{corr}[\boldsymbol{x}_2,\boldsymbol{x}_0] &amp; \mathrm{corr}[\boldsymbol{x}_2,\boldsymbol{x}_1] &amp; 1 &amp; \dots &amp; \dots &amp; \mathrm{corr}[\boldsymbol{x}_2,\boldsymbol{x}_{p-1}]\\
\dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots \\
\dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots &amp; \dots \\
\mathrm{corr}[\boldsymbol{x}_{p-1},\boldsymbol{x}_0] &amp; \mathrm{corr}[\boldsymbol{x}_{p-1},\boldsymbol{x}_1] &amp; \mathrm{corr}[\boldsymbol{x}_{p-1},\boldsymbol{x}_{2}] &amp; \dots &amp; \dots &amp; 1\\
\end{bmatrix},
\end{split}\]</div>
<p>The Numpy function <strong>np.cov</strong> calculates the covariance elements using
the factor <span class="math notranslate nohighlight">\(1/(n-1)\)</span> instead of <span class="math notranslate nohighlight">\(1/n\)</span> since it assumes we do not have
the exact mean values. The following simple function uses the
<strong>np.vstack</strong> function which takes each vector of dimension <span class="math notranslate nohighlight">\(1\times n\)</span>
and produces a <span class="math notranslate nohighlight">\(2\times n\)</span> matrix <span class="math notranslate nohighlight">\(\boldsymbol{W}\)</span></p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{W} = \begin{bmatrix} x_0 &amp; y_0 \\
x_1 &amp; y_1 \\
x_2 &amp; y_2\\
\dots &amp; \dots \\
x_{n-2} &amp; y_{n-2}\\
x_{n-1} &amp; y_{n-1} &amp;
\end{bmatrix},
\end{split}\]</div>
<p>which in turn is converted into into the <span class="math notranslate nohighlight">\(2\times 2\)</span> covariance matrix
<span class="math notranslate nohighlight">\(\boldsymbol{C}\)</span> via the Numpy function <strong>np.cov()</strong>. We note that we can also calculate
the mean value of each set of samples <span class="math notranslate nohighlight">\(\boldsymbol{x}\)</span> etc using the Numpy
function <strong>np.mean(x)</strong>. We can also extract the eigenvalues of the
covariance matrix through the <strong>np.linalg.eig()</strong> function.</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Importing various packages</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">4</span><span class="o">+</span><span class="mi">3</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">y</span><span class="p">))</span>
<span class="n">W</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">))</span>
<span class="n">C</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cov</span><span class="p">(</span><span class="n">W</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">C</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>-0.046842629321028326
3.909446359461397
[[0.76681867 2.32238906]
[2.32238906 8.10983159]]
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="correlation-matrix">
<h2><span class="section-number">11.2. </span>Correlation Matrix<a class="headerlink" href="#correlation-matrix" title="Permalink to this headline"></a></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 <span class="math notranslate nohighlight">\(2\times 2\)</span> correlation matrix (since we have only two vectors).</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">100</span>
<span class="c1"># define two vectors </span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">4</span><span class="o">+</span><span class="mi">3</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="c1">#scaling the x and y vectors </span>
<span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">y</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="n">variance_x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="nd">@x</span><span class="p">)</span><span class="o">/</span><span class="n">n</span>
<span class="n">variance_y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">y</span><span class="nd">@y</span><span class="p">)</span><span class="o">/</span><span class="n">n</span>
<span class="nb">print</span><span class="p">(</span><span class="n">variance_x</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">variance_y</span><span class="p">)</span>
<span class="n">cov_xy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="nd">@y</span><span class="p">)</span><span class="o">/</span><span class="n">n</span>
<span class="n">cov_xx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="nd">@x</span><span class="p">)</span><span class="o">/</span><span class="n">n</span>
<span class="n">cov_yy</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">y</span><span class="nd">@y</span><span class="p">)</span><span class="o">/</span><span class="n">n</span>
<span class="n">C</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span><span class="o">=</span> <span class="n">cov_xx</span><span class="o">/</span><span class="n">variance_x</span>
<span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span><span class="o">=</span> <span class="n">cov_yy</span><span class="o">/</span><span class="n">variance_y</span>
<span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span><span class="o">=</span> <span class="n">cov_xy</span><span class="o">/</span><span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">variance_y</span><span class="o">*</span><span class="n">variance_x</span><span class="p">)</span>
<span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span><span class="o">=</span> <span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">C</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>0.0798590438380667
1.270350130579073
[[1. 0.58734026]
[0.58734026 1. ]]
</pre></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 <strong>numpy</strong> can be made more compact if we use <strong>pandas</strong>.</p>
<p>We whow here how we can set up the correlation matrix using <strong>pandas</strong>, as done in this simple code</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">4</span><span class="o">+</span><span class="mi">3</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">y</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">vstack</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)))</span><span class="o">.</span><span class="n">T</span>
<span class="nb">print</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">Xpd</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">Xpd</span><span class="p">)</span>
<span class="n">correlation_matrix</span> <span class="o">=</span> <span class="n">Xpd</span><span class="o">.</span><span class="n">corr</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">correlation_matrix</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>[[-0.34565973 -1.4704785 ]
[-0.29669702 -0.75437273]
[ 1.05100602 2.13022421]
[ 0.40103689 3.11022072]
[ 0.01591047 -0.05087888]
[-0.89261577 -1.74947597]
[-0.21796226 -0.62901905]
[-0.5961905 -2.9242511 ]
[ 0.39428522 1.65208925]
[ 0.48688666 0.68594205]]
0 1
0 -0.345660 -1.470478
1 -0.296697 -0.754373
2 1.051006 2.130224
3 0.401037 3.110221
4 0.015910 -0.050879
5 -0.892616 -1.749476
6 -0.217962 -0.629019
7 -0.596190 -2.924251
8 0.394285 1.652089
9 0.486887 0.685942
0 1
0 1.00000 0.87078
1 0.87078 1.00000
</pre></div>
</div>
</div>
</div>
<p>We expand this model to the Franke function discussed above.</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Common imports</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="k">def</span> <span class="nf">FrankeFunction</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">):</span>
<span class="n">term1</span> <span class="o">=</span> <span class="mf">0.75</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="mf">0.25</span><span class="o">*</span><span class="p">(</span><span class="mi">9</span><span class="o">*</span><span class="n">x</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">-</span> <span class="mf">0.25</span><span class="o">*</span><span class="p">((</span><span class="mi">9</span><span class="o">*</span><span class="n">y</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">))</span>
<span class="n">term2</span> <span class="o">=</span> <span class="mf">0.75</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">((</span><span class="mi">9</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span><span class="o">/</span><span class="mf">49.0</span> <span class="o">-</span> <span class="mf">0.1</span><span class="o">*</span><span class="p">(</span><span class="mi">9</span><span class="o">*</span><span class="n">y</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span>
<span class="n">term3</span> <span class="o">=</span> <span class="mf">0.5</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="mi">9</span><span class="o">*</span><span class="n">x</span><span class="o">-</span><span class="mi">7</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="o">/</span><span class="mf">4.0</span> <span class="o">-</span> <span class="mf">0.25</span><span class="o">*</span><span class="p">((</span><span class="mi">9</span><span class="o">*</span><span class="n">y</span><span class="o">-</span><span class="mi">3</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">))</span>
<span class="n">term4</span> <span class="o">=</span> <span class="o">-</span><span class="mf">0.2</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="mi">9</span><span class="o">*</span><span class="n">x</span><span class="o">-</span><span class="mi">4</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span> <span class="o">-</span> <span class="p">(</span><span class="mi">9</span><span class="o">*</span><span class="n">y</span><span class="o">-</span><span class="mi">7</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span>
<span class="k">return</span> <span class="n">term1</span> <span class="o">+</span> <span class="n">term2</span> <span class="o">+</span> <span class="n">term3</span> <span class="o">+</span> <span class="n">term4</span>
<span class="k">def</span> <span class="nf">create_X</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">n</span> <span class="p">):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">ravel</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">ravel</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="n">N</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">l</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># Number of elements in beta</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">ones</span><span class="p">((</span><span class="n">N</span><span class="p">,</span><span class="n">l</span><span class="p">))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="n">q</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="n">i</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="n">X</span><span class="p">[:,</span><span class="n">q</span><span class="o">+</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="n">k</span><span class="p">))</span><span class="o">*</span><span class="p">(</span><span class="n">y</span><span class="o">**</span><span class="n">k</span><span class="p">)</span>
<span class="k">return</span> <span class="n">X</span>
<span class="c1"># Making meshgrid of datapoints and compute Franke&#39;s function</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">N</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">uniform</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">N</span><span class="p">))</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">uniform</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">N</span><span class="p">))</span>
<span class="n">z</span> <span class="o">=</span> <span class="n">FrankeFunction</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">create_X</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="p">)</span>
<span class="n">Xpd</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="c1"># subtract the mean values and set up the covariance matrix</span>
<span class="n">Xpd</span> <span class="o">=</span> <span class="n">Xpd</span> <span class="o">-</span> <span class="n">Xpd</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span>
<span class="n">covariance_matrix</span> <span class="o">=</span> <span class="n">Xpd</span><span class="o">.</span><span class="n">cov</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">covariance_matrix</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span> 0 1 2 3 4 5 6 7 \
0 0.0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
1 0.0 0.078785 0.081798 0.081422 0.083540 0.085693 0.075398 0.077082
2 0.0 0.081798 0.085346 0.084157 0.086550 0.088986 0.077522 0.079381
3 0.0 0.081422 0.084157 0.090290 0.092347 0.094426 0.087176 0.088908
4 0.0 0.083540 0.086550 0.092347 0.094577 0.096837 0.088893 0.090751
5 0.0 0.085693 0.088986 0.094426 0.096837 0.099287 0.090623 0.092613
6 0.0 0.075398 0.077522 0.087176 0.088893 0.090623 0.086538 0.088061
7 0.0 0.077082 0.079381 0.088908 0.090751 0.092613 0.088061 0.089682
8 0.0 0.078824 0.081308 0.090696 0.092672 0.094671 0.089629 0.091353
9 0.0 0.080630 0.083309 0.092544 0.094659 0.096803 0.091246 0.093078
10 0.0 0.068605 0.070202 0.081597 0.082978 0.084362 0.082661 0.083943
11 0.0 0.070006 0.071729 0.083096 0.084574 0.086059 0.084022 0.085383
12 0.0 0.071462 0.073318 0.084650 0.086230 0.087822 0.085431 0.086875
13 0.0 0.072976 0.074973 0.086263 0.087951 0.089654 0.086890 0.088422
14 0.0 0.074552 0.076697 0.087938 0.089739 0.091561 0.088402 0.090025
8 9 10 11 12 13 14
0 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
1 0.078824 0.080630 0.068605 0.070006 0.071462 0.072976 0.074552
2 0.081308 0.083309 0.070202 0.071729 0.073318 0.074973 0.076697
3 0.090696 0.092544 0.081597 0.083096 0.084650 0.086263 0.087938
4 0.092672 0.094659 0.082978 0.084574 0.086230 0.087951 0.089739
5 0.094671 0.096803 0.084362 0.086059 0.087822 0.089654 0.091561
6 0.089629 0.091246 0.082661 0.084022 0.085431 0.086890 0.088402
7 0.091353 0.093078 0.083943 0.085383 0.086875 0.088422 0.090025
8 0.093132 0.094970 0.085259 0.086782 0.088361 0.090000 0.091700
9 0.094970 0.096928 0.086611 0.088222 0.089892 0.091627 0.093429
10 0.085259 0.086611 0.080195 0.081374 0.082592 0.083851 0.085152
11 0.086782 0.088222 0.081374 0.082619 0.083906 0.085237 0.086615
12 0.088361 0.089892 0.082592 0.083906 0.085265 0.086673 0.088130
13 0.090000 0.091627 0.083851 0.085237 0.086673 0.088160 0.089702
14 0.091700 0.093429 0.085152 0.086615 0.088130 0.089702 0.091331
</pre></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 <span class="math notranslate nohighlight">\(n\)</span>). We would however not include the intercept
and wee can simply
drop these elements and construct a correlation
matrix without them.</p>
<p>We can rewrite the covariance matrix in a more compact form in terms of the design/feature matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span> as</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{C}[\boldsymbol{x}] = \frac{1}{n}\boldsymbol{X}^T\boldsymbol{X}= \mathbb{E}[\boldsymbol{X}^T\boldsymbol{X}].
\]</div>
<p>To see this let us simply look at a design matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\in {\mathbb{R}}^{2\times 2}\)</span></p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{X}=\begin{bmatrix}
x_{00} &amp; x_{01}\\
x_{10} &amp; x_{11}\\
\end{bmatrix}=\begin{bmatrix}
\boldsymbol{x}_{0} &amp; \boldsymbol{x}_{1}\\
\end{bmatrix}.
\end{split}\]</div>
<p>If we then compute the expectation value</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\mathbb{E}[\boldsymbol{X}^T\boldsymbol{X}] = \frac{1}{n}\boldsymbol{X}^T\boldsymbol{X}=\begin{bmatrix}
x_{00}^2+x_{01}^2 &amp; x_{00}x_{10}+x_{01}x_{11}\\
x_{10}x_{00}+x_{11}x_{01} &amp; x_{10}^2+x_{11}^2\\
\end{bmatrix},
\end{split}\]</div>
<p>which is just</p>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{C}[\boldsymbol{x}_0,\boldsymbol{x}_1] = \boldsymbol{C}[\boldsymbol{x}]=\begin{bmatrix} \mathrm{var}[\boldsymbol{x}_0] &amp; \mathrm{cov}[\boldsymbol{x}_0,\boldsymbol{x}_1] \\
\mathrm{cov}[\boldsymbol{x}_1,\boldsymbol{x}_0] &amp; \mathrm{var}[\boldsymbol{x}_1] \\
\end{bmatrix},
\end{split}\]</div>
<p>where we wrote $<span class="math notranslate nohighlight">\(\boldsymbol{C}[\boldsymbol{x}_0,\boldsymbol{x}_1] = \boldsymbol{C}[\boldsymbol{x}]\)</span><span class="math notranslate nohighlight">\( to indicate that this the covariance of the vectors \)</span>\boldsymbol{x}<span class="math notranslate nohighlight">\( of the design/feature matrix \)</span>\boldsymbol{X}$.</p>
<p>It is easy to generalize this to a matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\in {\mathbb{R}}^{n\times p}\)</span>.</p>
</div>
<div class="section" id="towards-the-pca-theorem">
<h2><span class="section-number">11.3. </span>Towards the PCA theorem<a class="headerlink" href="#towards-the-pca-theorem" title="Permalink to this headline"></a></h2>
<p>We have that the covariance matrix (the correlation matrix involves a simple rescaling) is given as</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{C}[\boldsymbol{x}] = \frac{1}{n}\boldsymbol{X}^T\boldsymbol{X}= \mathbb{E}[\boldsymbol{X}^T\boldsymbol{X}].
\]</div>
<p>Let us now assume that we can perform a series of orthogonal transformations where we employ some orthogonal matrices <span class="math notranslate nohighlight">\(\boldsymbol{S}\)</span>.
These matrices are defined as <span class="math notranslate nohighlight">\(\boldsymbol{S}\in {\mathbb{R}}^{p\times p}\)</span> and obey the orthogonality requirements <span class="math notranslate nohighlight">\(\boldsymbol{S}\boldsymbol{S}^T=\boldsymbol{S}^T\boldsymbol{S}=\boldsymbol{I}\)</span>. The matrix can be written out in terms of the column vectors <span class="math notranslate nohighlight">\(\boldsymbol{s}_i\)</span> as <span class="math notranslate nohighlight">\(\boldsymbol{S}=[\boldsymbol{s}_0,\boldsymbol{s}_1,\dots,\boldsymbol{s}_{p-1}]\)</span> and <span class="math notranslate nohighlight">\(\boldsymbol{s}_i \in {\mathbb{R}}^{p}\)</span>.</p>
<p>Assume also that there is a transformation <span class="math notranslate nohighlight">\(\boldsymbol{S}^T\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S}=\boldsymbol{C}[\boldsymbol{y}]\)</span> such that the new matrix <span class="math notranslate nohighlight">\(\boldsymbol{C}[\boldsymbol{y}]\)</span> is diagonal with elements <span class="math notranslate nohighlight">\([\lambda_0,\lambda_1,\lambda_2,\dots,\lambda_{p-1}]\)</span>.</p>
<p>That is we have</p>
<div class="math notranslate nohighlight">
\[
\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},
\]</div>
<p>since the matrix <span class="math notranslate nohighlight">\(\boldsymbol{S}\)</span> is not a data dependent matrix. Multiplying with <span class="math notranslate nohighlight">\(\boldsymbol{S}\)</span> from the left we have</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{S}\boldsymbol{C}[\boldsymbol{y}] = \boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S},
\]</div>
<p>and since <span class="math notranslate nohighlight">\(\boldsymbol{C}[\boldsymbol{y}]\)</span> is diagonal we have for a given eigenvalue <span class="math notranslate nohighlight">\(i\)</span> of the covariance matrix that</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{S}_i\lambda_i = \boldsymbol{C}[\boldsymbol{x}]\boldsymbol{S}_i.
\]</div>
<p>In the derivation of the PCA theorem we will assume that the eigenvalues are ordered in descending order, that is
<span class="math notranslate nohighlight">\(\lambda_0 &gt; \lambda_1 &gt; \dots &gt; \lambda_{p-1}\)</span>.</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 <span class="math notranslate nohighlight">\(p\)</span> is very large,
we could then aim at reducing <span class="math notranslate nohighlight">\(p\)</span> to <span class="math notranslate nohighlight">\(l &lt;&lt; p\)</span> and handle only <span class="math notranslate nohighlight">\(l\)</span>
features/predictors.</p>
<div class="section" id="the-algorithm-before-theorem">
<h3><span class="section-number">11.3.1. </span>The Algorithm before theorem<a class="headerlink" href="#the-algorithm-before-theorem" title="Permalink to this headline"></a></h3>
<p>Heres how we would proceed in setting up the algorithm for the PCA, see also discussion below here.</p>
<ul class="simple">
<li><p>Set up the datapoints for the design/feature matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span> with <span class="math notranslate nohighlight">\(\boldsymbol{X}\in {\mathbb{R}}^{n\times p}\)</span>, with the predictors/features <span class="math notranslate nohighlight">\(p\)</span> referring to the column numbers and the entries <span class="math notranslate nohighlight">\(n\)</span> being the row elements.</p></li>
</ul>
<div class="math notranslate nohighlight">
\[\begin{split}
\boldsymbol{X}=\begin{bmatrix}
x_{0,0} &amp; x_{0,1} &amp; x_{0,2}&amp; \dots &amp; \dots x_{0,p-1}\\
x_{1,0} &amp; x_{1,1} &amp; x_{1,2}&amp; \dots &amp; \dots x_{1,p-1}\\
x_{2,0} &amp; x_{2,1} &amp; x_{2,2}&amp; \dots &amp; \dots x_{2,p-1}\\
\dots &amp; \dots &amp; \dots &amp; \dots \dots &amp; \dots \\
x_{n-2,0} &amp; x_{n-2,1} &amp; x_{n-2,2}&amp; \dots &amp; \dots x_{n-2,p-1}\\
x_{n-1,0} &amp; x_{n-1,1} &amp; x_{n-1,2}&amp; \dots &amp; \dots x_{n-1,p-1}\\
\end{bmatrix},
\end{split}\]</div>
<ul class="simple">
<li><p>Center the data by subtracting the mean value for each column. This leads to a new matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\rightarrow \overline{\boldsymbol{X}}\)</span>.</p></li>
<li><p>Compute then the covariance/correlation matrix <span class="math notranslate nohighlight">\(\mathbb{E}[\overline{\boldsymbol{X}}^T\overline{\boldsymbol{X}}]\)</span>.</p></li>
<li><p>Find the eigenpairs of <span class="math notranslate nohighlight">\(\boldsymbol{C}\)</span> with eigenvalues <span class="math notranslate nohighlight">\([\lambda_0,\lambda_1,\dots,\lambda_{p-1}]\)</span> and eigenvectors <span class="math notranslate nohighlight">\([\boldsymbol{s}_0,\boldsymbol{s}_1,\dots,\boldsymbol{s}_{p-1}]\)</span>.</p></li>
<li><p>Order the eigenvalue (and the eigenvectors accordingly) in order of decreasing eigenvalues.</p></li>
<li><p>Keep only those <span class="math notranslate nohighlight">\(l\)</span> eigenvalues larger than a selected threshold value, discarding thus <span class="math notranslate nohighlight">\(p-l\)</span> features since we expect small variations in the data here.</p></li>
</ul>
</div>
<div class="section" id="writing-our-own-pca-code">
<h3><span class="section-number">11.3.2. </span>Writing our own PCA code<a class="headerlink" href="#writing-our-own-pca-code" title="Permalink to this headline"></a></h3>
<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>
<div class="math notranslate nohighlight">
\[\begin{split}
\mu = (-1,2) \qquad \Sigma = \begin{bmatrix} 4 &amp; 2 \\
2 &amp; 2
\end{bmatrix}
\end{split}\]</div>
<p>Note that the mean refers to each column of data.
We will generate <span class="math notranslate nohighlight">\(n = 10000\)</span> points <span class="math notranslate nohighlight">\(X = \{ x_1, \ldots, x_N \}\)</span> from
this distribution, and store them in the <span class="math notranslate nohighlight">\(1000 \times 2\)</span> matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span>. This is our design matrix where we have forced the covariance and mean values to take specific values.</p>
<p>The following Python code aids in setting up the data and writing out the design matrix.
Note that the function <strong>multivariate</strong> returns also the covariance discussed above and that it is defined by dividing by <span class="math notranslate nohighlight">\(n-1\)</span> instead of <span class="math notranslate nohighlight">\(n\)</span>.</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="o">%</span><span class="k">matplotlib</span> inline
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
<span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">display</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">10000</span>
<span class="n">mean</span> <span class="o">=</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">cov</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">]]</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">multivariate_normal</span><span class="p">(</span><span class="n">mean</span><span class="p">,</span> <span class="n">cov</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<p>Now we are going to implement the PCA algorithm. We will break it down into various substeps.</p>
<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>
<div class="math notranslate nohighlight">
\[
\mu_n = \frac{1}{n} \sum_{i=1}^n x_i
\]</div>
<p>and the mean-centered data <span class="math notranslate nohighlight">\(\bar{X} = \{ \bar{x}_1, \ldots, \bar{x}_n \}\)</span> takes the form</p>
<div class="math notranslate nohighlight">
\[
\bar{x}_i = x_i - \mu_n.
\]</div>
<p>When you are done with these steps, print out <span class="math notranslate nohighlight">\(\mu_n\)</span> to verify it is
close to <span class="math notranslate nohighlight">\(\mu\)</span> and plot your mean centered data to verify it is
centered at the origin!
The following code elements perform these operations using <strong>pandas</strong> or using our own functionality for doing so. The latter, using <strong>numpy</strong> is rather simple through the <strong>mean()</strong> function.</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="c1"># Pandas does the centering for us</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span> <span class="o">-</span><span class="n">df</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span>
<span class="c1"># we center it ourselves</span>
<span class="n">X_centered</span> <span class="o">=</span> <span class="n">X</span> <span class="o">-</span> <span class="n">X</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<p>Alternatively, we could use the functions we discussed
earlier for scaling the data set. That is, we could have used the
<strong>StandardScaler</strong> function in <strong>Scikit-Learn</strong>, 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 <span class="math notranslate nohighlight">\(2\sqrt{2}\)</span> for our
specific case.</p>
<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>
<div class="math notranslate nohighlight">
\[
\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)
\]</div>
<p>where the data points <span class="math notranslate nohighlight">\(x_i \in \mathbb{R}^p\)</span> (here in this example <span class="math notranslate nohighlight">\(p = 2\)</span>) are column vectors and <span class="math notranslate nohighlight">\(x^T\)</span> is the transpose of <span class="math notranslate nohighlight">\(x\)</span>.
We can write our own code or simply use either the functionaly of <strong>numpy</strong> or that of <strong>pandas</strong>, as follows</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="n">df</span><span class="o">.</span><span class="n">cov</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">cov</span><span class="p">(</span><span class="n">X_centered</span><span class="o">.</span><span class="n">T</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span> 0 1
0 4.034057 2.045548
1 2.045548 2.024217
[[4.03405654 2.04554803]
[2.04554803 2.02421742]]
</pre></div>
</div>
</div>
</div>
<p>Note that the way we define the covariance matrix here has a factor <span class="math notranslate nohighlight">\(n-1\)</span> instead of <span class="math notranslate nohighlight">\(n\)</span>. This is included in the <strong>cov()</strong> function by <strong>numpy</strong> and <strong>pandas</strong>.
Our own code here is not very elegant and asks for obvious improvements. It is tailored to this specific <span class="math notranslate nohighlight">\(2\times 2\)</span> covariance matrix.</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># extract the relevant columns from the centered design matrix of dim n x 2</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">X_centered</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">X_centered</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]</span>
<span class="n">Cov</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="n">Cov</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">T</span><span class="nd">@y</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">Cov</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">T</span><span class="nd">@x</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">Cov</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">y</span><span class="o">.</span><span class="n">T</span><span class="nd">@y</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">Cov</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span><span class="o">=</span> <span class="n">Cov</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Centered covariance using own code&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">Cov</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s1">&#39;x&#39;</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s1">&#39;equal&#39;</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>Centered covariance using own code
[[4.03405654 2.04554803]
[2.04554803 2.02421742]]
</pre></div>
</div>
<img alt="_images/chapter8_65_1.png" src="_images/chapter8_65_1.png" />
</div>
</div>
<p>Depending on the number of points <span class="math notranslate nohighlight">\(n\)</span>, 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>
</div>
<div class="section" id="diagonalize-the-sample-covariance-matrix-to-obtain-the-principal-components">
<h3><span class="section-number">11.3.3. </span>Diagonalize the sample covariance matrix to obtain the principal components<a class="headerlink" href="#diagonalize-the-sample-covariance-matrix-to-obtain-the-principal-components" title="Permalink to this headline"></a></h3>
<p>Now we are ready to solve for the principal components! To do so we
diagonalize the sample covariance matrix <span class="math notranslate nohighlight">\(\Sigma\)</span>. We can use the
function <strong>np.linalg.eig</strong> to do so. It will return the eigenvalues and
eigenvectors of <span class="math notranslate nohighlight">\(\Sigma\)</span>. Once we have these we can perform the
following tasks:</p>
<ul class="simple">
<li><p>We compute the percentage of the total variance captured by the first principal component</p></li>
<li><p>We plot the mean centered data and lines along the first and second principal components</p></li>
<li><p>Then we project the mean centered data onto the first and second principal components, and plot the projected data.</p></li>
<li><p>Finally, we approximate the data as</p></li>
</ul>
<div class="math notranslate nohighlight">
\[
x_i \approx \tilde{x}_i = \mu_n + \langle x_i, v_0 \rangle v_0
\]</div>
<p>where <span class="math notranslate nohighlight">\(v_0\)</span> is the first principal component.</p>
<p>Collecting all these steps we can write our own PCA function and
compare this with the functionality included in <strong>Scikit-Learn</strong>.</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>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># diagonalize and obtain eigenvalues, not necessarily sorted</span>
<span class="n">EigValues</span><span class="p">,</span> <span class="n">EigVectors</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">eig</span><span class="p">(</span><span class="n">Cov</span><span class="p">)</span>
<span class="c1"># sort eigenvectors and eigenvalues</span>
<span class="c1">#permute = EigValues.argsort()</span>
<span class="c1">#EigValues = EigValues[permute]</span>
<span class="c1">#EigVectors = EigVectors[:,permute]</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Eigenvalues of Covariance matrix&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="n">EigValues</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="n">FirstEigvector</span> <span class="o">=</span> <span class="n">EigVectors</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]</span>
<span class="n">SecondEigvector</span> <span class="o">=</span> <span class="n">EigVectors</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;First eigenvector&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">FirstEigvector</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Second eigenvector&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">SecondEigvector</span><span class="p">)</span>
<span class="c1">#thereafter we do a PCA with Scikit-learn</span>
<span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">PCA</span>
<span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">(</span><span class="n">n_components</span> <span class="o">=</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">X2Dsl</span> <span class="o">=</span> <span class="n">pca</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Eigenvector of largest eigenvalue&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">pca</span><span class="o">.</span><span class="n">components_</span><span class="o">.</span><span class="n">T</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">])</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>Eigenvalues of Covariance matrix
5.30820040103372
0.7500735612987705
First eigenvector
[0.84880366 0.52870818]
Second eigenvector
[-0.52870818 0.84880366]
</pre></div>
</div>
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>Eigenvector of largest eigenvalue
[-0.84880366 -0.52870818]
</pre></div>
</div>
</div>
</div>
<p>This code does not contain all the above elements, but it shows how we can use <strong>Scikit-Learn</strong> 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>
</div>
</div>
<div class="section" id="classical-pca-theorem">
<h2><span class="section-number">11.4. </span>Classical PCA Theorem<a class="headerlink" href="#classical-pca-theorem" title="Permalink to this headline"></a></h2>
<p>We assume now that we have a design matrix <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span> 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 <span class="math notranslate nohighlight">\([\boldsymbol{x}_0,\boldsymbol{x}_1,\dots, \boldsymbol{x}_{p-1}]\)</span> each with dimension
<span class="math notranslate nohighlight">\(\boldsymbol{x}\in {\mathbb{R}}^{n}\)</span>.</p>
<p>The PCA theorem states that minimizing the above reconstruction error
corresponds to setting <span class="math notranslate nohighlight">\(\boldsymbol{W}=\boldsymbol{S}\)</span>, 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
<span class="math notranslate nohighlight">\(\boldsymbol{z}_i\)</span> with at most <span class="math notranslate nohighlight">\(l\)</span> vectors, with <span class="math notranslate nohighlight">\(l &lt;&lt; p\)</span>, defined by the
orthogonal projection of the data onto the columns spanned by the
eigenvectors of the covariance(correlations matrix).</p>
<p>To show the PCA theorem let us start with the assumption that there is one vector <span class="math notranslate nohighlight">\(\boldsymbol{s}_0\)</span> which corresponds to a solution which minimized the reconstruction error <span class="math notranslate nohighlight">\(J\)</span>. This is an orthogonal vector. It means that we now approximate the reconstruction error in terms of <span class="math notranslate nohighlight">\(\boldsymbol{w}_0\)</span> and <span class="math notranslate nohighlight">\(\boldsymbol{z}_0\)</span> 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 <span class="math notranslate nohighlight">\(\boldsymbol{w}_0\)</span> go to infinity. However, this norm since we
want the matrix <span class="math notranslate nohighlight">\(\boldsymbol{W}\)</span> to be an orthogonal matrix, is constrained by
<span class="math notranslate nohighlight">\(\vert\vert \boldsymbol{w}_0 \vert\vert_2^2=1\)</span>. Imposing this condition via a
Lagrange multiplier we can then in turn maximize</p>
<div class="math notranslate nohighlight">
\[
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).
\]</div>
<p>Taking the derivative with respect to <span class="math notranslate nohighlight">\(\boldsymbol{w}_0\)</span> we obtain</p>
<div class="math notranslate nohighlight">
\[
\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,
\]</div>
<p>meaning that</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{w}_0=\lambda_0\boldsymbol{w}_0.
\]</div>
<p><strong>The direction that maximizes the variance (or minimizes the construction error) is an eigenvector of the covariance matrix</strong>! If we left multiply with <span class="math notranslate nohighlight">\(\boldsymbol{w}_0^T\)</span> we have the variance of the projected data is</p>
<div class="math notranslate nohighlight">
\[
\boldsymbol{w}_0^T\boldsymbol{C}[\boldsymbol{x}]\boldsymbol{w}_0=\lambda_0.
\]</div>
<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 <span class="math notranslate nohighlight">\(J\)</span> 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 <span class="math notranslate nohighlight">\(\boldsymbol{X}\)</span>.</p>
<p>The proof
for the other eigenvectors <span class="math notranslate nohighlight">\(\boldsymbol{w}_1,\boldsymbol{w}_2,\dots\)</span> can be
established by applying the above arguments and using the fact that
our basis of eigenvectors is orthogonal, see <a class="reference external" href="https://mitpress.mit.edu/books/machine-learning-1">Murphy chapter
12.2</a>. The
discussion in chapter 12.2 of Murphys 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 class="reference external" href="https://www.springer.com/gp/book/9780387878102">Vidal, Ma and Sastry, chapter 2</a>.</p>
</div>
<div class="section" id="geometric-interpretation-and-link-with-singular-value-decomposition">
<h2><span class="section-number">11.5. </span>Geometric Interpretation and link with Singular Value Decomposition<a class="headerlink" href="#geometric-interpretation-and-link-with-singular-value-decomposition" title="Permalink to this headline"></a></h2>
<p>For a detailed demonstration of the geometric interpretation, see <a class="reference external" href="https://www.springer.com/gp/book/9780387878102">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 NumPys <strong>svd()</strong> 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 <strong>pandas</strong> or our own code</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">display</span>
<span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
<span class="c1"># setting up a 10 x 5 vanilla matrix </span>
<span class="n">rows</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">cols</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="n">rows</span><span class="p">,</span><span class="n">cols</span><span class="p">)</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="c1"># Pandas does the centering for us</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span> <span class="o">-</span><span class="n">df</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span>
<span class="n">display</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
<span class="c1"># we center it ourselves</span>
<span class="n">X_centered</span> <span class="o">=</span> <span class="n">X</span> <span class="o">-</span> <span class="n">X</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="c1"># Then check the difference between pandas and our own set up</span>
<span class="nb">print</span><span class="p">(</span><span class="n">X_centered</span><span class="o">-</span><span class="n">df</span><span class="p">)</span>
<span class="c1">#Now we do an SVD</span>
<span class="n">U</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">V</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">svd</span><span class="p">(</span><span class="n">X_centered</span><span class="p">)</span>
<span class="n">c1</span> <span class="o">=</span> <span class="n">V</span><span class="o">.</span><span class="n">T</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span>
<span class="n">c2</span> <span class="o">=</span> <span class="n">V</span><span class="o">.</span><span class="n">T</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">]</span>
<span class="n">W2</span> <span class="o">=</span> <span class="n">V</span><span class="o">.</span><span class="n">T</span><span class="p">[:,</span> <span class="p">:</span><span class="mi">2</span><span class="p">]</span>
<span class="n">X2D</span> <span class="o">=</span> <span class="n">X_centered</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">W2</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">X2D</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output text_html"><div>
<style scoped>
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-1.574465</td>
<td>0.259153</td>
<td>1.197370</td>
<td>0.147400</td>
<td>0.649382</td>
</tr>
<tr>
<th>1</th>
<td>0.689519</td>
<td>0.137652</td>
<td>-1.025709</td>
<td>0.210340</td>
<td>-0.076938</td>
</tr>
<tr>
<th>2</th>
<td>-0.282727</td>
<td>0.351636</td>
<td>-0.539261</td>
<td>1.216683</td>
<td>0.340782</td>
</tr>
<tr>
<th>3</th>
<td>0.070889</td>
<td>-0.614808</td>
<td>1.074067</td>
<td>-0.038300</td>
<td>-1.450257</td>
</tr>
<tr>
<th>4</th>
<td>1.794282</td>
<td>1.458078</td>
<td>-0.207545</td>
<td>-0.442600</td>
<td>-0.147420</td>
</tr>
<tr>
<th>5</th>
<td>1.112383</td>
<td>0.647473</td>
<td>1.405890</td>
<td>0.073598</td>
<td>-0.276263</td>
</tr>
<tr>
<th>6</th>
<td>0.397700</td>
<td>-1.526744</td>
<td>-0.712018</td>
<td>1.216290</td>
<td>0.418506</td>
</tr>
<tr>
<th>7</th>
<td>-0.280647</td>
<td>1.106095</td>
<td>-1.646283</td>
<td>-0.956563</td>
<td>-1.564374</td>
</tr>
<tr>
<th>8</th>
<td>-0.369139</td>
<td>-0.751699</td>
<td>0.051649</td>
<td>-0.213103</td>
<td>0.967809</td>
</tr>
<tr>
<th>9</th>
<td>-1.557795</td>
<td>-1.066837</td>
<td>0.401842</td>
<td>-1.213743</td>
<td>1.138775</td>
</tr>
</tbody>
</table>
</div></div><div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span> 0 1 2 3 4
0 0.0 0.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0 0.0
2 0.0 0.0 0.0 0.0 0.0
3 0.0 0.0 0.0 0.0 0.0
4 0.0 0.0 0.0 0.0 0.0
5 0.0 0.0 0.0 0.0 0.0
6 0.0 0.0 0.0 0.0 0.0
7 0.0 0.0 0.0 0.0 0.0
8 0.0 0.0 0.0 0.0 0.0
9 0.0 0.0 0.0 0.0 0.0
[[-1.5378811 -0.94639099]
[ 0.86145244 0.89288636]
[-0.00445655 0.81633628]
[ 0.07145103 -1.00433417]
[ 2.03707133 -0.48476997]
[ 0.72174172 -1.4557763 ]
[-0.55854694 1.60673226]
[ 1.6999536 0.43766686]
[-1.10405456 0.31718909]
[-2.18673098 -0.17953942]]
</pre></div>
</div>
</div>
</div>
<p>PCA assumes that the dataset is centered around the origin. Scikit-Learns 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, dont
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 <span class="math notranslate nohighlight">\(d\)</span> dimensions by projecting it onto the hyperplane defined by the first <span class="math notranslate nohighlight">\(d\)</span> principal components.
Selecting this hyperplane ensures that the projection will preserve as much variance as possible.</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">W2</span> <span class="o">=</span> <span class="n">V</span><span class="o">.</span><span class="n">T</span><span class="p">[:,</span> <span class="p">:</span><span class="mi">2</span><span class="p">]</span>
<span class="n">X2D</span> <span class="o">=</span> <span class="n">X_centered</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">W2</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="pca-and-scikit-learn">
<h2><span class="section-number">11.6. </span>PCA and scikit-learn<a class="headerlink" href="#pca-and-scikit-learn" title="Permalink to this headline"></a></h2>
<p>Scikit-Learns 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>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="c1">#thereafter we do a PCA with Scikit-learn</span>
<span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">PCA</span>
<span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">(</span><span class="n">n_components</span> <span class="o">=</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">X2D</span> <span class="o">=</span> <span class="n">pca</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">X2D</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>[[ 1.5378811 -0.94639099]
[-0.86145244 0.89288636]
[ 0.00445655 0.81633628]
[-0.07145103 -1.00433417]
[-2.03707133 -0.48476997]
[-0.72174172 -1.4557763 ]
[ 0.55854694 1.60673226]
[-1.6999536 0.43766686]
[ 1.10405456 0.31718909]
[ 2.18673098 -0.17953942]]
</pre></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>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">pca</span><span class="o">.</span><span class="n">components_</span><span class="o">.</span><span class="n">T</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output text_plain highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>array([-0.62373464, -0.5303329 , 0.317367 , 0.01873344, 0.47815203])
</pre></div>
</div>
</div>
</div>
<p>Another very useful piece of information is the explained variance ratio of each principal component,
available via the <span class="math notranslate nohighlight">\(explained\_variance\_ratio\)</span> variable. It indicates the proportion of the datasets
variance that lies along the axis of each principal component.</p>
</div>
<div class="section" id="back-to-the-cancer-data">
<h2><span class="section-number">11.7. </span>Back to the Cancer Data<a class="headerlink" href="#back-to-the-cancer-data" title="Permalink to this headline"></a></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>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">train_test_split</span>
<span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">load_breast_cancer</span>
<span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">LogisticRegression</span>
<span class="n">cancer</span> <span class="o">=</span> <span class="n">load_breast_cancer</span><span class="p">()</span>
<span class="n">X_train</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="n">y_test</span> <span class="o">=</span> <span class="n">train_test_split</span><span class="p">(</span><span class="n">cancer</span><span class="o">.</span><span class="n">data</span><span class="p">,</span><span class="n">cancer</span><span class="o">.</span><span class="n">target</span><span class="p">,</span><span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="n">logreg</span> <span class="o">=</span> <span class="n">LogisticRegression</span><span class="p">()</span>
<span class="n">logreg</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Train set accuracy from Logistic Regression: </span><span class="si">{:.2f}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">logreg</span><span class="o">.</span><span class="n">score</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span><span class="n">y_train</span><span class="p">)))</span>
<span class="c1"># We scale the data</span>
<span class="kn">from</span> <span class="nn">sklearn.preprocessing</span> <span class="kn">import</span> <span class="n">StandardScaler</span>
<span class="n">scaler</span> <span class="o">=</span> <span class="n">StandardScaler</span><span class="p">()</span>
<span class="n">scaler</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">)</span>
<span class="n">X_train_scaled</span> <span class="o">=</span> <span class="n">scaler</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">X_train</span><span class="p">)</span>
<span class="n">X_test_scaled</span> <span class="o">=</span> <span class="n">scaler</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
<span class="c1"># Then perform again a log reg fit</span>
<span class="n">logreg</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train_scaled</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Train set accuracy scaled data: </span><span class="si">{:.2f}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">logreg</span><span class="o">.</span><span class="n">score</span><span class="p">(</span><span class="n">X_train_scaled</span><span class="p">,</span><span class="n">y_train</span><span class="p">)))</span>
<span class="c1">#thereafter we do a PCA with Scikit-learn</span>
<span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">PCA</span>
<span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">(</span><span class="n">n_components</span> <span class="o">=</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">X2D_train</span> <span class="o">=</span> <span class="n">pca</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">X_train_scaled</span><span class="p">)</span>
<span class="c1"># and finally compute the log reg fit and the score on the training data </span>
<span class="n">logreg</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X2D_train</span><span class="p">,</span><span class="n">y_train</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Train set accuracy scaled and PCA data: </span><span class="si">{:.2f}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">logreg</span><span class="o">.</span><span class="n">score</span><span class="p">(</span><span class="n">X2D_train</span><span class="p">,</span><span class="n">y_train</span><span class="p">)))</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>Train set accuracy from Logistic Regression: 0.95
</pre></div>
</div>
<div class="output stream highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>Train set accuracy scaled data: 0.99
Train set accuracy scaled and PCA data: 0.96
</pre></div>
</div>
<div class="output stderr highlight-myst-ansi notranslate"><div class="highlight"><pre><span></span>/Users/mhjensen/miniforge3/envs/myenv/lib/python3.9/site-packages/sklearn/linear_model/_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.
Increase the number of iterations (max_iter) or scale the data as shown in:
https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
n_iter_i = _check_optimize_result(
</pre></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 — 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 sets variance:</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">()</span>
<span class="n">pca</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">cumsum</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">cumsum</span><span class="p">(</span><span class="n">pca</span><span class="o">.</span><span class="n">explained_variance_ratio_</span><span class="p">)</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">cumsum</span> <span class="o">&gt;=</span> <span class="mf">0.95</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
</pre></div>
</div>
</div>
</div>
<p>You could then set <span class="math notranslate nohighlight">\(n\_components=d\)</span> 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 <span class="math notranslate nohighlight">\(n\_components\)</span> to be
a float between 0.0 and 1.0, indicating the ratio of variance you wish to preserve:</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mf">0.95</span><span class="p">)</span>
<span class="n">X_reduced</span> <span class="o">=</span> <span class="n">pca</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="incremental-pca">
<h3><span class="section-number">11.7.1. </span>Incremental PCA<a class="headerlink" href="#incremental-pca" title="Permalink to this headline"></a></h3>
<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>
</div>
<div class="section" id="randomized-pca">
<h3><span class="section-number">11.7.2. </span>Randomized PCA<a class="headerlink" href="#randomized-pca" title="Permalink to this headline"></a></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 <span class="math notranslate nohighlight">\(O(m \times d^2)+O(d^3)\)</span>, instead of <span class="math notranslate nohighlight">\(O(m \times n^2) + O(n^3)\)</span>, so it is dramatically faster than the
previous algorithms when <span class="math notranslate nohighlight">\(d\)</span> is much smaller than <span class="math notranslate nohighlight">\(n\)</span>.</p>
</div>
<div class="section" id="kernel-pca">
<h3><span class="section-number">11.7.3. </span>Kernel PCA<a class="headerlink" href="#kernel-pca" title="Permalink to this headline"></a></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-Learns KernelPCA class to perform kPCA with an</p>
<div class="cell docutils container">
<div class="cell_input docutils container">
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">KernelPCA</span>
<span class="n">rbf_pca</span> <span class="o">=</span> <span class="n">KernelPCA</span><span class="p">(</span><span class="n">n_components</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">kernel</span><span class="o">=</span><span class="s2">&quot;rbf&quot;</span><span class="p">,</span> <span class="n">gamma</span><span class="o">=</span><span class="mf">0.04</span><span class="p">)</span>
<span class="n">X_reduced</span> <span class="o">=</span> <span class="n">rbf_pca</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
<div class="section" id="other-techniques">
<h2><span class="section-number">11.8. </span>Other techniques<a class="headerlink" href="#other-techniques" title="Permalink to this headline"></a></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 class="simple">
<li><p><strong>Multidimensional Scaling (MDS)</strong> reduces dimensionality while trying to preserve the distances between the instances.</p></li>
<li><p><strong>Isomap</strong> creates a graph by connecting each instance to its nearest neighbors, then reduces dimensionality while trying to preserve the geodesic distances between the instances.</p></li>
<li><p><strong>t-Distributed Stochastic Neighbor Embedding</strong> (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).</p></li>
<li><p>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.</p></li>
</ul>
</div>
</div>
<script type="text/x-thebe-config">
{
requestKernel: true,
binderOptions: {
repo: "binder-examples/jupyter-stacks-datascience",
ref: "master",
},
codeMirrorConfig: {
theme: "abcdef",
mode: "python"
},
kernelOptions: {
kernelName: "python3",
path: "./."
},
predefinedOutput: true
}
</script>
<script>kernelName = 'python3'</script>
</div>
<!-- Previous / next buttons -->
<div class='prev-next-area'>
<a class='left-prev' id="prev-link" href="chapter7.html" title="previous page">
<i class="fas fa-angle-left"></i>
<div class="prev-next-info">
<p class="prev-next-subtitle">previous</p>
<p class="prev-next-title"><span class="section-number">10. </span>Ensemble Methods: From a Single Tree to Many Trees and Extreme Boosting, Meet the Jungle of Methods</p>
</div>
</a>
<a class='right-next' id="next-link" href="clustering.html" title="next page">
<div class="prev-next-info">
<p class="prev-next-subtitle">next</p>
<p class="prev-next-title"><span class="section-number">12. </span>Clustering and Unsupervised Learning</p>
</div>
<i class="fas fa-angle-right"></i>
</a>
</div>
</div>
</div>
<footer class="footer">
<p>
By Morten Hjorth-Jensen<br/>
&copy; Copyright 2021.<br/>
</p>
</footer>
</main>
</div>
</div>
<script src="_static/js/index.be7d3bbb2ef33a8344ce.js"></script>
</body>
</html>