Files
FYS-STK4155/doc/pub/week36/html/week36-solarized.html
T
Morten Hjorth-Jensen b62dc358d7 added video
2025-09-01 16:31:40 +02:00

2599 lines
125 KiB
HTML

<!--
HTML file automatically generated from DocOnce source
(https://github.com/doconce/doconce/)
doconce format html week36.do.txt --pygments_html_style=perldoc --html_style=solarized3 --html_links_in_new_window --html_output=week36-solarized --no_mako
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="DocOnce: https://github.com/doconce/doconce/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Week 36: Linear Regression and Gradient descent">
<title>Week 36: Linear Regression and Gradient descent</title>
<link href="https://cdn.rawgit.com/doconce/doconce/master/bundled/html_styles/style_solarized_box/css/solarized_light_code.css" rel="stylesheet" type="text/css" title="light"/>
<script src="https://cdn.rawgit.com/doconce/doconce/master/bundled/html_styles/style_solarized_box/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<link href="https://thomasf.github.io/solarized-css/solarized-light.min.css" rel="stylesheet">
<style type="text/css">
h1 {color: #b58900;} /* yellow */
/* h1 {color: #cb4b16;} orange */
/* h1 {color: #d33682;} magenta, the original choice of thomasf */
code { padding: 0px; background-color: inherit; }
pre {
border: 0pt solid #93a1a1;
box-shadow: none;
}
.alert-text-small { font-size: 80%; }
.alert-text-large { font-size: 130%; }
.alert-text-normal { font-size: 90%; }
.alert {
padding:8px 35px 8px 14px; margin-bottom:18px;
text-shadow:0 1px 0 rgba(255,255,255,0.5);
border:1px solid #93a1a1;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
color: #555;
background-color: #eee8d5;
background-position: 10px 5px;
background-repeat: no-repeat;
background-size: 38px;
padding-left: 55px;
width: 75%;
}
.alert-block {padding-top:14px; padding-bottom:14px}
.alert-block > p, .alert-block > ul {margin-bottom:1em}
.alert li {margin-top: 1em}
.alert-block p+p {margin-top:5px}
.alert-notice { background-image: url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_yellow_notice.png); }
.alert-summary { background-image:url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_yellow_summary.png); }
.alert-warning { background-image: url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_yellow_warning.png); }
.alert-question {background-image:url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_yellow_question.png); }
div { text-align: justify; text-justify: inter-word; }
.tab {
padding-left: 1.5em;
}
div.toc p,a {
line-height: 1.3;
margin-top: 1.1;
margin-bottom: 1.1;
}
</style>
</head>
<!-- tocinfo
{'highest level': 2,
'sections': [('Plans for week 36', 2, None, 'plans-for-week-36'),
('Material for lecture Monday September 2',
2,
None,
'material-for-lecture-monday-september-2'),
('Mathematical Interpretation of Ordinary Least Squares',
2,
None,
'mathematical-interpretation-of-ordinary-least-squares'),
('Residual Error', 2, None, 'residual-error'),
('Simple case', 2, None, 'simple-case'),
('The singular value decomposition',
2,
None,
'the-singular-value-decomposition'),
('Linear Regression Problems',
2,
None,
'linear-regression-problems'),
('Fixing the singularity', 2, None, 'fixing-the-singularity'),
('Ridge and LASSO Regression',
2,
None,
'ridge-and-lasso-regression'),
('Deriving the Ridge Regression Equations',
2,
None,
'deriving-the-ridge-regression-equations'),
('Basic math of the SVD', 2, None, 'basic-math-of-the-svd'),
('The SVD, a Fantastic Algorithm',
2,
None,
'the-svd-a-fantastic-algorithm'),
('Economy-size SVD', 2, None, 'economy-size-svd'),
('Codes for the SVD', 2, None, 'codes-for-the-svd'),
('Note about SVD Calculations',
2,
None,
'note-about-svd-calculations'),
('Mathematics of the SVD and implications',
2,
None,
'mathematics-of-the-svd-and-implications'),
('Example Matrix', 2, None, 'example-matrix'),
('Setting up the Matrix to be inverted',
2,
None,
'setting-up-the-matrix-to-be-inverted'),
('Further properties (important for our analyses later)',
2,
None,
'further-properties-important-for-our-analyses-later'),
('Back to Ridge and LASSO Regression',
2,
None,
'back-to-ridge-and-lasso-regression'),
('Interpreting the Ridge results',
2,
None,
'interpreting-the-ridge-results'),
('More interpretations', 2, None, 'more-interpretations'),
('Deriving the Lasso Regression Equations',
2,
None,
'deriving-the-lasso-regression-equations'),
('Optimization and gradient descent, the central part of any '
'Machine Learning algortithm',
2,
None,
'optimization-and-gradient-descent-the-central-part-of-any-machine-learning-algortithm'),
("Reminder on Newton-Raphson's method",
2,
None,
'reminder-on-newton-raphson-s-method'),
('The equations', 2, None, 'the-equations'),
('Simple geometric interpretation',
2,
None,
'simple-geometric-interpretation'),
('Extending to more than one variable',
2,
None,
'extending-to-more-than-one-variable'),
('Steepest descent', 2, None, 'steepest-descent'),
('More on Steepest descent', 2, None, 'more-on-steepest-descent'),
('The ideal', 2, None, 'the-ideal'),
('The sensitiveness of the gradient descent',
2,
None,
'the-sensitiveness-of-the-gradient-descent'),
('Convex functions', 2, None, 'convex-functions'),
('Convex function', 2, None, 'convex-function'),
('Conditions on convex functions',
2,
None,
'conditions-on-convex-functions'),
('More on convex functions', 2, None, 'more-on-convex-functions'),
('Some simple problems', 2, None, 'some-simple-problems'),
('Revisiting Ordinary Least Squares',
2,
None,
'revisiting-ordinary-least-squares'),
('Gradient descent example', 2, None, 'gradient-descent-example'),
('The derivative of the cost/loss function',
2,
None,
'the-derivative-of-the-cost-loss-function'),
('The Hessian matrix', 2, None, 'the-hessian-matrix'),
('Simple program', 2, None, 'simple-program'),
('Gradient Descent Example', 2, None, 'gradient-descent-example'),
('Gradient descent and Ridge',
2,
None,
'gradient-descent-and-ridge'),
('The Hessian matrix for Ridge Regression',
2,
None,
'the-hessian-matrix-for-ridge-regression'),
('Program example for gradient descent with Ridge Regression',
2,
None,
'program-example-for-gradient-descent-with-ridge-regression'),
('Using gradient descent methods, limitations',
2,
None,
'using-gradient-descent-methods-limitations'),
('Material for lab sessions sessions Tuesday and Wednesday',
2,
None,
'material-for-lab-sessions-sessions-tuesday-and-wednesday'),
('Linear Regression and the SVD',
2,
None,
'linear-regression-and-the-svd'),
('What does it mean?', 2, None, 'what-does-it-mean'),
('Ridge and LASSO Regression',
2,
None,
'ridge-and-lasso-regression'),
('From OLS to Ridge and Lasso',
2,
None,
'from-ols-to-ridge-and-lasso'),
('Deriving the Ridge Regression Equations',
2,
None,
'deriving-the-ridge-regression-equations'),
('Note on Scikit-Learn', 2, None, 'note-on-scikit-learn'),
('Comparison with OLS', 2, None, 'comparison-with-ols'),
('SVD analysis', 2, None, 'svd-analysis'),
('Interpreting the Ridge results',
2,
None,
'interpreting-the-ridge-results'),
('More interpretations', 2, None, 'more-interpretations'),
('Deriving the Lasso Regression Equations',
2,
None,
'deriving-the-lasso-regression-equations'),
('Simple example to illustrate Ordinary Least Squares, Ridge and '
'Lasso Regression',
2,
None,
'simple-example-to-illustrate-ordinary-least-squares-ridge-and-lasso-regression'),
('Ridge Regression', 2, None, 'ridge-regression'),
('Lasso Regression', 2, None, 'lasso-regression'),
('Yet another Example', 2, None, 'yet-another-example'),
('The OLS case', 2, None, 'the-ols-case'),
('The Ridge case', 2, None, 'the-ridge-case'),
('Writing the Cost Function',
2,
None,
'writing-the-cost-function'),
('Lasso case', 2, None, 'lasso-case'),
('The first Case', 2, None, 'the-first-case'),
('Simple code for solving the above problem',
2,
None,
'simple-code-for-solving-the-above-problem'),
('With Lasso Regression', 2, None, 'with-lasso-regression'),
('Another Example, now with a polynomial fit',
2,
None,
'another-example-now-with-a-polynomial-fit')]}
end of tocinfo -->
<body>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {
equationNumbers: { autoNumber: "AMS" },
extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
}
});
</script>
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<!-- ------------------- main content ---------------------- -->
<center>
<h1>Week 36: Linear Regression and Gradient descent</h1>
</center> <!-- document title -->
<!-- author(s): Morten Hjorth-Jensen -->
<center>
<b>Morten Hjorth-Jensen</b>
</center>
<!-- institution -->
<center>
<b>Department of Physics, University of Oslo, Norway</b>
</center>
<br>
<center>
<h4>September 1-5, 2025</h4>
</center> <!-- date -->
<br>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="plans-for-week-36">Plans for week 36 </h2>
<b>Material for the lecture on Monday September 1:</b>
<ol>
<li> Linear Regression, ordinary least squares (OLS), Ridge and Lasso and mathematical analysis</li>
<li> Derivation of Gradient descent and discussion of implementations for</li>
<li> Video of lecture at <a href="https://youtu.be/nVE_FRnGAHw" target="_blank"><tt>https://youtu.be/nVE_FRnGAHw</tt></a></li>
<li> Whiteboard notes at <a href="https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2025/FYSSTKweek36.pdf" target="_blank"><tt>https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2025/FYSSTKweek36.pdf</tt></a></li>
</ol>
<b>Material for the lab sessions on Tuesday and Wednesday (see at the end of these slides):</b>
<ol>
<li> Technicalities concerning Ridge and Lasso linear regression.</li>
<li> Presentation and discussion of the first project
<!-- * <a href="https://youtu.be/ZrIdZdZtHe0" target="_blank">Video of lab session</a> --></li>
</ol>
<b>Reading suggestion:</b>
<ol>
<li> Goodfellow et al, Deep Learning, introduction to gradient descent, see chapter 4.3 at <a href="https://www.deeplearningbook.org/contents/numerical.html" target="_blank"><tt>https://www.deeplearningbook.org/contents/numerical.html</tt></a></li>
<li> Rashcka et al, pages 37-44 and pages 278-283 with focus on linear regression.</li>
<li> Video on gradient descent at <a href="https://www.youtube.com/watch?v=sDv4f4s2SB8" target="_blank"><tt>https://www.youtube.com/watch?v=sDv4f4s2SB8</tt></a></li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="material-for-lecture-monday-september-2">Material for lecture Monday September 2 </h2>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-interpretation-of-ordinary-least-squares">Mathematical Interpretation of Ordinary Least Squares </h2>
<p>What is presented here is a mathematical analysis of various regression algorithms (ordinary least squares, Ridge and Lasso Regression). The analysis is based on an important algorithm in linear algebra, the so-called Singular Value Decomposition (SVD). </p>
<p>We have shown that in ordinary least squares the optimal parameters \( \theta \) are given by</p>
$$
\hat{\boldsymbol{\theta}} = \left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>The <b>hat</b> over \( \boldsymbol{\theta} \) means we have the optimal parameters after minimization of the cost function.</p>
<p>This means that our best model is defined as</p>
$$
\tilde{\boldsymbol{y}}=\boldsymbol{X}\hat{\boldsymbol{\theta}} = \boldsymbol{X}\left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>We now define a matrix</p>
$$
\boldsymbol{A}=\boldsymbol{X}\left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T.
$$
<p>We can rewrite</p>
$$
\tilde{\boldsymbol{y}}=\boldsymbol{X}\hat{\boldsymbol{\theta}} = \boldsymbol{A}\boldsymbol{y}.
$$
<p>The matrix \( \boldsymbol{A} \) has the important property that \( \boldsymbol{A}^2=\boldsymbol{A} \). This is the definition of a projection matrix.
We can then interpret our optimal model \( \tilde{\boldsymbol{y}} \) as being represented by an orthogonal projection of \( \boldsymbol{y} \) onto a space defined by the column vectors of \( \boldsymbol{X} \). In our case here the matrix \( \boldsymbol{A} \) is a square matrix. If it is a general rectangular matrix we have an oblique projection matrix.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="residual-error">Residual Error </h2>
<p>We have defined the residual error as</p>
$$
\boldsymbol{\epsilon}=\boldsymbol{y}-\tilde{\boldsymbol{y}}=\left[\boldsymbol{I}-\boldsymbol{X}\left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\right]\boldsymbol{y}.
$$
<p>The residual errors are then the projections of \( \boldsymbol{y} \) onto the orthogonal component of the space defined by the column vectors of \( \boldsymbol{X} \).</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="simple-case">Simple case </h2>
<p>If the matrix \( \boldsymbol{X} \) is an orthogonal (or unitary in case of complex values) matrix, we have</p>
$$
\boldsymbol{X}^T\boldsymbol{X}=\boldsymbol{X}\boldsymbol{X}^T = \boldsymbol{I}.
$$
<p>In this case the matrix \( \boldsymbol{A} \) becomes</p>
$$
\boldsymbol{A}=\boldsymbol{X}\left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T)=\boldsymbol{I},
$$
<p>and we have the obvious case</p>
$$
\boldsymbol{\epsilon}=\boldsymbol{y}-\tilde{\boldsymbol{y}}=0.
$$
<p>This serves also as a useful test of our codes. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-singular-value-decomposition">The singular value decomposition </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<p>The examples we have looked at so far are cases where we normally can
invert the matrix \( \boldsymbol{X}^T\boldsymbol{X} \). Using a polynomial expansion where we fit of various functions leads to
row vectors of the design matrix which are essentially orthogonal due
to the polynomial character of our model. Obtaining the inverse of the
design matrix is then often done via a so-called LU, QR or Cholesky
decomposition.
</p>
<p>As we will also see in the first project,
this may
however not the be case in general and a standard matrix inversion
algorithm based on say LU, QR or Cholesky decomposition may lead to singularities. We will see examples of this below and in other examples.
</p>
<p>There is however a way to circumvent this problem and also
gain some insights about the ordinary least squares approach, and
later shrinkage methods like Ridge and Lasso regressions.
</p>
<p>This is given by the <b>Singular Value Decomposition</b> (SVD) algorithm,
perhaps the most powerful linear algebra algorithm. The SVD provides
a numerically stable matrix decomposition that is used in a large
swath oc applications and the decomposition is always stable
numerically.
</p>
<p>In machine learning it plays a central role in dealing with for
example design matrices that may be near singular or singular.
Furthermore, as we will see here, the singular values can be related
to the covariance matrix (and thereby the correlation matrix) and in
turn the variance of a given quantity. It plays also an important role
in the principal component analysis where high-dimensional data can be
reduced to the statistically relevant features.
</p>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="linear-regression-problems">Linear Regression Problems </h2>
<p>One of the typical problems we encounter with linear regression, in particular
when the matrix \( \boldsymbol{X} \) (our so-called design matrix) is high-dimensional,
are problems with near singular or singular matrices. The column vectors of \( \boldsymbol{X} \)
may be linearly dependent, normally referred to as super-collinearity.
This means that the matrix may be rank deficient and it is basically impossible to
to model the data using linear regression. As an example, consider the matrix
</p>
$$
\begin{align*}
\mathbf{X} & = \left[
\begin{array}{rrr}
1 & -1 & 2
\\
1 & 0 & 1
\\
1 & 2 & -1
\\
1 & 1 & 0
\end{array} \right]
\end{align*}
$$
<p>The columns of \( \boldsymbol{X} \) are linearly dependent. We see this easily since the
the first column is the row-wise sum of the other two columns. The rank (more correct,
the column rank) of a matrix is the dimension of the space spanned by the
column vectors. Hence, the rank of \( \mathbf{X} \) is equal to the number
of linearly independent columns. In this particular case the matrix has rank 2.
</p>
<p>Super-collinearity of an \( (n \times p) \)-dimensional design matrix \( \mathbf{X} \) implies
that the inverse of the matrix \( \boldsymbol{X}^T\boldsymbol{X} \) (the matrix we need to invert to solve the linear regression equations) is non-invertible. If we have a square matrix that does not have an inverse, we say this matrix singular. The example here demonstrates this
</p>
$$
\begin{align*}
\boldsymbol{X} & = \left[
\begin{array}{rr}
1 & -1
\\
1 & -1
\end{array} \right].
\end{align*}
$$
<p>We see easily that \( \mbox{det}(\boldsymbol{X}) = x_{11} x_{22} - x_{12} x_{21} = 1 \times (-1) - 1 \times (-1) = 0 \). Hence, \( \mathbf{X} \) is singular and its inverse is undefined.
This is equivalent to saying that the matrix \( \boldsymbol{X} \) has at least an eigenvalue which is zero.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="fixing-the-singularity">Fixing the singularity </h2>
<p>If our design matrix \( \boldsymbol{X} \) which enters the linear regression problem</p>
$$
\begin{align}
\boldsymbol{\theta} & = (\boldsymbol{X}^{T} \boldsymbol{X})^{-1} \boldsymbol{X}^{T} \boldsymbol{y},
\label{_auto1}
\end{align}
$$
<p>has linearly dependent column vectors, we will not be able to compute the inverse
of \( \boldsymbol{X}^T\boldsymbol{X} \) and we cannot find the parameters (estimators) \( \theta_i \).
The estimators are only well-defined if \( (\boldsymbol{X}^{T}\boldsymbol{X})^{-1} \) exists.
This is more likely to happen when the matrix \( \boldsymbol{X} \) is high-dimensional. In this case it is likely to encounter a situation where
the regression parameters \( \theta_i \) cannot be estimated.
</p>
<p>A cheap <em>ad hoc</em> approach is simply to add a small diagonal component to the matrix to invert, that is we change</p>
$$
\boldsymbol{X}^{T} \boldsymbol{X} \rightarrow \boldsymbol{X}^{T} \boldsymbol{X}+\lambda \boldsymbol{I},
$$
<p>where \( \boldsymbol{I} \) is the identity matrix. When we discuss <b>Ridge</b> regression this is actually what we end up evaluating. The parameter \( \lambda \) is called a hyperparameter. More about this later. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="ridge-and-lasso-regression">Ridge and LASSO Regression </h2>
<p>Let us remind ourselves about the expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, that is
our optimization problem is
</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in {\mathbb{R}}^{p}}}\frac{1}{n}\left\{\left(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\right)^T\left(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\right)\right\}.
$$
<p>or we can state it as</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\sum_{i=0}^{n-1}\left(y_i-\tilde{y}_i\right)^2=\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2,
$$
<p>where we have used the definition of a norm-2 vector, that is</p>
$$
\vert\vert \boldsymbol{x}\vert\vert_2 = \sqrt{\sum_i x_i^2}.
$$
<p>By minimizing the above equation with respect to the parameters
\( \boldsymbol{\theta} \) we could then obtain an analytical expression for the
parameters \( \boldsymbol{\theta} \). We can add a regularization parameter \( \lambda \) by
defining a new cost function to be optimized, that is
</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_2^2
$$
<p>which leads to the Ridge regression minimization problem where we
require that \( \vert\vert \boldsymbol{\theta}\vert\vert_2^2\le t \), where \( t \) is
a finite number larger than zero. By defining
</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_1,
$$
<p>we have a new optimization equation</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_1
$$
<p>which leads to Lasso regression. Lasso stands for least absolute shrinkage and selection operator. </p>
<p>Here we have defined the norm-1 as </p>
$$
\vert\vert \boldsymbol{x}\vert\vert_1 = \sum_i \vert x_i\vert.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="deriving-the-ridge-regression-equations">Deriving the Ridge Regression Equations </h2>
<p>Using the matrix-vector expression for Ridge regression and dropping the parameter \( 1/n \) in front of the standard means squared error equation, we have</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\left\{(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})\right\}+\lambda\boldsymbol{\theta}^T\boldsymbol{\theta},
$$
<p>and
taking the derivatives with respect to \( \boldsymbol{\theta} \) we obtain then
a slightly modified matrix inversion problem which for finite values
of \( \lambda \) does not suffer from singularity problems. We obtain
the optimal parameters
</p>
$$
\hat{\boldsymbol{\theta}}_{\mathrm{Ridge}} = \left(\boldsymbol{X}^T\boldsymbol{X}+\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y},
$$
<p>with \( \boldsymbol{I} \) being a \( p\times p \) identity matrix with the constraint that</p>
$$
\sum_{i=0}^{p-1} \theta_i^2 \leq t,
$$
<p>with \( t \) a finite positive number. </p>
<p>If we keep the \( 1/n \) factor, the equation for the optimal \( \theta \) changes to</p>
$$
\hat{\boldsymbol{\theta}}_{\mathrm{Ridge}} = \left(\boldsymbol{X}^T\boldsymbol{X}+n\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>In many textbooks the \( 1/n \) term is often omitted. Note that a library like <b>Scikit-Learn</b> does not include the \( 1/n \) factor in the setup of the cost function.</p>
<p>When we compare this with the ordinary least squares result we have</p>
$$
\hat{\boldsymbol{\theta}}_{\mathrm{OLS}} = \left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y},
$$
<p>which can lead to singular matrices. However, with the SVD, we can always compute the inverse of the matrix \( \boldsymbol{X}^T\boldsymbol{X} \).</p>
<p>We see that Ridge regression is nothing but the standard OLS with a
modified diagonal term added to \( \boldsymbol{X}^T\boldsymbol{X} \). The consequences, in
particular for our discussion of the bias-variance tradeoff are rather
interesting. We will see that for specific values of \( \lambda \), we may
even reduce the variance of the optimal parameters \( \boldsymbol{\theta} \). These topics and other related ones, will be discussed after the more linear algebra oriented analysis here.
</p>
<p>When we have discussed the singular value decomposition of the design
matrix \( \boldsymbol{X} \), we will in turn perform a more rigorous mathematical
discussion of Ridge regression.
</p>
<p>The code here is a simple demonstration of how to implement Ridge regression with our own code and compare this with scikit-learn.</p>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">pandas</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">pd</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.model_selection</span> <span style="color: #8B008B; font-weight: bold">import</span> train_test_split
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn</span> <span style="color: #8B008B; font-weight: bold">import</span> linear_model
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">MSE</span>(y_data,y_model):
n = np.size(y_model)
<span style="color: #8B008B; font-weight: bold">return</span> np.sum((y_data-y_model)**<span style="color: #B452CD">2</span>)/n
<span style="color: #228B22"># A seed just to ensure that the random numbers are the same for every run.</span>
<span style="color: #228B22"># Useful for eventual debugging.</span>
np.random.seed(<span style="color: #B452CD">3155</span>)
n = <span style="color: #B452CD">100</span>
x = np.random.rand(n)
y = np.exp(-x**<span style="color: #B452CD">2</span>) + <span style="color: #B452CD">1.5</span> * np.exp(-(x-<span style="color: #B452CD">2</span>)**<span style="color: #B452CD">2</span>)
Maxpolydegree = <span style="color: #B452CD">20</span>
X = np.zeros((n,Maxpolydegree))
<span style="color: #228B22">#We include explicitely the intercept column</span>
<span style="color: #8B008B; font-weight: bold">for</span> degree <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(Maxpolydegree):
X[:,degree] = x**degree
<span style="color: #228B22"># We split the data in test and training data</span>
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=<span style="color: #B452CD">0.2</span>)
p = Maxpolydegree
I = np.eye(p,p)
<span style="color: #228B22"># Decide which values of lambda to use</span>
nlambdas = <span style="color: #B452CD">6</span>
MSEOwnRidgePredict = np.zeros(nlambdas)
MSERidgePredict = np.zeros(nlambdas)
lambdas = np.logspace(-<span style="color: #B452CD">4</span>, <span style="color: #B452CD">2</span>, nlambdas)
<span style="color: #8B008B; font-weight: bold">for</span> i <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(nlambdas):
lmb = lambdas[i]
OwnRidgeTheta = np.linalg.pinv(X_train.T @ X_train+lmb*I) @ X_train.T @ y_train
<span style="color: #228B22"># Note: we include the intercept column and no scaling</span>
RegRidge = linear_model.Ridge(lmb,fit_intercept=<span style="color: #8B008B; font-weight: bold">False</span>)
RegRidge.fit(X_train,y_train)
<span style="color: #228B22"># and then make the prediction</span>
ytildeOwnRidge = X_train @ OwnRidgeTheta
ypredictOwnRidge = X_test @ OwnRidgeTheta
ytildeRidge = RegRidge.predict(X_train)
ypredictRidge = RegRidge.predict(X_test)
MSEOwnRidgePredict[i] = MSE(y_test,ypredictOwnRidge)
MSERidgePredict[i] = MSE(y_test,ypredictRidge)
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;Theta values for own Ridge implementation&quot;</span>)
<span style="color: #658b00">print</span>(OwnRidgeTheta)
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;Theta values for Scikit-Learn Ridge implementation&quot;</span>)
<span style="color: #658b00">print</span>(RegRidge.coef_)
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;MSE values for own Ridge implementation&quot;</span>)
<span style="color: #658b00">print</span>(MSEOwnRidgePredict[i])
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;MSE values for Scikit-Learn Ridge implementation&quot;</span>)
<span style="color: #658b00">print</span>(MSERidgePredict[i])
<span style="color: #228B22"># Now plot the results</span>
plt.figure()
plt.plot(np.log10(lambdas), MSEOwnRidgePredict, <span style="color: #CD5555">&#39;r&#39;</span>, label = <span style="color: #CD5555">&#39;MSE own Ridge Test&#39;</span>)
plt.plot(np.log10(lambdas), MSERidgePredict, <span style="color: #CD5555">&#39;g&#39;</span>, label = <span style="color: #CD5555">&#39;MSE Ridge Test&#39;</span>)
plt.xlabel(<span style="color: #CD5555">&#39;log10(lambda)&#39;</span>)
plt.ylabel(<span style="color: #CD5555">&#39;MSE&#39;</span>)
plt.legend()
plt.show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>The results here agree when we force <b>Scikit-Learn</b>'s Ridge function to include the first column in our design matrix.
We see that the results agree very well. Here we have thus explicitely included the intercept column in the design matrix.
What happens if we do not include the intercept in our fit? We will discuss this in more detail next week.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="basic-math-of-the-svd">Basic math of the SVD </h2>
<p>From standard linear algebra we know that a square matrix \( \boldsymbol{X} \) can be diagonalized if and only if it is
a so-called <a href="https://en.wikipedia.org/wiki/Normal_matrix" target="_blank">normal matrix</a>, that is if \( \boldsymbol{X}\in {\mathbb{R}}^{n\times n} \)
we have \( \boldsymbol{X}\boldsymbol{X}^T=\boldsymbol{X}^T\boldsymbol{X} \) or if \( \boldsymbol{X}\in {\mathbb{C}}^{n\times n} \) we have \( \boldsymbol{X}\boldsymbol{X}^{\dagger}=\boldsymbol{X}^{\dagger}\boldsymbol{X} \).
The matrix has then a set of eigenpairs
</p>
$$
(\lambda_1,\boldsymbol{u}_1),\dots, (\lambda_n,\boldsymbol{u}_n),
$$
<p>and the eigenvalues are given by the diagonal matrix</p>
$$
\boldsymbol{\Sigma}=\mathrm{Diag}(\lambda_1, \dots,\lambda_n).
$$
<p>The matrix \( \boldsymbol{X} \) can be written in terms of an orthogonal/unitary transformation \( \boldsymbol{U} \)</p>
$$
\boldsymbol{X} = \boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T,
$$
<p>with \( \boldsymbol{U}\boldsymbol{U}^T=\boldsymbol{I} \) or \( \boldsymbol{U}\boldsymbol{U}^{\dagger}=\boldsymbol{I} \).</p>
<p>Not all square matrices are diagonalizable. A matrix like the one discussed above</p>
$$
\boldsymbol{X} = \begin{bmatrix}
1& -1 \\
1& -1\\
\end{bmatrix}
$$
<p>is not diagonalizable, it is a so-called <a href="https://en.wikipedia.org/wiki/Defective_matrix" target="_blank">defective matrix</a>. It is easy to see that the condition
\( \boldsymbol{X}\boldsymbol{X}^T=\boldsymbol{X}^T\boldsymbol{X} \) is not fulfilled.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-svd-a-fantastic-algorithm">The SVD, a Fantastic Algorithm </h2>
<p>However, and this is the strength of the SVD algorithm, any general
matrix \( \boldsymbol{X} \) can be decomposed in terms of a diagonal matrix and
two orthogonal/unitary matrices. The <a href="https://en.wikipedia.org/wiki/Singular_value_decomposition" target="_blank">Singular Value Decompostion
(SVD) theorem</a>
states that a general \( m\times n \) matrix \( \boldsymbol{X} \) can be written in
terms of a diagonal matrix \( \boldsymbol{\Sigma} \) of dimensionality \( m\times n \)
and two orthognal matrices \( \boldsymbol{U} \) and \( \boldsymbol{V} \), where the first has
dimensionality \( m \times m \) and the last dimensionality \( n\times n \).
We have then
</p>
$$
\boldsymbol{X} = \boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T
$$
<p>As an example, the above defective matrix can be decomposed as</p>
$$
\boldsymbol{X} = \frac{1}{\sqrt{2}}\begin{bmatrix} 1& 1 \\ 1& -1\\ \end{bmatrix} \begin{bmatrix} 2& 0 \\ 0& 0\\ \end{bmatrix} \frac{1}{\sqrt{2}}\begin{bmatrix} 1& -1 \\ 1& 1\\ \end{bmatrix}=\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T,
$$
<p>with eigenvalues \( \sigma_1=2 \) and \( \sigma_2=0 \).
The SVD exits always!
</p>
<p>The SVD
decomposition (singular values) gives eigenvalues
\( \sigma_i\geq\sigma_{i+1} \) for all \( i \) and for dimensions larger than \( i=p \), the
eigenvalues (singular values) are zero.
</p>
<p>In the general case, where our design matrix \( \boldsymbol{X} \) has dimension
\( n\times p \), the matrix is thus decomposed into an \( n\times n \)
orthogonal matrix \( \boldsymbol{U} \), a \( p\times p \) orthogonal matrix \( \boldsymbol{V} \)
and a diagonal matrix \( \boldsymbol{\Sigma} \) with \( r=\mathrm{min}(n,p) \)
singular values \( \sigma_i\geq 0 \) on the main diagonal and zeros filling
the rest of the matrix. There are at most \( p \) singular values
assuming that \( n > p \). In our regression examples for the nuclear
masses and the equation of state this is indeed the case, while for
the Ising model we have \( p > n \). These are often cases that lead to
near singular or singular matrices.
</p>
<p>The columns of \( \boldsymbol{U} \) are called the left singular vectors while the columns of \( \boldsymbol{V} \) are the right singular vectors.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="economy-size-svd">Economy-size SVD </h2>
<p>If we assume that \( n > p \), then our matrix \( \boldsymbol{U} \) has dimension \( n
\times n \). The last \( n-p \) columns of \( \boldsymbol{U} \) become however
irrelevant in our calculations since they are multiplied with the
zeros in \( \boldsymbol{\Sigma} \).
</p>
<p>The economy-size decomposition removes extra rows or columns of zeros
from the diagonal matrix of singular values, \( \boldsymbol{\Sigma} \), along with the columns
in either \( \boldsymbol{U} \) or \( \boldsymbol{V} \) that multiply those zeros in the expression.
Removing these zeros and columns can improve execution time
and reduce storage requirements without compromising the accuracy of
the decomposition.
</p>
<p>If \( n > p \), we keep only the first \( p \) columns of \( \boldsymbol{U} \) and \( \boldsymbol{\Sigma} \) has dimension \( p\times p \).
If \( p > n \), then only the first \( n \) columns of \( \boldsymbol{V} \) are computed and \( \boldsymbol{\Sigma} \) has dimension \( n\times n \).
The \( n=p \) case is obvious, we retain the full SVD.
In general the economy-size SVD leads to less FLOPS and still conserving the desired accuracy.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="codes-for-the-svd">Codes for the SVD </h2>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #228B22"># SVD inversion</span>
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">SVD</span>(A):
<span style="color: #CD5555">&#39;&#39;&#39; Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).</span>
<span style="color: #CD5555"> SVD is numerically more stable than the inversion algorithms provided by</span>
<span style="color: #CD5555"> numpy and scipy.linalg at the cost of being slower.</span>
<span style="color: #CD5555"> &#39;&#39;&#39;</span>
U, S, VT = np.linalg.svd(A,full_matrices=<span style="color: #8B008B; font-weight: bold">True</span>)
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&#39;test U&#39;</span>)
<span style="color: #658b00">print</span>( (np.transpose(U) @ U - U <span style="color: #707a7c">@np</span>.transpose(U)))
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&#39;test VT&#39;</span>)
<span style="color: #658b00">print</span>( (np.transpose(VT) @ VT - VT <span style="color: #707a7c">@np</span>.transpose(VT)))
<span style="color: #658b00">print</span>(U)
<span style="color: #658b00">print</span>(S)
<span style="color: #658b00">print</span>(VT)
D = np.zeros((<span style="color: #658b00">len</span>(U),<span style="color: #658b00">len</span>(VT)))
<span style="color: #8B008B; font-weight: bold">for</span> i <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(<span style="color: #B452CD">0</span>,<span style="color: #658b00">len</span>(VT)):
D[i,i]=S[i]
<span style="color: #8B008B; font-weight: bold">return</span> U @ D @ VT
X = np.array([ [<span style="color: #B452CD">1.0</span>,-<span style="color: #B452CD">1.0</span>], [<span style="color: #B452CD">1.0</span>,-<span style="color: #B452CD">1.0</span>]])
<span style="color: #228B22">#X = np.array([[1, 2], [3, 4], [5, 6]])</span>
<span style="color: #658b00">print</span>(X)
C = SVD(X)
<span style="color: #228B22"># Print the difference between the original matrix and the SVD one</span>
<span style="color: #658b00">print</span>(C-X)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>The matrix \( \boldsymbol{X} \) has columns that are linearly dependent. The first
column is the row-wise sum of the other two columns. The rank of a
matrix (the column rank) is the dimension of space spanned by the
column vectors. The rank of the matrix is the number of linearly
independent columns, in this case just \( 2 \). We see this from the
singular values when running the above code. Running the standard
inversion algorithm for matrix inversion with \( \boldsymbol{X}^T\boldsymbol{X} \) results
in the program terminating due to a singular matrix.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="note-about-svd-calculations">Note about SVD Calculations </h2>
<p>The \( U \), \( S \), and \( V \) matrices returned from the <b>svd()</b> function
cannot be multiplied directly.
</p>
<p>As you can see from the code, the \( S \) vector must be converted into a
diagonal matrix. This may cause a problem as the size of the matrices
do not fit the rules of matrix multiplication, where the number of
columns in a matrix must match the number of rows in the subsequent
matrix.
</p>
<p>If you wish to include the zero singular values, you will need to
resize the matrices and set up a diagonal matrix as done in the above
example
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematics-of-the-svd-and-implications">Mathematics of the SVD and implications </h2>
<p>Let us take a closer look at the mathematics of the SVD and the various implications for machine learning studies.</p>
<p>Our starting point is our design matrix \( \boldsymbol{X} \) of dimension \( n\times p \)</p>
$$
\boldsymbol{X}=\begin{bmatrix}
x_{0,0} & x_{0,1} & x_{0,2}& \dots & \dots x_{0,p-1}\\
x_{1,0} & x_{1,1} & x_{1,2}& \dots & \dots x_{1,p-1}\\
x_{2,0} & x_{2,1} & x_{2,2}& \dots & \dots x_{2,p-1}\\
\dots & \dots & \dots & \dots \dots & \dots \\
x_{n-2,0} & x_{n-2,1} & x_{n-2,2}& \dots & \dots x_{n-2,p-1}\\
x_{n-1,0} & x_{n-1,1} & x_{n-1,2}& \dots & \dots x_{n-1,p-1}\\
\end{bmatrix}.
$$
<p>We can SVD decompose our matrix as</p>
$$
\boldsymbol{X}=\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T,
$$
<p>where \( \boldsymbol{U} \) is an orthogonal matrix of dimension \( n\times n \), meaning that \( \boldsymbol{U}\boldsymbol{U}^T=\boldsymbol{U}^T\boldsymbol{U}=\boldsymbol{I}_n \). Here \( \boldsymbol{I}_n \) is the unit matrix of dimension \( n \times n \).</p>
<p>Similarly, \( \boldsymbol{V} \) is an orthogonal matrix of dimension \( p\times p \), meaning that \( \boldsymbol{V}\boldsymbol{V}^T=\boldsymbol{V}^T\boldsymbol{V}=\boldsymbol{I}_p \). Here \( \boldsymbol{I}_n \) is the unit matrix of dimension \( p \times p \).</p>
<p>Finally \( \boldsymbol{\Sigma} \) contains the singular values \( \sigma_i \). This matrix has dimension \( n\times p \) and the singular values \( \sigma_i \) are all positive. The non-zero values are ordered in descending order, that is</p>
$$
\sigma_0 > \sigma_1 > \sigma_2 > \dots > \sigma_{p-1} > 0.
$$
<p>All values beyond \( p-1 \) are all zero.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="example-matrix">Example Matrix </h2>
<p>As an example, consider the following \( 3\times 2 \) example for the matrix \( \boldsymbol{\Sigma} \)</p>
$$
\boldsymbol{\Sigma}=
\begin{bmatrix}
2& 0 \\
0 & 1 \\
0 & 0 \\
\end{bmatrix}
$$
<p>The singular values are \( \sigma_0=2 \) and \( \sigma_1=1 \). It is common to rewrite the matrix \( \boldsymbol{\Sigma} \) as</p>
$$
\boldsymbol{\Sigma}=
\begin{bmatrix}
\boldsymbol{\tilde{\Sigma}}\\
\boldsymbol{0}\\
\end{bmatrix},
$$
<p>where</p>
$$
\boldsymbol{\tilde{\Sigma}}=
\begin{bmatrix}
2& 0 \\
0 & 1 \\
\end{bmatrix},
$$
<p>contains only the singular values. Note also (and we will use this below) that</p>
$$
\boldsymbol{\Sigma}^T\boldsymbol{\Sigma}=
\begin{bmatrix}
4& 0 \\
0 & 1 \\
\end{bmatrix},
$$
<p>which is a \( 2\times 2 \) matrix while</p>
$$
\boldsymbol{\Sigma}\boldsymbol{\Sigma}^T=
\begin{bmatrix}
4& 0 & 0\\
0 & 1 & 0\\
0 & 0 & 0\\
\end{bmatrix},
$$
<p>is a \( 3\times 3 \) matrix. The last row and column of this last matrix
contain only zeros. This will have important consequences for our SVD
decomposition of the design matrix.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="setting-up-the-matrix-to-be-inverted">Setting up the Matrix to be inverted </h2>
<p>The matrix that may cause problems for us is \( \boldsymbol{X}^T\boldsymbol{X} \). Using the SVD we can rewrite this matrix as</p>
$$
\boldsymbol{X}^T\boldsymbol{X}=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{U}^T\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T,
$$
<p>and using the orthogonality of the matrix \( \boldsymbol{U} \) we have</p>
$$
\boldsymbol{X}^T\boldsymbol{X}=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{\Sigma}\boldsymbol{V}^T.
$$
<p>We define \( \boldsymbol{\Sigma}^T\boldsymbol{\Sigma}=\tilde{\boldsymbol{\Sigma}}^2 \) which is a diagonal matrix containing only the singular values squared. It has dimensionality \( p \times p \).</p>
<p>We can now insert the result for the matrix \( \boldsymbol{X}^T\boldsymbol{X} \) into our equation for ordinary least squares where</p>
$$
\tilde{y}_{\mathrm{OLS}}=\boldsymbol{X}\left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y},
$$
<p>and using our SVD decomposition of \( \boldsymbol{X} \) we have</p>
$$
\tilde{y}_{\mathrm{OLS}}=\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T\left(\boldsymbol{V}\tilde{\boldsymbol{\Sigma}}^{2}(\boldsymbol{V}^T\right)^{-1}\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{U}^T\boldsymbol{y},
$$
<p>which gives us, using the orthogonality of the matrix \( \boldsymbol{V} \),</p>
$$
\tilde{y}_{\mathrm{OLS}}=\sum_{i=0}^{p-1}\boldsymbol{u}_i\boldsymbol{u}^T_i\boldsymbol{y},
$$
<p>which is not the same as \( \tilde{y}_{\mathrm{OLS}}=\boldsymbol{U}\boldsymbol{U}^T\boldsymbol{y} \), which due to the orthogonality of \( \boldsymbol{U} \) would have given us that the model equals the output.</p>
<p>It means that the ordinary least square model (with the optimal
parameters) \( \boldsymbol{\tilde{y}} \), corresponds to an orthogonal
transformation of the output (or target) vector \( \boldsymbol{y} \) by the
vectors of the matrix \( \boldsymbol{U} \). <b>Note that the summation ends at</b>
\( p-1 \), that is \( \boldsymbol{\tilde{y}}\ne \boldsymbol{y} \). We can thus not use the
orthogonality relation for the matrix \( \boldsymbol{U} \).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="further-properties-important-for-our-analyses-later">Further properties (important for our analyses later) </h2>
<p>Let us study again \( \boldsymbol{X}^T\boldsymbol{X} \) in terms of our SVD,</p>
$$
\boldsymbol{X}^T\boldsymbol{X}=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{U}^T\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{\Sigma}\boldsymbol{V}^T.
$$
<p>If we now multiply from the right with \( \boldsymbol{V} \) (using the orthogonality of \( \boldsymbol{V} \)) we get</p>
$$
\left(\boldsymbol{X}^T\boldsymbol{X}\right)\boldsymbol{V}=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{\Sigma}.
$$
<p>This means the vectors \( \boldsymbol{v}_i \) of the orthogonal matrix \( \boldsymbol{V} \) are the eigenvectors of the matrix \( \boldsymbol{X}^T\boldsymbol{X} \)
with eigenvalues given by the singular values squared, that is
</p>
$$
\left(\boldsymbol{X}^T\boldsymbol{X}\right)\boldsymbol{v}_i=\boldsymbol{v}_i\sigma_i^2.
$$
<p>Similarly, if we use the SVD decomposition for the matrix \( \boldsymbol{X}\boldsymbol{X}^T \), we have</p>
$$
\boldsymbol{X}\boldsymbol{X}^T=\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{U}^T=\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{\Sigma}^T\boldsymbol{U}^T.
$$
<p>If we now multiply from the right with \( \boldsymbol{U} \) (using the orthogonality of \( \boldsymbol{U} \)) we get</p>
$$
\left(\boldsymbol{X}\boldsymbol{X}^T\right)\boldsymbol{U}=\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{\Sigma}^T.
$$
<p>This means the vectors \( \boldsymbol{u}_i \) of the orthogonal matrix \( \boldsymbol{U} \) are the eigenvectors of the matrix \( \boldsymbol{X}\boldsymbol{X}^T \)
with eigenvalues given by the singular values squared, that is
</p>
$$
\left(\boldsymbol{X}\boldsymbol{X}^T\right)\boldsymbol{u}_i=\boldsymbol{u}_i\sigma_i^2.
$$
<p><b>Important note</b>: we have defined our design matrix \( \boldsymbol{X} \) to be an
\( n\times p \) matrix. In most supervised learning cases we have that \( n
\ge p \), and quite often we have \( n >> p \). For linear algebra based methods like ordinary least squares or Ridge regression, this leads to a matrix \( \boldsymbol{X}^T\boldsymbol{X} \) which is small and thereby easier to handle from a computational point of view (in terms of number of floating point operations).
</p>
<p>In our lectures, the number of columns will
always refer to the number of features in our data set, while the
number of rows represents the number of data inputs. Note that in
other texts you may find the opposite notation. This has consequences
for the definition of for example the covariance matrix and its relation to the SVD.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="back-to-ridge-and-lasso-regression">Back to Ridge and LASSO Regression </h2>
<p>Let us remind ourselves about the expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, that is
our optimization problem is
</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in {\mathbb{R}}^{p}}}\frac{1}{n}\left\{\left(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\right)^T\left(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\right)\right\}.
$$
<p>or we can state it as</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\sum_{i=0}^{n-1}\left(y_i-\tilde{y}_i\right)^2=\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2,
$$
<p>where we have used the definition of a norm-2 vector, that is</p>
$$
\vert\vert \boldsymbol{x}\vert\vert_2 = \sqrt{\sum_i x_i^2}.
$$
<p>By minimizing the above equation with respect to the parameters
\( \boldsymbol{\theta} \) we could then obtain an analytical expression for the
parameters \( \boldsymbol{\theta} \). We can add a regularization parameter \( \lambda \) by
defining a new cost function to be optimized, that is
</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_2^2
$$
<p>which leads to the Ridge regression minimization problem where we
require that \( \vert\vert \boldsymbol{\theta}\vert\vert_2^2\le t \), where \( t \) is
a finite number larger than zero. By defining
</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_1,
$$
<p>we have a new optimization equation</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_1
$$
<p>which leads to Lasso regression. Lasso stands for least absolute shrinkage and selection operator. </p>
<p>Here we have defined the norm-1 as </p>
$$
\vert\vert \boldsymbol{x}\vert\vert_1 = \sum_i \vert x_i\vert.
$$
<p>Ridge regression, as discussed above, is nothing but the standard OLS with a
modified diagonal term added to \( \boldsymbol{X}^T\boldsymbol{X} \). The consequences, in
particular for our discussion of the bias-variance tradeoff are rather
interesting. We will see that for specific values of \( \lambda \), we may
even reduce the variance of the optimal parameters \( \boldsymbol{\theta} \). These topics and other related ones, will be discussed after the more linear algebra oriented analysis here.
</p>
<p>Using our insights about the SVD of the design matrix \( \boldsymbol{X} \)
We have already analyzed the OLS solutions in terms of the eigenvectors (the columns) of the right singular value matrix \( \boldsymbol{U} \) as
</p>
$$
\tilde{\boldsymbol{y}}_{\mathrm{OLS}}=\boldsymbol{X}\boldsymbol{\theta} =\boldsymbol{U}\boldsymbol{U}^T\boldsymbol{y}.
$$
<p>For Ridge regression this becomes</p>
$$
\tilde{\boldsymbol{y}}_{\mathrm{Ridge}}=\boldsymbol{X}\boldsymbol{\theta}_{\mathrm{Ridge}} = \boldsymbol{U\Sigma V^T}\left(\boldsymbol{V}\boldsymbol{\Sigma}^2\boldsymbol{V}^T+\lambda\boldsymbol{I} \right)^{-1}(\boldsymbol{U\Sigma V^T})^T\boldsymbol{y}=\sum_{j=0}^{p-1}\boldsymbol{u}_j\boldsymbol{u}_j^T\frac{\sigma_j^2}{\sigma_j^2+\lambda}\boldsymbol{y},
$$
<p>with the vectors \( \boldsymbol{u}_j \) being the columns of \( \boldsymbol{U} \) from the SVD of the matrix \( \boldsymbol{X} \). </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="interpreting-the-ridge-results">Interpreting the Ridge results </h2>
<p>Since \( \lambda \geq 0 \), it means that compared to OLS, we have </p>
$$
\frac{\sigma_j^2}{\sigma_j^2+\lambda} \leq 1.
$$
<p>Ridge regression finds the coordinates of \( \boldsymbol{y} \) with respect to the
orthonormal basis \( \boldsymbol{U} \), it then shrinks the coordinates by
\( \frac{\sigma_j^2}{\sigma_j^2+\lambda} \). Recall that the SVD has
eigenvalues ordered in a descending way, that is \( \sigma_i \geq
\sigma_{i+1} \).
</p>
<p>For small eigenvalues \( \sigma_i \) it means that their contributions become less important, a fact which can be used to reduce the number of degrees of freedom. More about this when we have covered the material on a statistical interpretation of various linear regression methods.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-interpretations">More interpretations </h2>
<p>For the sake of simplicity, let us assume that the design matrix is orthonormal, that is </p>
$$
\boldsymbol{X}^T\boldsymbol{X}=(\boldsymbol{X}^T\boldsymbol{X})^{-1} =\boldsymbol{I}.
$$
<p>In this case the standard OLS results in </p>
$$
\boldsymbol{\theta}^{\mathrm{OLS}} = \boldsymbol{X}^T\boldsymbol{y},
$$
<p>and</p>
$$
\boldsymbol{\theta}^{\mathrm{Ridge}} = \left(\boldsymbol{I}+\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}=\left(1+\lambda\right)^{-1}\boldsymbol{\theta}^{\mathrm{OLS}},
$$
<p>that is the Ridge estimator scales the OLS estimator by the inverse of a factor \( 1+\lambda \), and
the Ridge estimator converges to zero when the hyperparameter goes to
infinity.
</p>
<p>We will come back to more interpretions after we have gone through some of the statistical analysis part. </p>
<p>For more discussions of Ridge and Lasso regression, <a href="https://arxiv.org/abs/1509.09169" target="_blank">Wessel van Wieringen's</a> article is highly recommended.
Similarly, <a href="https://arxiv.org/abs/1803.08823" target="_blank">Mehta et al's article</a> is also recommended.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="deriving-the-lasso-regression-equations">Deriving the Lasso Regression Equations </h2>
<p>Using the matrix-vector expression for Lasso regression, we have the following <b>cost</b> function</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\frac{1}{n}\left\{(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})\right\}+\lambda\vert\vert\boldsymbol{\theta}\vert\vert_1,
$$
<p>Taking the derivative with respect to \( \boldsymbol{\theta} \) and recalling that the derivative of the absolute value is (we drop the boldfaced vector symbol for simplicty)</p>
$$
\frac{d \vert \theta\vert}{d \theta}=\mathrm{sgn}(\theta)=\left\{\begin{array}{cc} 1 & \theta > 0 \\-1 & \theta < 0, \end{array}\right.
$$
<p>we have that the derivative of the cost function is</p>
$$
\frac{\partial C(\boldsymbol{X},\boldsymbol{\theta})}{\partial \boldsymbol{\theta}}=-\frac{2}{n}\boldsymbol{X}^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})+\lambda sgn(\boldsymbol{\theta})=0,
$$
<p>and reordering we have</p>
$$
\boldsymbol{X}^T\boldsymbol{X}\boldsymbol{\theta}+\frac{n}{2}\lambda sgn(\boldsymbol{\theta})=\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>We can redefine \( \lambda \) to absorb the constant \( n/2 \) and we rewrite the last equation as</p>
$$
\boldsymbol{X}^T\boldsymbol{X}\boldsymbol{\theta}+\lambda sgn(\boldsymbol{\theta})=\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>This equation does not lead to a nice analytical equation as in either Ridge regression or ordinary least squares. This equation can however be solved by using standard convex optimization algorithms.We will discuss how to code the above methods using gradient descent methods.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="optimization-and-gradient-descent-the-central-part-of-any-machine-learning-algortithm">Optimization and gradient descent, the central part of any Machine Learning algortithm </h2>
<p>Almost every problem in machine learning and data science starts with
a dataset \( X \), a model \( g(\theta) \), which is a function of the
parameters \( \theta \) and a cost function \( C(X, g(\theta)) \) that allows
us to judge how well the model \( g(\theta) \) explains the observations
\( X \). The model is fit by finding the values of \( \theta \) that minimize
the cost function. Ideally we would be able to solve for \( \theta \)
analytically, however this is not possible in general and we must use
some approximative/numerical method to compute the minimum.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="reminder-on-newton-raphson-s-method">Reminder on Newton-Raphson's method </h2>
<p>Let us quickly remind ourselves how we derive the above method.</p>
<p>Perhaps the most celebrated of all one-dimensional root-finding
routines is Newton's method, also called the Newton-Raphson
method. This method requires the evaluation of both the
function \( f \) and its derivative \( f' \) at arbitrary points.
If you can only calculate the derivative
numerically and/or your function is not of the smooth type, we
normally discourage the use of this method.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-equations">The equations </h2>
<p>The Newton-Raphson formula consists geometrically of extending the
tangent line at a current point until it crosses zero, then setting
the next guess to the abscissa of that zero-crossing. The mathematics
behind this method is rather simple. Employing a Taylor expansion for
\( x \) sufficiently close to the solution \( s \), we have
</p>
$$
f(s)=0=f(x)+(s-x)f'(x)+\frac{(s-x)^2}{2}f''(x) +\dots.
\label{eq:taylornr}
$$
<p>For small enough values of the function and for well-behaved
functions, the terms beyond linear are unimportant, hence we obtain
</p>
$$
f(x)+(s-x)f'(x)\approx 0,
$$
<p>yielding</p>
$$
s\approx x-\frac{f(x)}{f'(x)}.
$$
<p>Having in mind an iterative procedure, it is natural to start iterating with</p>
$$
x_{n+1}=x_n-\frac{f(x_n)}{f'(x_n)}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="simple-geometric-interpretation">Simple geometric interpretation </h2>
<p>The above is Newton-Raphson's method. It has a simple geometric
interpretation, namely \( x_{n+1} \) is the point where the tangent from
\( (x_n,f(x_n)) \) crosses the \( x \)-axis. Close to the solution,
Newton-Raphson converges fast to the desired result. However, if we
are far from a root, where the higher-order terms in the series are
important, the Newton-Raphson formula can give grossly inaccurate
results. For instance, the initial guess for the root might be so far
from the true root as to let the search interval include a local
maximum or minimum of the function. If an iteration places a trial
guess near such a local extremum, so that the first derivative nearly
vanishes, then Newton-Raphson may fail totally
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="extending-to-more-than-one-variable">Extending to more than one variable </h2>
<p>Newton's method can be generalized to systems of several non-linear equations
and variables. Consider the case with two equations
</p>
$$
\begin{array}{cc} f_1(x_1,x_2) &=0\\
f_2(x_1,x_2) &=0,\end{array}
$$
<p>which we Taylor expand to obtain</p>
$$
\begin{array}{cc} 0=f_1(x_1+h_1,x_2+h_2)=&f_1(x_1,x_2)+h_1
\partial f_1/\partial x_1+h_2
\partial f_1/\partial x_2+\dots\\
0=f_2(x_1+h_1,x_2+h_2)=&f_2(x_1,x_2)+h_1
\partial f_2/\partial x_1+h_2
\partial f_2/\partial x_2+\dots
\end{array}.
$$
<p>Defining the Jacobian matrix \( {\bf \boldsymbol{J}} \) we have</p>
$$
{\bf \boldsymbol{J}}=\left( \begin{array}{cc}
\partial f_1/\partial x_1 & \partial f_1/\partial x_2 \\
\partial f_2/\partial x_1 &\partial f_2/\partial x_2
\end{array} \right),
$$
<p>we can rephrase Newton's method as</p>
$$
\left(\begin{array}{c} x_1^{n+1} \\ x_2^{n+1} \end{array} \right)=
\left(\begin{array}{c} x_1^{n} \\ x_2^{n} \end{array} \right)+
\left(\begin{array}{c} h_1^{n} \\ h_2^{n} \end{array} \right),
$$
<p>where we have defined</p>
$$
\left(\begin{array}{c} h_1^{n} \\ h_2^{n} \end{array} \right)=
-{\bf \boldsymbol{J}}^{-1}
\left(\begin{array}{c} f_1(x_1^{n},x_2^{n}) \\ f_2(x_1^{n},x_2^{n}) \end{array} \right).
$$
<p>We need thus to compute the inverse of the Jacobian matrix and it
is to understand that difficulties may
arise in case \( {\bf \boldsymbol{J}} \) is nearly singular.
</p>
<p>It is rather straightforward to extend the above scheme to systems of
more than two non-linear equations. In our case, the Jacobian matrix is given by the Hessian that represents the second derivative of cost function.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="steepest-descent">Steepest descent </h2>
<p>The basic idea of gradient descent is
that a function \( F(\mathbf{x}) \),
\( \mathbf{x} \equiv (x_1,\cdots,x_n) \), decreases fastest if one goes from \( \bf {x} \) in the
direction of the negative gradient \( -\nabla F(\mathbf{x}) \).
</p>
<p>It can be shown that if </p>
$$
\mathbf{x}_{k+1} = \mathbf{x}_k - \gamma_k \nabla F(\mathbf{x}_k),
$$
<p>with \( \gamma_k > 0 \).</p>
<p>For \( \gamma_k \) small enough, then \( F(\mathbf{x}_{k+1}) \leq
F(\mathbf{x}_k) \). This means that for a sufficiently small \( \gamma_k \)
we are always moving towards smaller function values, i.e a minimum.
</p>
<!-- !split -->
<h2 id="more-on-steepest-descent">More on Steepest descent </h2>
<p>The previous observation is the basis of the method of steepest
descent, which is also referred to as just gradient descent (GD). One
starts with an initial guess \( \mathbf{x}_0 \) for a minimum of \( F \) and
computes new approximations according to
</p>
$$
\mathbf{x}_{k+1} = \mathbf{x}_k - \gamma_k \nabla F(\mathbf{x}_k), \ \ k \geq 0.
$$
<p>The parameter \( \gamma_k \) is often referred to as the step length or
the learning rate within the context of Machine Learning.
</p>
<!-- !split -->
<h2 id="the-ideal">The ideal </h2>
<p>Ideally the sequence \( \{\mathbf{x}_k \}_{k=0} \) converges to a global
minimum of the function \( F \). In general we do not know if we are in a
global or local minimum. In the special case when \( F \) is a convex
function, all local minima are also global minima, so in this case
gradient descent can converge to the global solution. The advantage of
this scheme is that it is conceptually simple and straightforward to
implement. However the method in this form has some severe
limitations:
</p>
<p>In machine learing we are often faced with non-convex high dimensional
cost functions with many local minima. Since GD is deterministic we
will get stuck in a local minimum, if the method converges, unless we
have a very good intial guess. This also implies that the scheme is
sensitive to the chosen initial condition.
</p>
<p>Note that the gradient is a function of \( \mathbf{x} =
(x_1,\cdots,x_n) \) which makes it expensive to compute numerically.
</p>
<!-- !split -->
<h2 id="the-sensitiveness-of-the-gradient-descent">The sensitiveness of the gradient descent </h2>
<p>The gradient descent method
is sensitive to the choice of learning rate \( \gamma_k \). This is due
to the fact that we are only guaranteed that \( F(\mathbf{x}_{k+1}) \leq
F(\mathbf{x}_k) \) for sufficiently small \( \gamma_k \). The problem is to
determine an optimal learning rate. If the learning rate is chosen too
small the method will take a long time to converge and if it is too
large we can experience erratic behavior.
</p>
<p>Many of these shortcomings can be alleviated by introducing
randomness. One such method is that of Stochastic Gradient Descent
(SGD), to be discussed next week.
</p>
<!-- !split -->
<h2 id="convex-functions">Convex functions </h2>
<p>Ideally we want our cost/loss function to be convex(concave).</p>
<p>First we give the definition of a convex set: A set \( C \) in
\( \mathbb{R}^n \) is said to be convex if, for all \( x \) and \( y \) in \( C \) and
all \( t \in (0,1) \) , the point \( (1 &#8722; t)x + ty \) also belongs to
C. Geometrically this means that every point on the line segment
connecting \( x \) and \( y \) is in \( C \) as discussed below.
</p>
<p>The convex subsets of \( \mathbb{R} \) are the intervals of
\( \mathbb{R} \). Examples of convex sets of \( \mathbb{R}^2 \) are the
regular polygons (triangles, rectangles, pentagons, etc...).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="convex-function">Convex function </h2>
<p><b>Convex function</b>: Let \( X \subset \mathbb{R}^n \) be a convex set. Assume that the function \( f: X \rightarrow \mathbb{R} \) is continuous, then \( f \) is said to be convex if $$f(tx_1 + (1-t)x_2) \leq tf(x_1) + (1-t)f(x_2) $$ for all \( x_1, x_2 \in X \) and for all \( t \in [0,1] \). If \( \leq \) is replaced with a strict inequaltiy in the definition, we demand \( x_1 \neq x_2 \) and \( t\in(0,1) \) then \( f \) is said to be strictly convex. For a single variable function, convexity means that if you draw a straight line connecting \( f(x_1) \) and \( f(x_2) \), the value of the function on the interval \( [x_1,x_2] \) is always below the line as illustrated below.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="conditions-on-convex-functions">Conditions on convex functions </h2>
<p>In the following we state first and second-order conditions which
ensures convexity of a function \( f \). We write \( D_f \) to denote the
domain of \( f \), i.e the subset of \( R^n \) where \( f \) is defined. For more
details and proofs we refer to: <a href="http://stanford.edu/boyd/cvxbook/, 2004" target="_blank">S. Boyd and L. Vandenberghe. Convex Optimization. Cambridge University Press</a>.
</p>
<div class="alert alert-block alert-block alert-text-normal">
<b>First order condition</b>
<p>
<p>Suppose \( f \) is differentiable (i.e \( \nabla f(x) \) is well defined for
all \( x \) in the domain of \( f \)). Then \( f \) is convex if and only if \( D_f \)
is a convex set and $$f(y) \geq f(x) + \nabla f(x)^T (y-x) $$ holds
for all \( x,y \in D_f \). This condition means that for a convex function
the first order Taylor expansion (right hand side above) at any point
a global under estimator of the function. To convince yourself you can
make a drawing of \( f(x) = x^2+1 \) and draw the tangent line to \( f(x) \) and
note that it is always below the graph.
</p>
</div>
<div class="alert alert-block alert-block alert-text-normal">
<b>Second order condition</b>
<p>
<p>Assume that \( f \) is twice
differentiable, i.e the Hessian matrix exists at each point in
\( D_f \). Then \( f \) is convex if and only if \( D_f \) is a convex set and its
Hessian is positive semi-definite for all \( x\in D_f \). For a
single-variable function this reduces to \( f''(x) \geq 0 \). Geometrically this means that \( f \) has nonnegative curvature
everywhere.
</p>
</div>
<p>This condition is particularly useful since it gives us an procedure for determining if the function under consideration is convex, apart from using the definition.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-on-convex-functions">More on convex functions </h2>
<p>The next result is of great importance to us and the reason why we are
going on about convex functions. In machine learning we frequently
have to minimize a loss/cost function in order to find the best
parameters for the model we are considering.
</p>
<p>Ideally we want the
global minimum (for high-dimensional models it is hard to know
if we have local or global minimum). However, if the cost/loss function
is convex the following result provides invaluable information:
</p>
<div class="alert alert-block alert-block alert-text-normal">
<b>Any minimum is global for convex functions</b>
<p>
<p>Consider the problem of finding \( x \in \mathbb{R}^n \) such that \( f(x) \)
is minimal, where \( f \) is convex and differentiable. Then, any point
\( x^* \) that satisfies \( \nabla f(x^*) = 0 \) is a global minimum.
</p>
</div>
<p>This result means that if we know that the cost/loss function is convex and we are able to find a minimum, we are guaranteed that it is a global minimum.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="some-simple-problems">Some simple problems </h2>
<ol>
<li> Show that \( f(x)=x^2 \) is convex for \( x \in \mathbb{R} \) using the definition of convexity. Hint: If you re-write the definition, \( f \) is convex if the following holds for all \( x,y \in D_f \) and any \( \lambda \in [0,1] \) $\lambda f(x)+(1-\lambda)f(y)-f(\lambda x + (1-\lambda) y ) \geq 0$.</li>
<li> Using the second order condition show that the following functions are convex on the specified domain.</li>
<ul>
<li> \( f(x) = e^x \) is convex for \( x \in \mathbb{R} \).</li>
<li> \( g(x) = -\ln(x) \) is convex for \( x \in (0,\infty) \).</li>
</ul>
<li> Let \( f(x) = x^2 \) and \( g(x) = e^x \). Show that \( f(g(x)) \) and \( g(f(x)) \) is convex for \( x \in \mathbb{R} \). Also show that if \( f(x) \) is any convex function than \( h(x) = e^{f(x)} \) is convex.</li>
<li> A norm is any function that satisfy the following properties</li>
<ul>
<li> \( f(\alpha x) = |\alpha| f(x) \) for all \( \alpha \in \mathbb{R} \).</li>
<li> \( f(x+y) \leq f(x) + f(y) \)</li>
<li> \( f(x) \leq 0 \) for all \( x \in \mathbb{R}^n \) with equality if and only if \( x = 0 \)</li>
</ul>
</ol>
<p>Using the definition of convexity, try to show that a function satisfying the properties above is convex (the third condition is not needed to show this).</p>
<!-- !split -->
<h2 id="revisiting-ordinary-least-squares">Revisiting Ordinary Least Squares </h2>
<p>We will use linear regression as a case study for the gradient descent
methods. Linear regression is a great test case for the gradient
descent methods discussed in the lectures since it has several
desirable properties such as:
</p>
<ol>
<li> An analytical solution (recall homework sets for week 35).</li>
<li> The gradient can be computed analytically.</li>
<li> The cost function is convex which guarantees that gradient descent converges for small enough learning rates</li>
</ol>
<p>We revisit an example similar to what we had in the first homework set. We had a function of the type</p>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;">x = <span style="color: #B452CD">2</span>*np.random.rand(m,<span style="color: #B452CD">1</span>)
y = <span style="color: #B452CD">4</span>+<span style="color: #B452CD">3</span>*x+np.random.randn(m,<span style="color: #B452CD">1</span>)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>with \( x_i \in [0,1] \) is chosen randomly using a uniform distribution. Additionally we have a stochastic noise chosen according to a normal distribution \( \cal {N}(0,1) \).
The linear regression model is given by
</p>
$$
h_\theta(x) = \boldsymbol{y} = \theta_0 + \theta_1 x,
$$
<p>such that </p>
$$
\boldsymbol{y}_i = \theta_0 + \theta_1 x_i.
$$
<!-- !split -->
<h2 id="gradient-descent-example">Gradient descent example </h2>
<p>Let \( \mathbf{y} = (y_1,\cdots,y_n)^T \), \( \mathbf{\boldsymbol{y}} = (\boldsymbol{y}_1,\cdots,\boldsymbol{y}_n)^T \) and \( \theta = (\theta_0, \theta_1)^T \)</p>
<p>It is convenient to write \( \mathbf{\boldsymbol{y}} = X\theta \) where \( X \in \mathbb{R}^{100 \times 2} \) is the design matrix given by (we keep the intercept here)</p>
$$
X \equiv \begin{bmatrix}
1 & x_1 \\
\vdots & \vdots \\
1 & x_{100} & \\
\end{bmatrix}.
$$
<p>The cost/loss/risk function is given by (</p>
$$
C(\theta) = \frac{1}{n}||X\theta-\mathbf{y}||_{2}^{2} = \frac{1}{n}\sum_{i=1}^{100}\left[ (\theta_0 + \theta_1 x_i)^2 - 2 y_i (\theta_0 + \theta_1 x_i) + y_i^2\right]
$$
<p>and we want to find \( \theta \) such that \( C(\theta) \) is minimized.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-derivative-of-the-cost-loss-function">The derivative of the cost/loss function </h2>
<p>Computing \( \partial C(\theta) / \partial \theta_0 \) and \( \partial C(\theta) / \partial \theta_1 \) we can show that the gradient can be written as</p>
$$
\nabla_{\theta} C(\theta) = \frac{2}{n}\begin{bmatrix} \sum_{i=1}^{100} \left(\theta_0+\theta_1x_i-y_i\right) \\
\sum_{i=1}^{100}\left( x_i (\theta_0+\theta_1x_i)-y_ix_i\right) \\
\end{bmatrix} = \frac{2}{n}X^T(X\theta - \mathbf{y}),
$$
<p>where \( X \) is the design matrix defined above.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-hessian-matrix">The Hessian matrix </h2>
<p>The Hessian matrix of \( C(\theta) \) is given by </p>
$$
\boldsymbol{H} \equiv \begin{bmatrix}
\frac{\partial^2 C(\theta)}{\partial \theta_0^2} & \frac{\partial^2 C(\theta)}{\partial \theta_0 \partial \theta_1} \\
\frac{\partial^2 C(\theta)}{\partial \theta_0 \partial \theta_1} & \frac{\partial^2 C(\theta)}{\partial \theta_1^2} & \\
\end{bmatrix} = \frac{2}{n}X^T X.
$$
<p>This result implies that \( C(\theta) \) is a convex function since the matrix \( X^T X \) always is positive semi-definite.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="simple-program">Simple program </h2>
<p>We can now write a program that minimizes \( C(\theta) \) using the gradient descent method with a constant learning rate \( \gamma \) according to </p>
$$
\theta_{k+1} = \theta_k - \gamma \nabla_\theta C(\theta_k), \ k=0,1,\cdots
$$
<p>We can use the expression we computed for the gradient and let use a
\( \theta_0 \) be chosen randomly and let \( \gamma = 0.001 \). Stop iterating
when \( ||\nabla_\theta C(\theta_k) || \leq \epsilon = 10^{-8} \). <b>Note that the code below does not include the latter stop criterion</b>.
</p>
<p>And finally we can compare our solution for \( \theta \) with the analytic result given by
\( \theta= (X^TX)^{-1} X^T \mathbf{y} \).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="gradient-descent-example">Gradient Descent Example </h2>
<p>Here our simple example</p>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #228B22"># Importing various packages</span>
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">random</span> <span style="color: #8B008B; font-weight: bold">import</span> random, seed
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">mpl_toolkits.mplot3d</span> <span style="color: #8B008B; font-weight: bold">import</span> Axes3D
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">matplotlib</span> <span style="color: #8B008B; font-weight: bold">import</span> cm
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">matplotlib.ticker</span> <span style="color: #8B008B; font-weight: bold">import</span> LinearLocator, FormatStrFormatter
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">sys</span>
<span style="color: #228B22"># the number of datapoints</span>
n = <span style="color: #B452CD">100</span>
x = <span style="color: #B452CD">2</span>*np.random.rand(n,<span style="color: #B452CD">1</span>)
y = <span style="color: #B452CD">4</span>+<span style="color: #B452CD">3</span>*x+np.random.randn(n,<span style="color: #B452CD">1</span>)
X = np.c_[np.ones((n,<span style="color: #B452CD">1</span>)), x]
<span style="color: #228B22"># Hessian matrix</span>
H = (<span style="color: #B452CD">2.0</span>/n)* X.T @ X
<span style="color: #228B22"># Get the eigenvalues</span>
EigValues, EigVectors = np.linalg.eig(H)
<span style="color: #658b00">print</span>(<span style="color: #CD5555">f&quot;Eigenvalues of Hessian Matrix:{</span>EigValues<span style="color: #CD5555">}&quot;</span>)
theta_linreg = np.linalg.inv(X.T @ X) @ X.T @ y
<span style="color: #658b00">print</span>(theta_linreg)
theta = np.random.randn(<span style="color: #B452CD">2</span>,<span style="color: #B452CD">1</span>)
eta = <span style="color: #B452CD">1.0</span>/np.max(EigValues)
Niterations = <span style="color: #B452CD">1000</span>
<span style="color: #8B008B; font-weight: bold">for</span> <span style="color: #658b00">iter</span> <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(Niterations):
gradient = (<span style="color: #B452CD">2.0</span>/n)*X.T @ (X @ theta-y)
theta -= eta*gradient
<span style="color: #658b00">print</span>(theta)
xnew = np.array([[<span style="color: #B452CD">0</span>],[<span style="color: #B452CD">2</span>]])
xbnew = np.c_[np.ones((<span style="color: #B452CD">2</span>,<span style="color: #B452CD">1</span>)), xnew]
ypredict = xbnew.dot(theta)
ypredict2 = xbnew.dot(theta_linreg)
plt.plot(xnew, ypredict, <span style="color: #CD5555">&quot;r-&quot;</span>)
plt.plot(xnew, ypredict2, <span style="color: #CD5555">&quot;b-&quot;</span>)
plt.plot(x, y ,<span style="color: #CD5555">&#39;ro&#39;</span>)
plt.axis([<span style="color: #B452CD">0</span>,<span style="color: #B452CD">2.0</span>,<span style="color: #B452CD">0</span>, <span style="color: #B452CD">15.0</span>])
plt.xlabel(<span style="color: #CD5555">r&#39;$x$&#39;</span>)
plt.ylabel(<span style="color: #CD5555">r&#39;$y$&#39;</span>)
plt.title(<span style="color: #CD5555">r&#39;Gradient descent example&#39;</span>)
plt.show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split -->
<h2 id="gradient-descent-and-ridge">Gradient descent and Ridge </h2>
<p>We have also discussed Ridge regression where the loss function contains a regularized term given by the \( L_2 \) norm of \( \theta \), </p>
$$
C_{\text{ridge}}(\theta) = \frac{1}{n}||X\theta -\mathbf{y}||^2 + \lambda ||\theta||^2, \ \lambda \geq 0.
$$
<p>In order to minimize \( C_{\text{ridge}}(\theta) \) using GD we adjust the gradient as follows </p>
$$
\nabla_\theta C_{\text{ridge}}(\theta) = \frac{2}{n}\begin{bmatrix} \sum_{i=1}^{100} \left(\theta_0+\theta_1x_i-y_i\right) \\
\sum_{i=1}^{100}\left( x_i (\theta_0+\theta_1x_i)-y_ix_i\right) \\
\end{bmatrix} + 2\lambda\begin{bmatrix} \theta_0 \\ \theta_1\end{bmatrix} = 2 (\frac{1}{n}X^T(X\theta - \mathbf{y})+\lambda \theta).
$$
<p>We can easily extend our program to minimize \( C_{\text{ridge}}(\theta) \) using gradient descent and compare with the analytical solution given by </p>
$$
\theta_{\text{ridge}} = \left(X^T X + n\lambda I_{2 \times 2} \right)^{-1} X^T \mathbf{y}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-hessian-matrix-for-ridge-regression">The Hessian matrix for Ridge Regression </h2>
<p>The Hessian matrix of Ridge Regression for our simple example is given by </p>
$$
\boldsymbol{H} \equiv \begin{bmatrix}
\frac{\partial^2 C(\theta)}{\partial \theta_0^2} & \frac{\partial^2 C(\theta)}{\partial \theta_0 \partial \theta_1} \\
\frac{\partial^2 C(\theta)}{\partial \theta_0 \partial \theta_1} & \frac{\partial^2 C(\theta)}{\partial \theta_1^2} & \\
\end{bmatrix} = \frac{2}{n}X^T X+2\lambda\boldsymbol{I}.
$$
<p>This implies that the Hessian matrix is positive definite, hence the stationary point is a
minimum.
Note that the Ridge cost function is convex being a sum of two convex
functions. Therefore, the stationary point is a global
minimum of this function.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="program-example-for-gradient-descent-with-ridge-regression">Program example for gradient descent with Ridge Regression </h2>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">random</span> <span style="color: #8B008B; font-weight: bold">import</span> random, seed
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">mpl_toolkits.mplot3d</span> <span style="color: #8B008B; font-weight: bold">import</span> Axes3D
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">matplotlib</span> <span style="color: #8B008B; font-weight: bold">import</span> cm
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">matplotlib.ticker</span> <span style="color: #8B008B; font-weight: bold">import</span> LinearLocator, FormatStrFormatter
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">sys</span>
<span style="color: #228B22"># the number of datapoints</span>
n = <span style="color: #B452CD">100</span>
x = <span style="color: #B452CD">2</span>*np.random.rand(n,<span style="color: #B452CD">1</span>)
y = <span style="color: #B452CD">4</span>+<span style="color: #B452CD">3</span>*x+np.random.randn(n,<span style="color: #B452CD">1</span>)
X = np.c_[np.ones((n,<span style="color: #B452CD">1</span>)), x]
XT_X = X.T @ X
<span style="color: #228B22">#Ridge parameter lambda</span>
lmbda = <span style="color: #B452CD">0.001</span>
Id = n*lmbda* np.eye(XT_X.shape[<span style="color: #B452CD">0</span>])
<span style="color: #228B22"># Hessian matrix</span>
H = (<span style="color: #B452CD">2.0</span>/n)* XT_X+<span style="color: #B452CD">2</span>*lmbda* np.eye(XT_X.shape[<span style="color: #B452CD">0</span>])
<span style="color: #228B22"># Get the eigenvalues</span>
EigValues, EigVectors = np.linalg.eig(H)
<span style="color: #658b00">print</span>(<span style="color: #CD5555">f&quot;Eigenvalues of Hessian Matrix:{</span>EigValues<span style="color: #CD5555">}&quot;</span>)
theta_linreg = np.linalg.inv(XT_X+Id) @ X.T @ y
<span style="color: #658b00">print</span>(theta_linreg)
<span style="color: #228B22"># Start plain gradient descent</span>
theta = np.random.randn(<span style="color: #B452CD">2</span>,<span style="color: #B452CD">1</span>)
eta = <span style="color: #B452CD">1.0</span>/np.max(EigValues)
Niterations = <span style="color: #B452CD">100</span>
<span style="color: #8B008B; font-weight: bold">for</span> <span style="color: #658b00">iter</span> <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(Niterations):
gradients = <span style="color: #B452CD">2.0</span>/n*X.T @ (X @ (theta)-y)+<span style="color: #B452CD">2</span>*lmbda*theta
theta -= eta*gradients
<span style="color: #658b00">print</span>(theta)
ypredict = X @ theta
ypredict2 = X @ theta_linreg
plt.plot(x, ypredict, <span style="color: #CD5555">&quot;r-&quot;</span>)
plt.plot(x, ypredict2, <span style="color: #CD5555">&quot;b-&quot;</span>)
plt.plot(x, y ,<span style="color: #CD5555">&#39;ro&#39;</span>)
plt.axis([<span style="color: #B452CD">0</span>,<span style="color: #B452CD">2.0</span>,<span style="color: #B452CD">0</span>, <span style="color: #B452CD">15.0</span>])
plt.xlabel(<span style="color: #CD5555">r&#39;$x$&#39;</span>)
plt.ylabel(<span style="color: #CD5555">r&#39;$y$&#39;</span>)
plt.title(<span style="color: #CD5555">r&#39;Gradient descent example for Ridge&#39;</span>)
plt.show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="using-gradient-descent-methods-limitations">Using gradient descent methods, limitations </h2>
<ul>
<li> <b>Gradient descent (GD) finds local minima of our function</b>. Since the GD algorithm is deterministic, if it converges, it will converge to a local minimum of our cost/loss/risk function. Because in ML we are often dealing with extremely rugged landscapes with many local minima, this can lead to poor performance.</li>
<li> <b>GD is sensitive to initial conditions</b>. One consequence of the local nature of GD is that initial conditions matter. Depending on where one starts, one will end up at a different local minima. Therefore, it is very important to think about how one initializes the training process. This is true for GD as well as more complicated variants of GD.</li>
<li> <b>Gradients are computationally expensive to calculate for large datasets</b>. In many cases in statistics and ML, the cost/loss/risk function is a sum of terms, with one term for each data point. For example, in linear regression, \( E \propto \sum_{i=1}^n (y_i - \mathbf{w}^T\cdot\mathbf{x}_i)^2 \); for logistic regression, the square error is replaced by the cross entropy. To calculate the gradient we have to sum over <em>all</em> \( n \) data points. Doing this at every GD step becomes extremely computationally expensive. An ingenious solution to this, is to calculate the gradients using small subsets of the data called &quot;mini batches&quot;. This has the added benefit of introducing stochasticity into our algorithm.</li>
<li> <b>GD is very sensitive to choices of learning rates</b>. GD is extremely sensitive to the choice of learning rates. If the learning rate is very small, the training process take an extremely long time. For larger learning rates, GD can diverge and give poor results. Furthermore, depending on what the local landscape looks like, we have to modify the learning rates to ensure convergence. Ideally, we would <em>adaptively</em> choose the learning rates to match the landscape.</li>
<li> <b>GD treats all directions in parameter space uniformly.</b> Another major drawback of GD is that unlike Newton's method, the learning rate for GD is the same in all directions in parameter space. For this reason, the maximum learning rate is set by the behavior of the steepest direction and this can significantly slow down training. Ideally, we would like to take large steps in flat directions and small steps in steep directions. Since we are exploring rugged landscapes where curvatures change, this requires us to keep track of not only the gradient but second derivatives. The ideal scenario would be to calculate the Hessian but this proves to be too computationally expensive.</li>
<li> GD can take exponential time to escape saddle points, even with random initialization. As we mentioned, GD is extremely sensitive to initial condition since it determines the particular local minimum GD would eventually reach. However, even with a good initialization scheme, through the introduction of randomness, GD can still take exponential time to escape saddle points.</li>
</ul>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="material-for-lab-sessions-sessions-tuesday-and-wednesday">Material for lab sessions sessions Tuesday and Wednesday </h2>
<p>The material here contains a summary of the lecture on Monday and discussion of SVD, Ridge and Lasso regression with examples </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="linear-regression-and-the-svd">Linear Regression and the SVD </h2>
<p>We used the SVD to analyse the matrix to invert in ordinary lineat regression</p>
$$
\boldsymbol{X}^T\boldsymbol{X}=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{U}^T\boldsymbol{U}\boldsymbol{\Sigma}\boldsymbol{V}^T=\boldsymbol{V}\boldsymbol{\Sigma}^T\boldsymbol{\Sigma}\boldsymbol{V}^T.
$$
<p>Since the matrices here have dimension \( p\times p \), with \( p \) corresponding to the singular values, we defined last week the matrix</p>
$$
\boldsymbol{\Sigma}^T\boldsymbol{\Sigma} = \begin{bmatrix} \tilde{\boldsymbol{\Sigma}} & \boldsymbol{0}\\ \end{bmatrix}\begin{bmatrix} \tilde{\boldsymbol{\Sigma}} \\ \boldsymbol{0}\end{bmatrix},
$$
<p>where the tilde-matrix \( \tilde{\boldsymbol{\Sigma}} \) is a matrix of dimension \( p\times p \) containing only the singular values \( \sigma_i \), that is</p>
$$
\tilde{\boldsymbol{\Sigma}}=\begin{bmatrix} \sigma_0 & 0 & 0 & \dots & 0 & 0 \\
0 & \sigma_1 & 0 & \dots & 0 & 0 \\
0 & 0 & \sigma_2 & \dots & 0 & 0 \\
0 & 0 & 0 & \dots & \sigma_{p-2} & 0 \\
0 & 0 & 0 & \dots & 0 & \sigma_{p-1} \\
\end{bmatrix},
$$
<p>meaning we can write</p>
$$
\boldsymbol{X}^T\boldsymbol{X}=\boldsymbol{V}\tilde{\boldsymbol{\Sigma}}^2\boldsymbol{V}^T.
$$
<p>Multiplying from the right with \( \boldsymbol{V} \) (using the orthogonality of \( \boldsymbol{V} \)) we get</p>
$$
\left(\boldsymbol{X}^T\boldsymbol{X}\right)\boldsymbol{V}=\boldsymbol{V}\tilde{\boldsymbol{\Sigma}}^2.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="what-does-it-mean">What does it mean? </h2>
<p>This means the vectors \( \boldsymbol{v}_i \) of the orthogonal matrix \( \boldsymbol{V} \)
are the eigenvectors of the matrix \( \boldsymbol{X}^T\boldsymbol{X} \) with eigenvalues
given by the singular values squared, that is
</p>
$$
\left(\boldsymbol{X}^T\boldsymbol{X}\right)\boldsymbol{v}_i=\boldsymbol{v}_i\sigma_i^2.
$$
<p>In other words, each non-zero singular value of \( \boldsymbol{X} \) is a positive
square root of an eigenvalue of \( \boldsymbol{X}^T\boldsymbol{X} \). It means also that
the columns of \( \boldsymbol{V} \) are the eigenvectors of
\( \boldsymbol{X}^T\boldsymbol{X} \). Since we have ordered the singular values of
\( \boldsymbol{X} \) in a descending order, it means that the column vectors
\( \boldsymbol{v}_i \) are hierarchically ordered by how much correlation they
encode from the columns of \( \boldsymbol{X} \).
</p>
<p>Note that these are also the eigenvectors and eigenvalues of the
Hessian matrix.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="ridge-and-lasso-regression">Ridge and LASSO Regression </h2>
<p>Let us remind ourselves about the expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, that is
our optimization problem is
</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in {\mathbb{R}}^{p}}}\frac{1}{n}\left\{\left(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\right)^T\left(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\right)\right\}.
$$
<p>or we can state it as</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\sum_{i=0}^{n-1}\left(y_i-\tilde{y}_i\right)^2=\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2,
$$
<p>where we have used the definition of a norm-2 vector, that is</p>
$$
\vert\vert \boldsymbol{x}\vert\vert_2 = \sqrt{\sum_i x_i^2}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="from-ols-to-ridge-and-lasso">From OLS to Ridge and Lasso </h2>
<p>By minimizing the above equation with respect to the parameters
\( \boldsymbol{\theta} \) we could then obtain an analytical expression for the
parameters \( \boldsymbol{\theta} \). We can add a regularization parameter \( \lambda \) by
defining a new cost function to be optimized, that is
</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_2^2
$$
<p>which leads to the Ridge regression minimization problem where we
require that \( \vert\vert \boldsymbol{\theta}\vert\vert_2^2\le t \), where \( t \) is
a finite number larger than zero. We do not include such a constraints in the discussions here.
</p>
<p>By defining</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_1,
$$
<p>we have a new optimization equation</p>
$$
{\displaystyle \min_{\boldsymbol{\theta}\in
{\mathbb{R}}^{p}}}\frac{1}{n}\vert\vert \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta}\vert\vert_2^2+\lambda\vert\vert \boldsymbol{\theta}\vert\vert_1
$$
<p>which leads to Lasso regression. Lasso stands for least absolute shrinkage and selection operator. </p>
<p>Here we have defined the norm-1 as </p>
$$
\vert\vert \boldsymbol{x}\vert\vert_1 = \sum_i \vert x_i\vert.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="deriving-the-ridge-regression-equations">Deriving the Ridge Regression Equations </h2>
<p>Using the matrix-vector expression for Ridge regression and dropping the parameter \( 1/n \) in front of the standard means squared error equation, we have</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\left\{(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})\right\}+\lambda\boldsymbol{\theta}^T\boldsymbol{\theta},
$$
<p>and
taking the derivatives with respect to \( \boldsymbol{\theta} \) we obtain then
a slightly modified matrix inversion problem which for finite values
of \( \lambda \) does not suffer from singularity problems. We obtain
the optimal parameters
</p>
$$
\hat{\boldsymbol{\theta}}_{\mathrm{Ridge}} = \left(\boldsymbol{X}^T\boldsymbol{X}+\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y},
$$
<p>with \( \boldsymbol{I} \) being a \( p\times p \) identity matrix with the constraint that</p>
$$
\sum_{i=0}^{p-1} \theta_i^2 \leq t,
$$
<p>with \( t \) a finite positive number. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="note-on-scikit-learn">Note on Scikit-Learn </h2>
<p>Note well that a library like <b>Scikit-Learn</b> does not include the \( 1/n \) factor in the expression for the mean-squared error. If you include it, the optimal parameter \( \theta \) becomes</p>
$$
\hat{\boldsymbol{\theta}}_{\mathrm{Ridge}} = \left(\boldsymbol{X}^T\boldsymbol{X}+n\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>In our codes where we compare our own codes with <b>Scikit-Learn</b>, we do thus not include the \( 1/n \) factor in the cost function.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="comparison-with-ols">Comparison with OLS </h2>
<p>When we compare this with the ordinary least squares result we have</p>
$$
\hat{\boldsymbol{\theta}}_{\mathrm{OLS}} = \left(\boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y},
$$
<p>which can lead to singular matrices. However, with the SVD, we can always compute the inverse of the matrix \( \boldsymbol{X}^T\boldsymbol{X} \).</p>
<p>We see that Ridge regression is nothing but the standard OLS with a
modified diagonal term added to \( \boldsymbol{X}^T\boldsymbol{X} \). The consequences, in
particular for our discussion of the bias-variance tradeoff are rather
interesting. We will see that for specific values of \( \lambda \), we may
even reduce the variance of the optimal parameters \( \boldsymbol{\theta} \). These topics and other related ones, will be discussed after the more linear algebra oriented analysis here.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="svd-analysis">SVD analysis </h2>
<p>Using our insights about the SVD of the design matrix \( \boldsymbol{X} \)
We have already analyzed the OLS solutions in terms of the eigenvectors (the columns) of the right singular value matrix \( \boldsymbol{U} \) as
</p>
$$
\tilde{\boldsymbol{y}}_{\mathrm{OLS}}=\boldsymbol{X}\boldsymbol{\theta} =\boldsymbol{U}\boldsymbol{U}^T\boldsymbol{y}.
$$
<p>For Ridge regression this becomes</p>
$$
\tilde{\boldsymbol{y}}_{\mathrm{Ridge}}=\boldsymbol{X}\boldsymbol{\theta}_{\mathrm{Ridge}} = \boldsymbol{U\Sigma V^T}\left(\boldsymbol{V}\boldsymbol{\Sigma}^2\boldsymbol{V}^T+\lambda\boldsymbol{I} \right)^{-1}(\boldsymbol{U\Sigma V^T})^T\boldsymbol{y}=\sum_{j=0}^{p-1}\boldsymbol{u}_j\boldsymbol{u}_j^T\frac{\sigma_j^2}{\sigma_j^2+\lambda}\boldsymbol{y},
$$
<p>with the vectors \( \boldsymbol{u}_j \) being the columns of \( \boldsymbol{U} \) from the SVD of the matrix \( \boldsymbol{X} \). </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="interpreting-the-ridge-results">Interpreting the Ridge results </h2>
<p>Since \( \lambda \geq 0 \), it means that compared to OLS, we have </p>
$$
\frac{\sigma_j^2}{\sigma_j^2+\lambda} \leq 1.
$$
<p>Ridge regression finds the coordinates of \( \boldsymbol{y} \) with respect to the
orthonormal basis \( \boldsymbol{U} \), it then shrinks the coordinates by
\( \frac{\sigma_j^2}{\sigma_j^2+\lambda} \). Recall that the SVD has
eigenvalues ordered in a descending way, that is \( \sigma_i \geq
\sigma_{i+1} \).
</p>
<p>For small eigenvalues \( \sigma_i \) it means that their contributions become less important, a fact which can be used to reduce the number of degrees of freedom. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-interpretations">More interpretations </h2>
<p>For the sake of simplicity, let us assume that the design matrix is orthonormal, that is </p>
$$
\boldsymbol{X}^T\boldsymbol{X}=(\boldsymbol{X}^T\boldsymbol{X})^{-1} =\boldsymbol{I}.
$$
<p>In this case the standard OLS results in </p>
$$
\boldsymbol{\theta}^{\mathrm{OLS}} = \boldsymbol{X}^T\boldsymbol{y}=\sum_{i=0}^{n-1}\boldsymbol{u}_i\boldsymbol{u}_i^T\boldsymbol{y},
$$
<p>and</p>
$$
\boldsymbol{\theta}^{\mathrm{Ridge}} = \left(\boldsymbol{I}+\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}=\left(1+\lambda\right)^{-1}\boldsymbol{\theta}^{\mathrm{OLS}},
$$
<p>that is the Ridge estimator scales the OLS estimator by the inverse of a factor \( 1+\lambda \), and
the Ridge estimator converges to zero when the hyperparameter goes to
infinity.
</p>
<p>We will come back to more interpreations after we have gone through some of the statistical analysis part. </p>
<p>For more discussions of Ridge and Lasso regression, <a href="https://arxiv.org/abs/1509.09169" target="_blank">Wessel van Wieringen's</a> article is highly recommended.
Similarly, <a href="https://arxiv.org/abs/1803.08823" target="_blank">Mehta et al's article</a> is also recommended.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="deriving-the-lasso-regression-equations">Deriving the Lasso Regression Equations </h2>
<p>Using the matrix-vector expression for Lasso regression, we have the following <b>cost</b> function</p>
$$
C(\boldsymbol{X},\boldsymbol{\theta})=\frac{1}{n}\left\{(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})\right\}+\lambda\vert\vert\boldsymbol{\theta}\vert\vert_1,
$$
<p>Taking the derivative with respect to \( \boldsymbol{\theta} \) and recalling that the derivative of the absolute value is (we drop the boldfaced vector symbol for simplicity)</p>
$$
\frac{d \vert \theta\vert}{d \theta}=\mathrm{sgn}(\theta)=\left\{\begin{array}{cc} 1 & \theta > 0 \\-1 & \theta < 0, \end{array}\right.
$$
<p>we have that the derivative of the cost function is</p>
$$
\frac{\partial C(\boldsymbol{X},\boldsymbol{\theta})}{\partial \boldsymbol{\theta}}=-\frac{2}{n}\boldsymbol{X}^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{\theta})+\lambda sgn(\boldsymbol{\theta})=0,
$$
<p>and reordering we have</p>
$$
\boldsymbol{X}^T\boldsymbol{X}\boldsymbol{\theta}+\lambda sgn(\boldsymbol{\theta})=\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>This equation does not lead to a nice analytical equation as in Ridge regression or ordinary least squares. We have absorbed the factor \( 2/n \) in a redefinition of the parameter \( \lambda \). We will solve this type of problems using libraries like <b>scikit-learn</b> and using our own gradient descent code in project 1.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="simple-example-to-illustrate-ordinary-least-squares-ridge-and-lasso-regression">Simple example to illustrate Ordinary Least Squares, Ridge and Lasso Regression </h2>
<p>Let us assume that our design matrix is given by unit (identity) matrix, that is a square diagonal matrix with ones only along the
diagonal. In this case we have an equal number of rows and columns \( n=p \).
</p>
<p>Our model approximation is just \( \tilde{\boldsymbol{y}}=\boldsymbol{\theta} \) and the mean squared error and thereby the cost function for ordinary least sqquares (OLS) is then (we drop the term \( 1/n \)) </p>
$$
C(\boldsymbol{\theta})=\sum_{i=0}^{p-1}(y_i-\theta_i)^2,
$$
<p>and minimizing we have that</p>
$$
\hat{\theta}_i^{\mathrm{OLS}} = y_i.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="ridge-regression">Ridge Regression </h2>
<p>For Ridge regression our cost function is</p>
$$
C(\boldsymbol{\theta})=\sum_{i=0}^{p-1}(y_i-\theta_i)^2+\lambda\sum_{i=0}^{p-1}\theta_i^2,
$$
<p>and minimizing we have that</p>
$$
\hat{\theta}_i^{\mathrm{Ridge}} = \frac{y_i}{1+\lambda}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="lasso-regression">Lasso Regression </h2>
<p>For Lasso regression our cost function is</p>
$$
C(\boldsymbol{\theta})=\sum_{i=0}^{p-1}(y_i-\theta_i)^2+\lambda\sum_{i=0}^{p-1}\vert\theta_i\vert=\sum_{i=0}^{p-1}(y_i-\theta_i)^2+\lambda\sum_{i=0}^{p-1}\sqrt{\theta_i^2},
$$
<p>and minimizing we have that</p>
$$
-2\sum_{i=0}^{p-1}(y_i-\theta_i)+\lambda \sum_{i=0}^{p-1}\frac{(\theta_i)}{\vert\theta_i\vert}=0,
$$
<p>which leads to </p>
$$
\hat{\boldsymbol{\theta}}_i^{\mathrm{Lasso}} = \left\{\begin{array}{ccc}y_i-\frac{\lambda}{2} &\mathrm{if} & y_i> \frac{\lambda}{2}\\
y_i+\frac{\lambda}{2} &\mathrm{if} & y_i < -\frac{\lambda}{2}\\
0 &\mathrm{if} & \vert y_i\vert\le \frac{\lambda}{2}\end{array}\right.\\.
$$
<p>Plotting these results shows clearly that Lasso regression suppresses (sets to zero) values of \( \theta_i \) for specific values of \( \lambda \). Ridge regression reduces on the other hand the values of \( \theta_i \) as function of \( \lambda \).</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="yet-another-example">Yet another Example </h2>
<p>Let us assume we have a data set with outputs/targets given by the vector</p>
$$
\boldsymbol{y}=\begin{bmatrix}4 \\ 2 \\3\end{bmatrix},
$$
<p>and our inputs as a \( 3\times 2 \) design matrix</p>
$$
\boldsymbol{X}=\begin{bmatrix}2 & 0\\ 0 & 1 \\ 0 & 0\end{bmatrix},
$$
<p>meaning that we have two features and two unknown parameters \( \theta_0 \) and \( \theta_1 \) to be determined either by ordinary least squares, Ridge or Lasso regression.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-ols-case">The OLS case </h2>
<p>For ordinary least squares (OLS) we know that the optimal solution is</p>
$$
\hat{\boldsymbol{\theta}}^{\mathrm{OLS}}=\left( \boldsymbol{X}^T\boldsymbol{X}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>Inserting the above values we obtain that </p>
$$
\hat{\boldsymbol{\theta}}^{\mathrm{OLS}}=\begin{bmatrix}2 \\ 2\end{bmatrix},
$$
<p>The code which implements this simpler case is presented after the discussion of Ridge and Lasso.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-ridge-case">The Ridge case </h2>
<p>For Ridge regression we have</p>
$$
\hat{\boldsymbol{\theta}}^{\mathrm{Ridge}}=\left( \boldsymbol{X}^T\boldsymbol{X}+\lambda\boldsymbol{I}\right)^{-1}\boldsymbol{X}^T\boldsymbol{y}.
$$
<p>Inserting the above values we obtain that </p>
$$
\hat{\boldsymbol{\theta}}^{\mathrm{Ridge}}=\begin{bmatrix}\frac{8}{4+\lambda} \\ \frac{2}{1+\lambda}\end{bmatrix},
$$
<p>There is normally a constraint on the value of \( \vert\vert \boldsymbol{\theta}\vert\vert_2 \) via the parameter \( \lambda \).
Let us for simplicity assume that \( \theta_0^2+\theta_1^2=1 \) as constraint. This will allow us to find an expression for the optimal values of \( \theta \) and \( \lambda \).
</p>
<p>To see this, let us write the cost function for Ridge regression. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="writing-the-cost-function">Writing the Cost Function </h2>
<p>We define the MSE without the \( 1/n \) factor and have then, using that</p>
$$
\boldsymbol{X}\boldsymbol{\theta}=\begin{bmatrix} 2\theta_0 \\ \theta_1 \\0 \end{bmatrix},
$$
$$
C(\boldsymbol{\theta})=(4-2\theta_0)^2+(2-\theta_1)^2+\lambda(\theta_0^2+\theta_1^2),
$$
<p>and taking the derivative with respect to \( \theta_0 \) we get</p>
$$
\theta_0=\frac{8}{4+\lambda},
$$
<p>and for \( \theta_1 \) we obtain</p>
$$
\theta_1=\frac{2}{1+\lambda},
$$
<p>Using the constraint for \( \theta_0^2+\theta_1^2=1 \) we can constrain \( \lambda \) by solving</p>
$$
\left(\frac{8}{4+\lambda}\right)^2+\left(\frac{2}{1+\lambda}\right)^2=1,
$$
<p>which gives \( \lambda=4.571 \) and \( \theta_0=0.933 \) and \( \theta_1=0.359 \).</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="lasso-case">Lasso case </h2>
<p>For Lasso we need now, keeping a constraint on \( \vert\theta_0\vert+\vert\theta_1\vert=1 \), to take the derivative of the absolute values of \( \theta_0 \)
and \( \theta_1 \). This gives us the following derivatives of the cost function
</p>
$$
C(\boldsymbol{\theta})=(4-2\theta_0)^2+(2-\theta_1)^2+\lambda(\vert\theta_0\vert+\vert\theta_1\vert),
$$
$$
\frac{\partial C(\boldsymbol{\theta})}{\partial \theta_0}=-4(4-2\theta_0)+\lambda\mathrm{sgn}(\theta_0)=0,
$$
<p>and</p>
$$
\frac{\partial C(\boldsymbol{\theta})}{\partial \theta_1}=-2(2-\theta_1)+\lambda\mathrm{sgn}(\theta_1)=0.
$$
<p>We have now four cases to solve besides the trivial cases \( \theta_0 \) and/or \( \theta_1 \) are zero, namely</p>
<ol>
<li> \( \theta_0 > 0 \) and \( \theta_1 > 0 \),</li>
<li> \( \theta_0 > 0 \) and \( \theta_1 < 0 \),</li>
<li> \( \theta_0 < 0 \) and \( \theta_1 > 0 \),</li>
<li> \( \theta_0 < 0 \) and \( \theta_1 < 0 \).</li>
</ol>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-first-case">The first Case </h2>
<p>If we consider the first case, we have then</p>
$$
-4(4-2\theta_0)+\lambda=0,
$$
<p>and</p>
$$
-2(2-\theta_1)+\lambda=0.
$$
<p>which yields</p>
$$
\theta_0=\frac{16+\lambda}{8},
$$
<p>and</p>
$$
\theta_1=\frac{4+\lambda}{2}.
$$
<p>Using the constraint on \( \theta_0 \) and \( \theta_1 \) we can then find the optimal value of \( \lambda \) for the different cases. We leave this as an exercise to you.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="simple-code-for-solving-the-above-problem">Simple code for solving the above problem </h2>
<p>Here we set up the OLS, Ridge and Lasso functionality in order to study the above example. Note that here we have opted for a set of values of \( \lambda \), meaning that we need to perform a search in order to find the optimal values.</p>
<p>First we study and compare the OLS and Ridge results. The next code compares all three methods.</p>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">os</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">pandas</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">pd</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">R2</span>(y_data, y_model):
<span style="color: #8B008B; font-weight: bold">return</span> <span style="color: #B452CD">1</span> - np.sum((y_data - y_model) ** <span style="color: #B452CD">2</span>) / np.sum((y_data - np.mean(y_data)) ** <span style="color: #B452CD">2</span>)
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">MSE</span>(y_data,y_model):
n = np.size(y_model)
<span style="color: #8B008B; font-weight: bold">return</span> np.sum((y_data-y_model)**<span style="color: #B452CD">2</span>)/n
<span style="color: #228B22"># A seed just to ensure that the random numbers are the same for every run.</span>
<span style="color: #228B22"># Useful for eventual debugging.</span>
X = np.array( [ [ <span style="color: #B452CD">2</span>, <span style="color: #B452CD">0</span>], [<span style="color: #B452CD">0</span>, <span style="color: #B452CD">1</span>], [<span style="color: #B452CD">0</span>,<span style="color: #B452CD">0</span>]])
y = np.array( [<span style="color: #B452CD">4</span>, <span style="color: #B452CD">2</span>, <span style="color: #B452CD">3</span>])
<span style="color: #228B22"># matrix inversion to find beta</span>
OLSbeta = np.linalg.inv(X.T @ X) @ X.T @ y
<span style="color: #658b00">print</span>(OLSbeta)
<span style="color: #228B22"># and then make the prediction</span>
ytildeOLS = X @ OLSbeta
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;Training MSE for OLS&quot;</span>)
<span style="color: #658b00">print</span>(MSE(y,ytildeOLS))
ypredictOLS = X @ OLSbeta
<span style="color: #228B22"># Repeat now for Ridge regression and various values of the regularization parameter</span>
I = np.eye(<span style="color: #B452CD">2</span>,<span style="color: #B452CD">2</span>)
<span style="color: #228B22"># Decide which values of lambda to use</span>
nlambdas = <span style="color: #B452CD">100</span>
MSEPredict = np.zeros(nlambdas)
lambdas = np.logspace(-<span style="color: #B452CD">4</span>, <span style="color: #B452CD">4</span>, nlambdas)
<span style="color: #8B008B; font-weight: bold">for</span> i <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(nlambdas):
lmb = lambdas[i]
Ridgebeta = np.linalg.inv(X.T @ X+lmb*I) @ X.T @ y
<span style="color: #228B22"># print(Ridgebeta)</span>
<span style="color: #228B22"># and then make the prediction</span>
ypredictRidge = X @ Ridgebeta
MSEPredict[i] = MSE(y,ypredictRidge)
<span style="color: #228B22"># print(MSEPredict[i])</span>
<span style="color: #228B22"># Now plot the results</span>
plt.figure()
plt.plot(np.log10(lambdas), MSEPredict, <span style="color: #CD5555">&#39;r--&#39;</span>, label = <span style="color: #CD5555">&#39;MSE Ridge Train&#39;</span>)
plt.xlabel(<span style="color: #CD5555">&#39;log10(lambda)&#39;</span>)
plt.ylabel(<span style="color: #CD5555">&#39;MSE&#39;</span>)
plt.legend()
plt.show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>We see here that we reach a plateau. What is actually happening?</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="with-lasso-regression">With Lasso Regression </h2>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">os</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">pandas</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">pd</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn</span> <span style="color: #8B008B; font-weight: bold">import</span> linear_model
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">R2</span>(y_data, y_model):
<span style="color: #8B008B; font-weight: bold">return</span> <span style="color: #B452CD">1</span> - np.sum((y_data - y_model) ** <span style="color: #B452CD">2</span>) / np.sum((y_data - np.mean(y_data)) ** <span style="color: #B452CD">2</span>)
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">MSE</span>(y_data,y_model):
n = np.size(y_model)
<span style="color: #8B008B; font-weight: bold">return</span> np.sum((y_data-y_model)**<span style="color: #B452CD">2</span>)/n
<span style="color: #228B22"># A seed just to ensure that the random numbers are the same for every run.</span>
<span style="color: #228B22"># Useful for eventual debugging.</span>
X = np.array( [ [ <span style="color: #B452CD">2</span>, <span style="color: #B452CD">0</span>], [<span style="color: #B452CD">0</span>, <span style="color: #B452CD">1</span>], [<span style="color: #B452CD">0</span>,<span style="color: #B452CD">0</span>]])
y = np.array( [<span style="color: #B452CD">4</span>, <span style="color: #B452CD">2</span>, <span style="color: #B452CD">3</span>])
<span style="color: #228B22"># matrix inversion to find beta</span>
OLSbeta = np.linalg.inv(X.T @ X) @ X.T @ y
<span style="color: #658b00">print</span>(OLSbeta)
<span style="color: #228B22"># and then make the prediction</span>
ytildeOLS = X @ OLSbeta
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;Training MSE for OLS&quot;</span>)
<span style="color: #658b00">print</span>(MSE(y,ytildeOLS))
ypredictOLS = X @ OLSbeta
<span style="color: #228B22"># Repeat now for Ridge regression and various values of the regularization parameter</span>
I = np.eye(<span style="color: #B452CD">2</span>,<span style="color: #B452CD">2</span>)
<span style="color: #228B22"># Decide which values of lambda to use</span>
nlambdas = <span style="color: #B452CD">100</span>
MSERidgePredict = np.zeros(nlambdas)
MSELassoPredict = np.zeros(nlambdas)
lambdas = np.logspace(-<span style="color: #B452CD">4</span>, <span style="color: #B452CD">4</span>, nlambdas)
<span style="color: #8B008B; font-weight: bold">for</span> i <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(nlambdas):
lmb = lambdas[i]
Ridgebeta = np.linalg.inv(X.T @ X+lmb*I) @ X.T @ y
<span style="color: #658b00">print</span>(Ridgebeta)
<span style="color: #228B22"># and then make the prediction</span>
ypredictRidge = X @ Ridgebeta
MSERidgePredict[i] = MSE(y,ypredictRidge)
RegLasso = linear_model.Lasso(lmb,fit_intercept=<span style="color: #8B008B; font-weight: bold">False</span>)
RegLasso.fit(X,y)
ypredictLasso = RegLasso.predict(X)
<span style="color: #658b00">print</span>(RegLasso.coef_)
MSELassoPredict[i] = MSE(y,ypredictLasso)
<span style="color: #228B22"># Now plot the results</span>
plt.figure()
plt.plot(np.log10(lambdas), MSERidgePredict, <span style="color: #CD5555">&#39;r--&#39;</span>, label = <span style="color: #CD5555">&#39;MSE Ridge Train&#39;</span>)
plt.plot(np.log10(lambdas), MSELassoPredict, <span style="color: #CD5555">&#39;r--&#39;</span>, label = <span style="color: #CD5555">&#39;MSE Lasso Train&#39;</span>)
plt.xlabel(<span style="color: #CD5555">&#39;log10(lambda)&#39;</span>)
plt.ylabel(<span style="color: #CD5555">&#39;MSE&#39;</span>)
plt.legend()
plt.show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="another-example-now-with-a-polynomial-fit">Another Example, now with a polynomial fit </h2>
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #eeeedd">
<pre style="line-height: 125%;"><span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">os</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">pandas</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">pd</span>
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.model_selection</span> <span style="color: #8B008B; font-weight: bold">import</span> train_test_split
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn</span> <span style="color: #8B008B; font-weight: bold">import</span> linear_model
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">R2</span>(y_data, y_model):
<span style="color: #8B008B; font-weight: bold">return</span> <span style="color: #B452CD">1</span> - np.sum((y_data - y_model) ** <span style="color: #B452CD">2</span>) / np.sum((y_data - np.mean(y_data)) ** <span style="color: #B452CD">2</span>)
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">MSE</span>(y_data,y_model):
n = np.size(y_model)
<span style="color: #8B008B; font-weight: bold">return</span> np.sum((y_data-y_model)**<span style="color: #B452CD">2</span>)/n
<span style="color: #228B22"># A seed just to ensure that the random numbers are the same for every run.</span>
<span style="color: #228B22"># Useful for eventual debugging.</span>
np.random.seed(<span style="color: #B452CD">3155</span>)
x = np.random.rand(<span style="color: #B452CD">100</span>)
y = <span style="color: #B452CD">2.0</span>+<span style="color: #B452CD">5</span>*x*x+<span style="color: #B452CD">0.1</span>*np.random.randn(<span style="color: #B452CD">100</span>)
<span style="color: #228B22"># number of features p (here degree of polynomial</span>
p = <span style="color: #B452CD">3</span>
<span style="color: #228B22"># The design matrix now as function of a given polynomial</span>
X = np.zeros((<span style="color: #658b00">len</span>(x),p))
X[:,<span style="color: #B452CD">0</span>] = <span style="color: #B452CD">1.0</span>
X[:,<span style="color: #B452CD">1</span>] = x
X[:,<span style="color: #B452CD">2</span>] = x*x
<span style="color: #228B22"># We split the data in test and training data</span>
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=<span style="color: #B452CD">0.2</span>)
<span style="color: #228B22"># matrix inversion to find beta</span>
OLSbeta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train
<span style="color: #658b00">print</span>(OLSbeta)
<span style="color: #228B22"># and then make the prediction</span>
ytildeOLS = X_train @ OLSbeta
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;Training MSE for OLS&quot;</span>)
<span style="color: #658b00">print</span>(MSE(y_train,ytildeOLS))
ypredictOLS = X_test @ OLSbeta
<span style="color: #658b00">print</span>(<span style="color: #CD5555">&quot;Test MSE OLS&quot;</span>)
<span style="color: #658b00">print</span>(MSE(y_test,ypredictOLS))
<span style="color: #228B22"># Repeat now for Lasso and Ridge regression and various values of the regularization parameter</span>
I = np.eye(p,p)
<span style="color: #228B22"># Decide which values of lambda to use</span>
nlambdas = <span style="color: #B452CD">100</span>
MSEPredict = np.zeros(nlambdas)
MSETrain = np.zeros(nlambdas)
MSELassoPredict = np.zeros(nlambdas)
MSELassoTrain = np.zeros(nlambdas)
lambdas = np.logspace(-<span style="color: #B452CD">4</span>, <span style="color: #B452CD">4</span>, nlambdas)
<span style="color: #8B008B; font-weight: bold">for</span> i <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(nlambdas):
lmb = lambdas[i]
Ridgebeta = np.linalg.inv(X_train.T @ X_train+lmb*I) @ X_train.T @ y_train
<span style="color: #228B22"># include lasso using Scikit-Learn</span>
RegLasso = linear_model.Lasso(lmb,fit_intercept=<span style="color: #8B008B; font-weight: bold">False</span>)
RegLasso.fit(X_train,y_train)
<span style="color: #228B22"># and then make the prediction</span>
ytildeRidge = X_train @ Ridgebeta
ypredictRidge = X_test @ Ridgebeta
ytildeLasso = RegLasso.predict(X_train)
ypredictLasso = RegLasso.predict(X_test)
MSEPredict[i] = MSE(y_test,ypredictRidge)
MSETrain[i] = MSE(y_train,ytildeRidge)
MSELassoPredict[i] = MSE(y_test,ypredictLasso)
MSELassoTrain[i] = MSE(y_train,ytildeLasso)
<span style="color: #228B22"># Now plot the results</span>
plt.figure()
plt.plot(np.log10(lambdas), MSETrain, label = <span style="color: #CD5555">&#39;MSE Ridge train&#39;</span>)
plt.plot(np.log10(lambdas), MSEPredict, <span style="color: #CD5555">&#39;r--&#39;</span>, label = <span style="color: #CD5555">&#39;MSE Ridge Test&#39;</span>)
plt.plot(np.log10(lambdas), MSELassoTrain, label = <span style="color: #CD5555">&#39;MSE Lasso train&#39;</span>)
plt.plot(np.log10(lambdas), MSELassoPredict, <span style="color: #CD5555">&#39;r--&#39;</span>, label = <span style="color: #CD5555">&#39;MSE Lasso Test&#39;</span>)
plt.xlabel(<span style="color: #CD5555">&#39;log10(lambda)&#39;</span>)
plt.ylabel(<span style="color: #CD5555">&#39;MSE&#39;</span>)
plt.legend()
plt.show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- ------------------- end of main content --------------- -->
<center style="font-size:80%">
<!-- copyright --> &copy; 1999-2025, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
</center>
</body>
</html>