Files
FYS-STK4155/doc/pub/week40/html/week40.html
T
Morten Hjorth-Jensen 7fdec91b02 update week 40
2025-09-29 07:24:45 +02:00

1989 lines
125 KiB
HTML

<!--
HTML file automatically generated from DocOnce source
(https://github.com/doconce/doconce/)
doconce format html week40.do.txt --pygments_html_style=default --html_style=bloodish --html_links_in_new_window --html_output=week40 --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 40: Gradient descent methods (continued) and start Neural networks">
<title>Week 40: Gradient descent methods (continued) and start Neural networks</title>
<style type="text/css">
/* bloodish style */
body {
font-family: Helvetica, Verdana, Arial, Sans-serif;
color: #404040;
background: #ffffff;
}
h1 { font-size: 1.8em; color: #8A0808; }
h2 { font-size: 1.6em; color: #8A0808; }
h3 { font-size: 1.4em; color: #8A0808; }
h4 { font-size: 1.2em; color: #8A0808; }
a { color: #8A0808; text-decoration:none; }
tt { font-family: "Courier New", Courier; }
p { text-indent: 0px; }
hr { border: 0; width: 80%; border-bottom: 1px solid #aaa}
p.caption { width: 80%; font-style: normal; text-align: left; }
hr.figure { border: 0; width: 80%; border-bottom: 1px solid #aaa; }div.highlight {
border: 1px solid #cfcfcf;
border-radius: 2px;
line-height: 1.21429em;
}
div.cell {
width: 100%;
padding: 5px 5px 5px 0;
margin: 0;
outline: none;
}
div.input {
page-break-inside: avoid;
box-orient: horizontal;
box-align: stretch;
display: flex;
flex-direction: row;
align-items: stretch;
}
div.inner_cell {
box-orient: vertical;
box-align: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
box-flex: 1;
flex: 1;
}
div.input_area {
border: 1px solid #cfcfcf;
border-radius: 4px;
background: #f7f7f7;
line-height: 1.21429em;
}
div.input_area > div.highlight {
margin: .4em;
border: none;
padding: 0;
background-color: transparent;
}
div.output_wrapper {
position: relative;
box-orient: vertical;
box-align: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
}
.output {
box-orient: vertical;
box-align: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
}
div.output_area {
padding: 0;
page-break-inside: avoid;
box-orient: horizontal;
box-align: stretch;
display: flex;
flex-direction: row;
align-items: stretch;
}
div.output_subarea {
padding: .4em .4em 0 .4em;
box-flex: 1;
flex: 1;
}
div.output_text {
text-align: left;
color: #000;
line-height: 1.21429em;
}
.alert-text-small { font-size: 80%; }
.alert-text-large { font-size: 130%; }
.alert-text-normal { font-size: 90%; }
.alert {
padding:8px 35px 8px 14px; margin-bottom:18px;
text-shadow:0 1px 0 rgba(255,255,255,0.5);
border:1px solid #bababa;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
color: #555;
background-color: #f8f8f8;
background-position: 10px 5px;
background-repeat: no-repeat;
background-size: 38px;
padding-left: 55px;
width: 75%;
}
.alert-block {padding-top:14px; padding-bottom:14px}
.alert-block > p, .alert-block > ul {margin-bottom:1em}
.alert li {margin-top: 1em}
.alert-block p+p {margin-top:5px}
.alert-notice { background-image: url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_notice.png); }
.alert-summary { background-image:url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_summary.png); }
.alert-warning { background-image: url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_warning.png); }
.alert-question {background-image:url(https://cdn.rawgit.com/doconce/doconce/master/bundled/html_images/small_gray_question.png); }
div { text-align: justify; text-justify: inter-word; }
.tab {
padding-left: 1.5em;
}
div.toc p,a {
line-height: 1.3;
margin-top: 1.1;
margin-bottom: 1.1;
}
</style>
</head>
<!-- tocinfo
{'highest level': 2,
'sections': [('Lecture Monday September 29, 2025',
2,
None,
'lecture-monday-september-29-2025'),
('Suggested readings and videos',
2,
None,
'suggested-readings-and-videos'),
('Lab sessions Tuesday and Wednesday',
2,
None,
'lab-sessions-tuesday-and-wednesday'),
('Logistic Regression, from last week',
2,
None,
'logistic-regression-from-last-week'),
('Classification problems', 2, None, 'classification-problems'),
('Optimization and Deep learning',
2,
None,
'optimization-and-deep-learning'),
('Basics', 2, None, 'basics'),
('Two parameters', 2, None, 'two-parameters'),
('Maximum likelihood', 2, None, 'maximum-likelihood'),
('The cost function rewritten',
2,
None,
'the-cost-function-rewritten'),
('Minimizing the cross entropy',
2,
None,
'minimizing-the-cross-entropy'),
('A more compact expression',
2,
None,
'a-more-compact-expression'),
('Extending to more predictors',
2,
None,
'extending-to-more-predictors'),
('Including more classes', 2, None, 'including-more-classes'),
('More classes', 2, None, 'more-classes'),
('Optimization, the central part of any Machine Learning '
'algortithm',
2,
None,
'optimization-the-central-part-of-any-machine-learning-algortithm'),
('Revisiting our Logistic Regression case',
2,
None,
'revisiting-our-logistic-regression-case'),
('The equations to solve', 2, None, 'the-equations-to-solve'),
("Solving using Newton-Raphson's method",
2,
None,
'solving-using-newton-raphson-s-method'),
('Example code for Logistic Regression',
2,
None,
'example-code-for-logistic-regression'),
('Synthetic data generation',
3,
None,
'synthetic-data-generation'),
('Using _Scikit-learn_', 2, None, 'using-scikit-learn'),
('Using the correlation matrix',
2,
None,
'using-the-correlation-matrix'),
('Discussing the correlation data',
2,
None,
'discussing-the-correlation-data'),
('Other measures in classification studies',
2,
None,
'other-measures-in-classification-studies'),
('Introduction to Neural networks',
2,
None,
'introduction-to-neural-networks'),
('Artificial neurons', 2, None, 'artificial-neurons'),
('Neural network types', 2, None, 'neural-network-types'),
('Feed-forward neural networks',
2,
None,
'feed-forward-neural-networks'),
('Convolutional Neural Network',
2,
None,
'convolutional-neural-network'),
('Recurrent neural networks',
2,
None,
'recurrent-neural-networks'),
('Other types of networks', 2, None, 'other-types-of-networks'),
('Multilayer perceptrons', 2, None, 'multilayer-perceptrons'),
('Why multilayer perceptrons?',
2,
None,
'why-multilayer-perceptrons'),
('Illustration of a single perceptron model and a '
'multi-perceptron model',
2,
None,
'illustration-of-a-single-perceptron-model-and-a-multi-perceptron-model'),
('Examples of XOR, OR and AND gates',
2,
None,
'examples-of-xor-or-and-and-gates'),
('Does Logistic Regression do a better Job?',
2,
None,
'does-logistic-regression-do-a-better-job'),
('Adding Neural Networks', 2, None, 'adding-neural-networks'),
('Mathematical model', 2, None, 'mathematical-model'),
('Mathematical model', 2, None, 'mathematical-model'),
('Mathematical model', 2, None, 'mathematical-model'),
('Mathematical model', 2, None, 'mathematical-model'),
('Mathematical model', 2, None, 'mathematical-model'),
('Matrix-vector notation', 3, None, 'matrix-vector-notation'),
('Matrix-vector notation and activation',
3,
None,
'matrix-vector-notation-and-activation'),
('Activation functions', 3, None, 'activation-functions'),
('Activation functions, Logistic and Hyperbolic ones',
3,
None,
'activation-functions-logistic-and-hyperbolic-ones'),
('Relevance', 3, None, 'relevance')]}
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 40: Gradient descent methods (continued) and start Neural networks</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 29-October 3, 2025</h4>
</center> <!-- date -->
<br>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="lecture-monday-september-29-2025">Lecture Monday September 29, 2025 </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b></b>
<p>
<ol>
<li> Logistic regression and gradient descent, examples on how to code
<!-- o Automatic differentiation and gradient descent, examples using Logistic regression --></li>
<li> Start with the basics of Neural Networks, setting up the basic steps, from the simple perceptron model to the multi-layer perceptron model
<!-- o <a href="https://youtu.be/jdJoOrCIdII" target="_blank">Video of lecture</a> -->
<!-- o Whiteboard notes at <a href="https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2024/NotesSeptember30.pdf" target="_blank"><tt>https://github.com/CompPhysics/MachineLearning/blob/master/doc/HandWrittenNotes/2024/NotesSeptember30.pdf</tt></a> --></li>
</ol>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="suggested-readings-and-videos">Suggested readings and videos </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b>Readings and Videos:</b>
<p>
<ol>
<li> The lecture notes for week 40 (these notes)
<!-- o For a good discussion on gradient methods, we would like to recommend Goodfellow et al section 4.3-4.5 and# sections 8.3-8.6. We will come back to the latter chapter in our discussion of Neural networks as well. --></li>
<li> For neural networks we recommend Goodfellow et al chapter 6 and Raschka et al chapter 2 (contains also material about gradient descent) and chapter 11 (we will use this next week)
<!-- o 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> -->
<!-- o Video on automatic differentiation at <a href="https://www.youtube.com/watch?v=wG_nF1awSSY" target="_blank"><tt>https://www.youtube.com/watch?v=wG_nF1awSSY</tt></a> --></li>
<li> Neural Networks demystified at <a href="https://www.youtube.com/watch?v=bxe2T-V8XRs&list=PLiaHhY2iBX9hdHaRr6b7XevZtgZRa1PoU&ab_channel=WelchLabs" target="_blank"><tt>https://www.youtube.com/watch?v=bxe2T-V8XRs&list=PLiaHhY2iBX9hdHaRr6b7XevZtgZRa1PoU&ab_channel=WelchLabs</tt></a></li>
<li> Building Neural Networks from scratch at URL:https://www.youtube.com/watch?v=Wo5dMEP_BbI&list=PLQVvvaa0QuDcjD5BAw2DxE6OF2tius3V3&ab_channel=sentdex"</li>
</ol>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="lab-sessions-tuesday-and-wednesday">Lab sessions Tuesday and Wednesday </h2>
<div class="alert alert-block alert-block alert-text-normal">
<b>Material for the active learning sessions on Tuesday and Wednesday</b>
<p>
<ul>
<li> Work on project 1 and discussions on how to structure your report</li>
<li> No weekly exercises for week 40, project work only</li>
<li> Video on how to write scientific reports recorded during one of the lab sessions at <a href="https://youtu.be/tVW1ZDmZnwM" target="_blank"><tt>https://youtu.be/tVW1ZDmZnwM</tt></a></li>
<li> A general guideline can be found at <a href="https://github.com/CompPhysics/MachineLearning/blob/master/doc/Projects/EvaluationGrading/EvaluationForm.md" target="_blank"><tt>https://github.com/CompPhysics/MachineLearning/blob/master/doc/Projects/EvaluationGrading/EvaluationForm.md</tt></a>.</li>
</ul>
</div>
<!-- !split -->
<h2 id="logistic-regression-from-last-week">Logistic Regression, from last week </h2>
<p>In linear regression our main interest was centered on learning the
coefficients of a functional fit (say a polynomial) in order to be
able to predict the response of a continuous variable on some unseen
data. The fit to the continuous variable \( y_i \) is based on some
independent variables \( \boldsymbol{x}_i \). Linear regression resulted in
analytical expressions for standard ordinary Least Squares or Ridge
regression (in terms of matrices to invert) for several quantities,
ranging from the variance and thereby the confidence intervals of the
parameters \( \boldsymbol{\theta} \) to the mean squared error. If we can invert
the product of the design matrices, linear regression gives then a
simple recipe for fitting our data.
</p>
<!-- !split -->
<h2 id="classification-problems">Classification problems </h2>
<p>Classification problems, however, are concerned with outcomes taking
the form of discrete variables (i.e. categories). We may for example,
on the basis of DNA sequencing for a number of patients, like to find
out which mutations are important for a certain disease; or based on
scans of various patients' brains, figure out if there is a tumor or
not; or given a specific physical system, we'd like to identify its
state, say whether it is an ordered or disordered system (typical
situation in solid state physics); or classify the status of a
patient, whether she/he has a stroke or not and many other similar
situations.
</p>
<p>The most common situation we encounter when we apply logistic
regression is that of two possible outcomes, normally denoted as a
binary outcome, true or false, positive or negative, success or
failure etc.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="optimization-and-deep-learning">Optimization and Deep learning </h2>
<p>Logistic regression will also serve as our stepping stone towards
neural network algorithms and supervised deep learning. For logistic
learning, the minimization of the cost function leads to a non-linear
equation in the parameters \( \boldsymbol{\theta} \). The optimization of the
problem calls therefore for minimization algorithms.
</p>
<p>As we have discussed earlier, this forms the
bottle neck of all machine learning algorithms, namely how to find
reliable minima of a multi-variable function. This leads us to the
family of gradient descent methods. The latter are the working horses
of basically all modern machine learning algorithms.
</p>
<p>We note also that many of the topics discussed here on logistic
regression are also commonly used in modern supervised Deep Learning
models, as we will see later.
</p>
<!-- !split -->
<h2 id="basics">Basics </h2>
<p>We consider the case where the outputs/targets, also called the
responses or the outcomes, \( y_i \) are discrete and only take values
from \( k=0,\dots,K-1 \) (i.e. \( K \) classes).
</p>
<p>The goal is to predict the
output classes from the design matrix \( \boldsymbol{X}\in\mathbb{R}^{n\times p} \)
made of \( n \) samples, each of which carries \( p \) features or predictors. The
primary goal is to identify the classes to which new unseen samples
belong.
</p>
<p>Last week we specialized to the case of two classes only, with outputs
\( y_i=0 \) and \( y_i=1 \). Our outcomes could represent the status of a
credit card user that could default or not on her/his credit card
debt. That is
</p>
$$
y_i = \begin{bmatrix} 0 & \mathrm{no}\\ 1 & \mathrm{yes} \end{bmatrix}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="two-parameters">Two parameters </h2>
<p>We assume now that we have two classes with \( y_i \) either \( 0 \) or \( 1 \). Furthermore we assume also that we have only two parameters \( \theta \) in our fitting of the Sigmoid function, that is we define probabilities </p>
$$
\begin{align*}
p(y_i=1|x_i,\boldsymbol{\theta}) &= \frac{\exp{(\theta_0+\theta_1x_i)}}{1+\exp{(\theta_0+\theta_1x_i)}},\nonumber\\
p(y_i=0|x_i,\boldsymbol{\theta}) &= 1 - p(y_i=1|x_i,\boldsymbol{\theta}),
\end{align*}
$$
<p>where \( \boldsymbol{\theta} \) are the weights we wish to extract from data, in our case \( \theta_0 \) and \( \theta_1 \). </p>
<p>Note that we used</p>
$$
p(y_i=0\vert x_i, \boldsymbol{\theta}) = 1-p(y_i=1\vert x_i, \boldsymbol{\theta}).
$$
<!-- !split -->
<h2 id="maximum-likelihood">Maximum likelihood </h2>
<p>In order to define the total likelihood for all possible outcomes from a
dataset \( \mathcal{D}=\{(y_i,x_i)\} \), with the binary labels
\( y_i\in\{0,1\} \) and where the data points are drawn independently, we use the so-called <a href="https://en.wikipedia.org/wiki/Maximum_likelihood_estimation" target="_blank">Maximum Likelihood Estimation</a> (MLE) principle.
We aim thus at maximizing
the probability of seeing the observed data. We can then approximate the
likelihood in terms of the product of the individual probabilities of a specific outcome \( y_i \), that is
</p>
$$
\begin{align*}
P(\mathcal{D}|\boldsymbol{\theta})& = \prod_{i=1}^n \left[p(y_i=1|x_i,\boldsymbol{\theta})\right]^{y_i}\left[1-p(y_i=1|x_i,\boldsymbol{\theta}))\right]^{1-y_i}\nonumber \\
\end{align*}
$$
<p>from which we obtain the log-likelihood and our <b>cost/loss</b> function</p>
$$
\mathcal{C}(\boldsymbol{\theta}) = \sum_{i=1}^n \left( y_i\log{p(y_i=1|x_i,\boldsymbol{\theta})} + (1-y_i)\log\left[1-p(y_i=1|x_i,\boldsymbol{\theta}))\right]\right).
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-cost-function-rewritten">The cost function rewritten </h2>
<p>Reordering the logarithms, we can rewrite the <b>cost/loss</b> function as</p>
$$
\mathcal{C}(\boldsymbol{\theta}) = \sum_{i=1}^n \left(y_i(\theta_0+\theta_1x_i) -\log{(1+\exp{(\theta_0+\theta_1x_i)})}\right).
$$
<p>The maximum likelihood estimator is defined as the set of parameters that maximize the log-likelihood where we maximize with respect to \( \theta \).
Since the cost (error) function is just the negative log-likelihood, for logistic regression we have that
</p>
$$
\mathcal{C}(\boldsymbol{\theta})=-\sum_{i=1}^n \left(y_i(\theta_0+\theta_1x_i) -\log{(1+\exp{(\theta_0+\theta_1x_i)})}\right).
$$
<p>This equation is known in statistics as the <b>cross entropy</b>. Finally, we note that just as in linear regression,
in practice we often supplement the cross-entropy with additional regularization terms, usually \( L_1 \) and \( L_2 \) regularization as we did for Ridge and Lasso regression.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="minimizing-the-cross-entropy">Minimizing the cross entropy </h2>
<p>The cross entropy is a convex function of the weights \( \boldsymbol{\theta} \) and,
therefore, any local minimizer is a global minimizer.
</p>
<p>Minimizing this
cost function with respect to the two parameters \( \theta_0 \) and \( \theta_1 \) we obtain
</p>
$$
\frac{\partial \mathcal{C}(\boldsymbol{\theta})}{\partial \theta_0} = -\sum_{i=1}^n \left(y_i -\frac{\exp{(\theta_0+\theta_1x_i)}}{1+\exp{(\theta_0+\theta_1x_i)}}\right),
$$
<p>and </p>
$$
\frac{\partial \mathcal{C}(\boldsymbol{\theta})}{\partial \theta_1} = -\sum_{i=1}^n \left(y_ix_i -x_i\frac{\exp{(\theta_0+\theta_1x_i)}}{1+\exp{(\theta_0+\theta_1x_i)}}\right).
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="a-more-compact-expression">A more compact expression </h2>
<p>Let us now define a vector \( \boldsymbol{y} \) with \( n \) elements \( y_i \), an
\( n\times p \) matrix \( \boldsymbol{X} \) which contains the \( x_i \) values and a
vector \( \boldsymbol{p} \) of fitted probabilities \( p(y_i\vert x_i,\boldsymbol{\theta}) \). We can rewrite in a more compact form the first
derivative of the cost function as
</p>
$$
\frac{\partial \mathcal{C}(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}} = -\boldsymbol{X}^T\left(\boldsymbol{y}-\boldsymbol{p}\right).
$$
<p>If we in addition define a diagonal matrix \( \boldsymbol{W} \) with elements
\( p(y_i\vert x_i,\boldsymbol{\theta})(1-p(y_i\vert x_i,\boldsymbol{\theta}) \), we can obtain a compact expression of the second derivative as
</p>
$$
\frac{\partial^2 \mathcal{C}(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}\partial \boldsymbol{\theta}^T} = \boldsymbol{X}^T\boldsymbol{W}\boldsymbol{X}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="extending-to-more-predictors">Extending to more predictors </h2>
<p>Within a binary classification problem, we can easily expand our model to include multiple predictors. Our ratio between likelihoods is then with \( p \) predictors</p>
$$
\log{ \frac{p(\boldsymbol{\theta}\boldsymbol{x})}{1-p(\boldsymbol{\theta}\boldsymbol{x})}} = \theta_0+\theta_1x_1+\theta_2x_2+\dots+\theta_px_p.
$$
<p>Here we defined \( \boldsymbol{x}=[1,x_1,x_2,\dots,x_p] \) and \( \boldsymbol{\theta}=[\theta_0, \theta_1, \dots, \theta_p] \) leading to</p>
$$
p(\boldsymbol{\theta}\boldsymbol{x})=\frac{ \exp{(\theta_0+\theta_1x_1+\theta_2x_2+\dots+\theta_px_p)}}{1+\exp{(\theta_0+\theta_1x_1+\theta_2x_2+\dots+\theta_px_p)}}.
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="including-more-classes">Including more classes </h2>
<p>Till now we have mainly focused on two classes, the so-called binary
system. Suppose we wish to extend to \( K \) classes. Let us for the sake
of simplicity assume we have only two predictors. We have then following model
</p>
$$
\log{\frac{p(C=1\vert x)}{p(K\vert x)}} = \theta_{10}+\theta_{11}x_1,
$$
<p>and </p>
$$
\log{\frac{p(C=2\vert x)}{p(K\vert x)}} = \theta_{20}+\theta_{21}x_1,
$$
<p>and so on till the class \( C=K-1 \) class</p>
$$
\log{\frac{p(C=K-1\vert x)}{p(K\vert x)}} = \theta_{(K-1)0}+\theta_{(K-1)1}x_1,
$$
<p>and the model is specified in term of \( K-1 \) so-called log-odds or
<b>logit</b> transformations.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="more-classes">More classes </h2>
<p>In our discussion of neural networks we will encounter the above again
in terms of a slightly modified function, the so-called <b>Softmax</b> function.
</p>
<p>The softmax function is used in various multiclass classification
methods, such as multinomial logistic regression (also known as
softmax regression), multiclass linear discriminant analysis, naive
Bayes classifiers, and artificial neural networks. Specifically, in
multinomial logistic regression and linear discriminant analysis, the
input to the function is the result of \( K \) distinct linear functions,
and the predicted probability for the \( k \)-th class given a sample
vector \( \boldsymbol{x} \) and a weighting vector \( \boldsymbol{\theta} \) is (with two
predictors):
</p>
$$
p(C=k\vert \mathbf {x} )=\frac{\exp{(\theta_{k0}+\theta_{k1}x_1)}}{1+\sum_{l=1}^{K-1}\exp{(\theta_{l0}+\theta_{l1}x_1)}}.
$$
<p>It is easy to extend to more predictors. The final class is </p>
$$
p(C=K\vert \mathbf {x} )=\frac{1}{1+\sum_{l=1}^{K-1}\exp{(\theta_{l0}+\theta_{l1}x_1)}},
$$
<p>and they sum to one. Our earlier discussions were all specialized to
the case with two classes only. It is easy to see from the above that
what we derived earlier is compatible with these equations.
</p>
<p>To find the optimal parameters we would typically use a gradient
descent method. Newton's method and gradient descent methods are
discussed in the material on <a href="https://compphysics.github.io/MachineLearning/doc/pub/Splines/html/Splines-bs.html" target="_blank">optimization
methods</a>.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="optimization-the-central-part-of-any-machine-learning-algortithm">Optimization, 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="revisiting-our-logistic-regression-case">Revisiting our Logistic Regression case </h2>
<p>In our discussion on Logistic Regression we studied the
case of
two classes, with \( y_i \) either
\( 0 \) or \( 1 \). Furthermore we assumed also that we have only two
parameters \( \theta \) in our fitting, that is we
defined probabilities
</p>
$$
\begin{align*}
p(y_i=1|x_i,\boldsymbol{\theta}) &= \frac{\exp{(\theta_0+\theta_1x_i)}}{1+\exp{(\theta_0+\theta_1x_i)}},\nonumber\\
p(y_i=0|x_i,\boldsymbol{\theta}) &= 1 - p(y_i=1|x_i,\boldsymbol{\theta}),
\end{align*}
$$
<p>where \( \boldsymbol{\theta} \) are the weights we wish to extract from data, in our case \( \theta_0 \) and \( \theta_1 \). </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="the-equations-to-solve">The equations to solve </h2>
<p>Our compact equations used a definition of a vector \( \boldsymbol{y} \) with \( n \)
elements \( y_i \), an \( n\times p \) matrix \( \boldsymbol{X} \) which contains the
\( x_i \) values and a vector \( \boldsymbol{p} \) of fitted probabilities
\( p(y_i\vert x_i,\boldsymbol{\theta}) \). We rewrote in a more compact form
the first derivative of the cost function as
</p>
$$
\frac{\partial \mathcal{C}(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}} = -\boldsymbol{X}^T\left(\boldsymbol{y}-\boldsymbol{p}\right).
$$
<p>If we in addition define a diagonal matrix \( \boldsymbol{W} \) with elements
\( p(y_i\vert x_i,\boldsymbol{\theta})(1-p(y_i\vert x_i,\boldsymbol{\theta}) \), we can obtain a compact expression of the second derivative as
</p>
$$
\frac{\partial^2 \mathcal{C}(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}\partial \boldsymbol{\theta}^T} = \boldsymbol{X}^T\boldsymbol{W}\boldsymbol{X}.
$$
<p>This defines what is called the Hessian matrix.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="solving-using-newton-raphson-s-method">Solving using Newton-Raphson's method </h2>
<p>If we can set up these equations, Newton-Raphson's iterative method is normally the method of choice. It requires however that we can compute in an efficient way the matrices that define the first and second derivatives. </p>
<p>Our iterative scheme is then given by</p>
$$
\boldsymbol{\theta}^{\mathrm{new}} = \boldsymbol{\theta}^{\mathrm{old}}-\left(\frac{\partial^2 \mathcal{C}(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}\partial \boldsymbol{\theta}^T}\right)^{-1}_{\boldsymbol{\theta}^{\mathrm{old}}}\times \left(\frac{\partial \mathcal{C}(\boldsymbol{\theta})}{\partial \boldsymbol{\theta}}\right)_{\boldsymbol{\theta}^{\mathrm{old}}},
$$
<p>or in matrix form as</p>
$$
\boldsymbol{\theta}^{\mathrm{new}} = \boldsymbol{\theta}^{\mathrm{old}}-\left(\boldsymbol{X}^T\boldsymbol{W}\boldsymbol{X} \right)^{-1}\times \left(-\boldsymbol{X}^T(\boldsymbol{y}-\boldsymbol{p}) \right)_{\boldsymbol{\theta}^{\mathrm{old}}}.
$$
<p>The right-hand side is computed with the old values of \( \theta \). </p>
<p>If we can compute these matrices, in particular the Hessian, the above is often the easiest method to implement. </p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="example-code-for-logistic-regression">Example code for Logistic Regression </h2>
<p>Here we make a class for Logistic regression. The code uses a simple data set and includes both a binary case and a multiclass case.</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">LogisticRegression</span>:
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Logistic Regression for binary and multiclass classification.</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">__init__</span>(<span style="color: #008000">self</span>, lr<span style="color: #666666">=0.01</span>, epochs<span style="color: #666666">=1000</span>, fit_intercept<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>, verbose<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">False</span>):
<span style="color: #008000">self</span><span style="color: #666666">.</span>lr <span style="color: #666666">=</span> lr <span style="color: #408080; font-style: italic"># Learning rate for gradient descent</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>epochs <span style="color: #666666">=</span> epochs <span style="color: #408080; font-style: italic"># Number of iterations</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>fit_intercept <span style="color: #666666">=</span> fit_intercept <span style="color: #408080; font-style: italic"># Whether to add intercept (bias)</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>verbose <span style="color: #666666">=</span> verbose <span style="color: #408080; font-style: italic"># Print loss during training if True</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>weights <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">None</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>multi_class <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">False</span> <span style="color: #408080; font-style: italic"># Will be determined at fit time</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">_add_intercept</span>(<span style="color: #008000">self</span>, X):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Add intercept term (column of ones) to feature matrix.&quot;&quot;&quot;</span>
intercept <span style="color: #666666">=</span> np<span style="color: #666666">.</span>ones((X<span style="color: #666666">.</span>shape[<span style="color: #666666">0</span>], <span style="color: #666666">1</span>))
<span style="color: #008000; font-weight: bold">return</span> np<span style="color: #666666">.</span>concatenate((intercept, X), axis<span style="color: #666666">=1</span>)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">_sigmoid</span>(<span style="color: #008000">self</span>, z):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Sigmoid function for binary logistic.&quot;&quot;&quot;</span>
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">1</span> <span style="color: #666666">/</span> (<span style="color: #666666">1</span> <span style="color: #666666">+</span> np<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>z))
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">_softmax</span>(<span style="color: #008000">self</span>, Z):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Softmax function for multiclass logistic.&quot;&quot;&quot;</span>
exp_Z <span style="color: #666666">=</span> np<span style="color: #666666">.</span>exp(Z <span style="color: #666666">-</span> np<span style="color: #666666">.</span>max(Z, axis<span style="color: #666666">=1</span>, keepdims<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>))
<span style="color: #008000; font-weight: bold">return</span> exp_Z <span style="color: #666666">/</span> np<span style="color: #666666">.</span>sum(exp_Z, axis<span style="color: #666666">=1</span>, keepdims<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">fit</span>(<span style="color: #008000">self</span>, X, y):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Train the logistic regression model using gradient descent.</span>
<span style="color: #BA2121; font-style: italic"> Supports binary (sigmoid) and multiclass (softmax) based on y.</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(X)
y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(y)
n_samples, n_features <span style="color: #666666">=</span> X<span style="color: #666666">.</span>shape
<span style="color: #408080; font-style: italic"># Add intercept if needed</span>
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>fit_intercept:
X <span style="color: #666666">=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>_add_intercept(X)
n_features <span style="color: #666666">+=</span> <span style="color: #666666">1</span>
<span style="color: #408080; font-style: italic"># Determine classes and mode (binary vs multiclass)</span>
unique_classes <span style="color: #666666">=</span> np<span style="color: #666666">.</span>unique(y)
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">len</span>(unique_classes) <span style="color: #666666">&gt;</span> <span style="color: #666666">2</span>:
<span style="color: #008000">self</span><span style="color: #666666">.</span>multi_class <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">True</span>
<span style="color: #008000; font-weight: bold">else</span>:
<span style="color: #008000">self</span><span style="color: #666666">.</span>multi_class <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">False</span>
<span style="color: #408080; font-style: italic"># ----- Multiclass case -----</span>
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>multi_class:
n_classes <span style="color: #666666">=</span> <span style="color: #008000">len</span>(unique_classes)
<span style="color: #408080; font-style: italic"># Map original labels to 0...n_classes-1</span>
class_to_index <span style="color: #666666">=</span> {c: idx <span style="color: #008000; font-weight: bold">for</span> idx, c <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">enumerate</span>(unique_classes)}
y_indices <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array([class_to_index[c] <span style="color: #008000; font-weight: bold">for</span> c <span style="color: #AA22FF; font-weight: bold">in</span> y])
<span style="color: #408080; font-style: italic"># Initialize weight matrix (features x classes)</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>weights <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros((n_features, n_classes))
<span style="color: #408080; font-style: italic"># One-hot encode y</span>
Y_onehot <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros((n_samples, n_classes))
Y_onehot[np<span style="color: #666666">.</span>arange(n_samples), y_indices] <span style="color: #666666">=</span> <span style="color: #666666">1</span>
<span style="color: #408080; font-style: italic"># Gradient descent</span>
<span style="color: #008000; font-weight: bold">for</span> epoch <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(<span style="color: #008000">self</span><span style="color: #666666">.</span>epochs):
scores <span style="color: #666666">=</span> X<span style="color: #666666">.</span>dot(<span style="color: #008000">self</span><span style="color: #666666">.</span>weights) <span style="color: #408080; font-style: italic"># Linear scores (n_samples x n_classes)</span>
probs <span style="color: #666666">=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>_softmax(scores) <span style="color: #408080; font-style: italic"># Probabilities (n_samples x n_classes)</span>
<span style="color: #408080; font-style: italic"># Compute gradient (features x classes)</span>
gradient <span style="color: #666666">=</span> (<span style="color: #666666">1</span> <span style="color: #666666">/</span> n_samples) <span style="color: #666666">*</span> X<span style="color: #666666">.</span>T<span style="color: #666666">.</span>dot(probs <span style="color: #666666">-</span> Y_onehot)
<span style="color: #408080; font-style: italic"># Update weights</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>weights <span style="color: #666666">-=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>lr <span style="color: #666666">*</span> gradient
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>verbose <span style="color: #AA22FF; font-weight: bold">and</span> epoch <span style="color: #666666">%</span> <span style="color: #666666">100</span> <span style="color: #666666">==</span> <span style="color: #666666">0</span>:
<span style="color: #408080; font-style: italic"># Compute current loss (categorical cross-entropy)</span>
loss <span style="color: #666666">=</span> <span style="color: #666666">-</span>np<span style="color: #666666">.</span>sum(Y_onehot <span style="color: #666666">*</span> np<span style="color: #666666">.</span>log(probs <span style="color: #666666">+</span> <span style="color: #666666">1e-15</span>)) <span style="color: #666666">/</span> n_samples
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;[Epoch </span><span style="color: #BB6688; font-weight: bold">{</span>epoch<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">] Multiclass loss: </span><span style="color: #BB6688; font-weight: bold">{</span>loss<span style="color: #BB6688; font-weight: bold">:</span><span style="color: #BA2121">.4f</span><span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># ----- Binary case -----</span>
<span style="color: #008000; font-weight: bold">else</span>:
<span style="color: #408080; font-style: italic"># Convert y to 0/1 if not already</span>
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #AA22FF; font-weight: bold">not</span> np<span style="color: #666666">.</span>array_equal(unique_classes, [<span style="color: #666666">0</span>, <span style="color: #666666">1</span>]):
<span style="color: #408080; font-style: italic"># Map the two classes to 0 and 1</span>
class0, class1 <span style="color: #666666">=</span> unique_classes
y_binary <span style="color: #666666">=</span> np<span style="color: #666666">.</span>where(y <span style="color: #666666">==</span> class1, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>)
<span style="color: #008000; font-weight: bold">else</span>:
y_binary <span style="color: #666666">=</span> y<span style="color: #666666">.</span>copy()<span style="color: #666666">.</span>astype(<span style="color: #008000">int</span>)
<span style="color: #408080; font-style: italic"># Initialize weights vector (features,)</span>
<span style="color: #008000">self</span><span style="color: #666666">.</span>weights <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros(n_features)
<span style="color: #408080; font-style: italic"># Gradient descent</span>
<span style="color: #008000; font-weight: bold">for</span> epoch <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(<span style="color: #008000">self</span><span style="color: #666666">.</span>epochs):
linear_model <span style="color: #666666">=</span> X<span style="color: #666666">.</span>dot(<span style="color: #008000">self</span><span style="color: #666666">.</span>weights) <span style="color: #408080; font-style: italic"># (n_samples,)</span>
probs <span style="color: #666666">=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>_sigmoid(linear_model) <span style="color: #408080; font-style: italic"># (n_samples,)</span>
<span style="color: #408080; font-style: italic"># Gradient for binary cross-entropy</span>
gradient <span style="color: #666666">=</span> (<span style="color: #666666">1</span> <span style="color: #666666">/</span> n_samples) <span style="color: #666666">*</span> X<span style="color: #666666">.</span>T<span style="color: #666666">.</span>dot(probs <span style="color: #666666">-</span> y_binary)
<span style="color: #008000">self</span><span style="color: #666666">.</span>weights <span style="color: #666666">-=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>lr <span style="color: #666666">*</span> gradient
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>verbose <span style="color: #AA22FF; font-weight: bold">and</span> epoch <span style="color: #666666">%</span> <span style="color: #666666">100</span> <span style="color: #666666">==</span> <span style="color: #666666">0</span>:
<span style="color: #408080; font-style: italic"># Compute binary cross-entropy loss</span>
loss <span style="color: #666666">=</span> <span style="color: #666666">-</span>np<span style="color: #666666">.</span>mean(
y_binary <span style="color: #666666">*</span> np<span style="color: #666666">.</span>log(probs <span style="color: #666666">+</span> <span style="color: #666666">1e-15</span>) <span style="color: #666666">+</span>
(<span style="color: #666666">1</span> <span style="color: #666666">-</span> y_binary) <span style="color: #666666">*</span> np<span style="color: #666666">.</span>log(<span style="color: #666666">1</span> <span style="color: #666666">-</span> probs <span style="color: #666666">+</span> <span style="color: #666666">1e-15</span>)
)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;[Epoch </span><span style="color: #BB6688; font-weight: bold">{</span>epoch<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">] Binary loss: </span><span style="color: #BB6688; font-weight: bold">{</span>loss<span style="color: #BB6688; font-weight: bold">:</span><span style="color: #BA2121">.4f</span><span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">predict_prob</span>(<span style="color: #008000">self</span>, X):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Compute probability estimates. Returns a 1D array for binary or</span>
<span style="color: #BA2121; font-style: italic"> a 2D array (n_samples x n_classes) for multiclass.</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(X)
<span style="color: #408080; font-style: italic"># Add intercept if the model used it</span>
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>fit_intercept:
X <span style="color: #666666">=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>_add_intercept(X)
scores <span style="color: #666666">=</span> X<span style="color: #666666">.</span>dot(<span style="color: #008000">self</span><span style="color: #666666">.</span>weights)
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>multi_class:
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>_softmax(scores)
<span style="color: #008000; font-weight: bold">else</span>:
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>_sigmoid(scores)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">predict</span>(<span style="color: #008000">self</span>, X):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Predict class labels for samples in X.</span>
<span style="color: #BA2121; font-style: italic"> Returns integer class labels (0,1 for binary, or 0...C-1 for multiclass).</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
probs <span style="color: #666666">=</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>predict_prob(X)
<span style="color: #008000; font-weight: bold">if</span> <span style="color: #008000">self</span><span style="color: #666666">.</span>multi_class:
<span style="color: #408080; font-style: italic"># Choose class with highest probability</span>
<span style="color: #008000; font-weight: bold">return</span> np<span style="color: #666666">.</span>argmax(probs, axis<span style="color: #666666">=1</span>)
<span style="color: #008000; font-weight: bold">else</span>:
<span style="color: #408080; font-style: italic"># Threshold at 0.5 for binary</span>
<span style="color: #008000; font-weight: bold">return</span> (probs <span style="color: #666666">&gt;=</span> <span style="color: #666666">0.5</span>)<span style="color: #666666">.</span>astype(<span style="color: #008000">int</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>The class implements the sigmoid and softmax internally. During fit(),
we check the number of classes: if more than 2, we set
self.multi_class=True and perform multinomial logistic regression. We
one-hot encode the target vector and update a weight matrix with
softmax probabilities. Otherwise, we do standard binary logistic
regression, converting labels to 0/1 if needed and updating a weight
vector. In both cases we use batch gradient descent on the
cross-entropy loss (we add a small epsilon 1e-15 to logs for numerical
stability). Progress (loss) can be printed if verbose=True.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># Evaluation Metrics</span>
<span style="color: #408080; font-style: italic">#We define helper functions for accuracy and cross-entropy loss. Accuracy is the fraction of correct predictions . For loss, we compute the appropriate cross-entropy:</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">accuracy_score</span>(y_true, y_pred):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Accuracy = (# correct predictions) / (total samples).&quot;&quot;&quot;</span>
y_true <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(y_true)
y_pred <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(y_pred)
<span style="color: #008000; font-weight: bold">return</span> np<span style="color: #666666">.</span>mean(y_true <span style="color: #666666">==</span> y_pred)
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">binary_cross_entropy</span>(y_true, y_prob):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Binary cross-entropy loss.</span>
<span style="color: #BA2121; font-style: italic"> y_true: true binary labels (0 or 1), y_prob: predicted probabilities for class 1.</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
y_true <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(y_true)
y_prob <span style="color: #666666">=</span> np<span style="color: #666666">.</span>clip(np<span style="color: #666666">.</span>array(y_prob), <span style="color: #666666">1e-15</span>, <span style="color: #666666">1-1e-15</span>)
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #666666">-</span>np<span style="color: #666666">.</span>mean(y_true <span style="color: #666666">*</span> np<span style="color: #666666">.</span>log(y_prob) <span style="color: #666666">+</span> (<span style="color: #666666">1</span> <span style="color: #666666">-</span> y_true) <span style="color: #666666">*</span> np<span style="color: #666666">.</span>log(<span style="color: #666666">1</span> <span style="color: #666666">-</span> y_prob))
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">categorical_cross_entropy</span>(y_true, y_prob):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Categorical cross-entropy loss for multiclass.</span>
<span style="color: #BA2121; font-style: italic"> y_true: true labels (0...C-1), y_prob: array of predicted probabilities (n_samples x C).</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
y_true <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(y_true, dtype<span style="color: #666666">=</span><span style="color: #008000">int</span>)
y_prob <span style="color: #666666">=</span> np<span style="color: #666666">.</span>clip(np<span style="color: #666666">.</span>array(y_prob), <span style="color: #666666">1e-15</span>, <span style="color: #666666">1-1e-15</span>)
<span style="color: #408080; font-style: italic"># One-hot encode true labels</span>
n_samples, n_classes <span style="color: #666666">=</span> y_prob<span style="color: #666666">.</span>shape
one_hot <span style="color: #666666">=</span> np<span style="color: #666666">.</span>zeros_like(y_prob)
one_hot[np<span style="color: #666666">.</span>arange(n_samples), y_true] <span style="color: #666666">=</span> <span style="color: #666666">1</span>
<span style="color: #408080; font-style: italic"># Compute cross-entropy</span>
loss_vec <span style="color: #666666">=</span> <span style="color: #666666">-</span>np<span style="color: #666666">.</span>sum(one_hot <span style="color: #666666">*</span> np<span style="color: #666666">.</span>log(y_prob), axis<span style="color: #666666">=1</span>)
<span style="color: #008000; font-weight: bold">return</span> np<span style="color: #666666">.</span>mean(loss_vec)
</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>
<h3 id="synthetic-data-generation">Synthetic data generation </h3>
<p>Binary classification data: Create two Gaussian clusters in 2D. For example, class 0 around mean [-2,-2] and class 1 around [2,2].
Multiclass data: Create several Gaussian clusters (one per class) spread out in feature space.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">generate_binary_data</span>(n_samples<span style="color: #666666">=100</span>, n_features<span style="color: #666666">=2</span>, random_state<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">None</span>):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Generate synthetic binary classification data.</span>
<span style="color: #BA2121; font-style: italic"> Returns (X, y) where X is (n_samples x n_features), y in {0,1}.</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
rng <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>RandomState(random_state)
<span style="color: #408080; font-style: italic"># Half samples for class 0, half for class 1</span>
n0 <span style="color: #666666">=</span> n_samples <span style="color: #666666">//</span> <span style="color: #666666">2</span>
n1 <span style="color: #666666">=</span> n_samples <span style="color: #666666">-</span> n0
<span style="color: #408080; font-style: italic"># Class 0 around mean -2, class 1 around +2</span>
mean0 <span style="color: #666666">=</span> <span style="color: #666666">-2</span> <span style="color: #666666">*</span> np<span style="color: #666666">.</span>ones(n_features)
mean1 <span style="color: #666666">=</span> <span style="color: #666666">2</span> <span style="color: #666666">*</span> np<span style="color: #666666">.</span>ones(n_features)
X0 <span style="color: #666666">=</span> rng<span style="color: #666666">.</span>randn(n0, n_features) <span style="color: #666666">+</span> mean0
X1 <span style="color: #666666">=</span> rng<span style="color: #666666">.</span>randn(n1, n_features) <span style="color: #666666">+</span> mean1
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>vstack((X0, X1))
y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array([<span style="color: #666666">0</span>]<span style="color: #666666">*</span>n0 <span style="color: #666666">+</span> [<span style="color: #666666">1</span>]<span style="color: #666666">*</span>n1)
<span style="color: #008000; font-weight: bold">return</span> X, y
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">generate_multiclass_data</span>(n_samples<span style="color: #666666">=150</span>, n_features<span style="color: #666666">=2</span>, n_classes<span style="color: #666666">=3</span>, random_state<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">None</span>):
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic"> Generate synthetic multiclass data with n_classes Gaussian clusters.</span>
<span style="color: #BA2121; font-style: italic"> &quot;&quot;&quot;</span>
rng <span style="color: #666666">=</span> np<span style="color: #666666">.</span>random<span style="color: #666666">.</span>RandomState(random_state)
X <span style="color: #666666">=</span> []
y <span style="color: #666666">=</span> []
samples_per_class <span style="color: #666666">=</span> n_samples <span style="color: #666666">//</span> n_classes
<span style="color: #008000; font-weight: bold">for</span> <span style="color: #008000">cls</span> <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(n_classes):
<span style="color: #408080; font-style: italic"># Random cluster center for each class</span>
center <span style="color: #666666">=</span> rng<span style="color: #666666">.</span>uniform(<span style="color: #666666">-5</span>, <span style="color: #666666">5</span>, size<span style="color: #666666">=</span>n_features)
Xi <span style="color: #666666">=</span> rng<span style="color: #666666">.</span>randn(samples_per_class, n_features) <span style="color: #666666">+</span> center
yi <span style="color: #666666">=</span> [<span style="color: #008000">cls</span>] <span style="color: #666666">*</span> samples_per_class
X<span style="color: #666666">.</span>append(Xi)
y<span style="color: #666666">.</span>extend(yi)
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>vstack(X)
y <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array(y)
<span style="color: #008000; font-weight: bold">return</span> X, y
<span style="color: #408080; font-style: italic"># Generate and test on binary data</span>
X_bin, y_bin <span style="color: #666666">=</span> generate_binary_data(n_samples<span style="color: #666666">=200</span>, n_features<span style="color: #666666">=2</span>, random_state<span style="color: #666666">=42</span>)
model_bin <span style="color: #666666">=</span> LogisticRegression(lr<span style="color: #666666">=0.1</span>, epochs<span style="color: #666666">=1000</span>)
model_bin<span style="color: #666666">.</span>fit(X_bin, y_bin)
y_prob_bin <span style="color: #666666">=</span> model_bin<span style="color: #666666">.</span>predict_prob(X_bin) <span style="color: #408080; font-style: italic"># probabilities for class 1</span>
y_pred_bin <span style="color: #666666">=</span> model_bin<span style="color: #666666">.</span>predict(X_bin) <span style="color: #408080; font-style: italic"># predicted classes 0 or 1</span>
acc_bin <span style="color: #666666">=</span> accuracy_score(y_bin, y_pred_bin)
loss_bin <span style="color: #666666">=</span> binary_cross_entropy(y_bin, y_prob_bin)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;Binary Classification - Accuracy: </span><span style="color: #BB6688; font-weight: bold">{</span>acc_bin<span style="color: #BB6688; font-weight: bold">:</span><span style="color: #BA2121">.2f</span><span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">, Cross-Entropy Loss: </span><span style="color: #BB6688; font-weight: bold">{</span>loss_bin<span style="color: #BB6688; font-weight: bold">:</span><span style="color: #BA2121">.2f</span><span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic">#For multiclass:</span>
<span style="color: #408080; font-style: italic"># Generate and test on multiclass data</span>
X_multi, y_multi <span style="color: #666666">=</span> generate_multiclass_data(n_samples<span style="color: #666666">=300</span>, n_features<span style="color: #666666">=2</span>, n_classes<span style="color: #666666">=3</span>, random_state<span style="color: #666666">=1</span>)
model_multi <span style="color: #666666">=</span> LogisticRegression(lr<span style="color: #666666">=0.1</span>, epochs<span style="color: #666666">=1000</span>)
model_multi<span style="color: #666666">.</span>fit(X_multi, y_multi)
y_prob_multi <span style="color: #666666">=</span> model_multi<span style="color: #666666">.</span>predict_prob(X_multi) <span style="color: #408080; font-style: italic"># (n_samples x 3) probabilities</span>
y_pred_multi <span style="color: #666666">=</span> model_multi<span style="color: #666666">.</span>predict(X_multi) <span style="color: #408080; font-style: italic"># predicted labels 0,1,2</span>
acc_multi <span style="color: #666666">=</span> accuracy_score(y_multi, y_pred_multi)
loss_multi <span style="color: #666666">=</span> categorical_cross_entropy(y_multi, y_prob_multi)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;Multiclass Classification - Accuracy: </span><span style="color: #BB6688; font-weight: bold">{</span>acc_multi<span style="color: #BB6688; font-weight: bold">:</span><span style="color: #BA2121">.2f</span><span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">, Cross-Entropy Loss: </span><span style="color: #BB6688; font-weight: bold">{</span>loss_multi<span style="color: #BB6688; font-weight: bold">:</span><span style="color: #BA2121">.2f</span><span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># CSV Export</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">csv</span>
<span style="color: #408080; font-style: italic"># Export binary results</span>
<span style="color: #008000; font-weight: bold">with</span> <span style="color: #008000">open</span>(<span style="color: #BA2121">&#39;binary_results.csv&#39;</span>, mode<span style="color: #666666">=</span><span style="color: #BA2121">&#39;w&#39;</span>, newline<span style="color: #666666">=</span><span style="color: #BA2121">&#39;&#39;</span>) <span style="color: #008000; font-weight: bold">as</span> f:
writer <span style="color: #666666">=</span> csv<span style="color: #666666">.</span>writer(f)
writer<span style="color: #666666">.</span>writerow([<span style="color: #BA2121">&quot;TrueLabel&quot;</span>, <span style="color: #BA2121">&quot;PredictedLabel&quot;</span>])
<span style="color: #008000; font-weight: bold">for</span> true, pred <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">zip</span>(y_bin, y_pred_bin):
writer<span style="color: #666666">.</span>writerow([true, pred])
<span style="color: #408080; font-style: italic"># Export multiclass results</span>
<span style="color: #008000; font-weight: bold">with</span> <span style="color: #008000">open</span>(<span style="color: #BA2121">&#39;multiclass_results.csv&#39;</span>, mode<span style="color: #666666">=</span><span style="color: #BA2121">&#39;w&#39;</span>, newline<span style="color: #666666">=</span><span style="color: #BA2121">&#39;&#39;</span>) <span style="color: #008000; font-weight: bold">as</span> f:
writer <span style="color: #666666">=</span> csv<span style="color: #666666">.</span>writer(f)
writer<span style="color: #666666">.</span>writerow([<span style="color: #BA2121">&quot;TrueLabel&quot;</span>, <span style="color: #BA2121">&quot;PredictedLabel&quot;</span>])
<span style="color: #008000; font-weight: bold">for</span> true, pred <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">zip</span>(y_multi, y_pred_multi):
writer<span style="color: #666666">.</span>writerow([true, pred])
</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-scikit-learn">Using <b>Scikit-learn</b> </h2>
<p>We show here how we can use a logistic regression case on a data set
included in _scikit_learn_, the so-called Wisconsin breast cancer data
using Logistic regression as our algorithm for classification. This is
a widely studied data set and can easily be included in demonstrations
of classification problems.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.model_selection</span> <span style="color: #008000; font-weight: bold">import</span> train_test_split
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> load_breast_cancer
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.linear_model</span> <span style="color: #008000; font-weight: bold">import</span> LogisticRegression
<span style="color: #408080; font-style: italic"># Load the data</span>
cancer <span style="color: #666666">=</span> load_breast_cancer()
X_train, X_test, y_train, y_test <span style="color: #666666">=</span> train_test_split(cancer<span style="color: #666666">.</span>data,cancer<span style="color: #666666">.</span>target,random_state<span style="color: #666666">=0</span>)
<span style="color: #008000">print</span>(X_train<span style="color: #666666">.</span>shape)
<span style="color: #008000">print</span>(X_test<span style="color: #666666">.</span>shape)
<span style="color: #408080; font-style: italic"># Logistic Regression</span>
logreg <span style="color: #666666">=</span> LogisticRegression(solver<span style="color: #666666">=</span><span style="color: #BA2121">&#39;lbfgs&#39;</span>)
logreg<span style="color: #666666">.</span>fit(X_train, y_train)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Test set accuracy with Logistic Regression: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X_test,y_test)))
</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-the-correlation-matrix">Using the correlation matrix </h2>
<p>In addition to the above scores, we could also study the covariance (and the correlation matrix).
We use <b>Pandas</b> to compute the correlation matrix.
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.model_selection</span> <span style="color: #008000; font-weight: bold">import</span> train_test_split
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> load_breast_cancer
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.linear_model</span> <span style="color: #008000; font-weight: bold">import</span> LogisticRegression
cancer <span style="color: #666666">=</span> load_breast_cancer()
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pandas</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">pd</span>
<span style="color: #408080; font-style: italic"># Making a data frame</span>
cancerpd <span style="color: #666666">=</span> pd<span style="color: #666666">.</span>DataFrame(cancer<span style="color: #666666">.</span>data, columns<span style="color: #666666">=</span>cancer<span style="color: #666666">.</span>feature_names)
fig, axes <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>subplots(<span style="color: #666666">15</span>,<span style="color: #666666">2</span>,figsize<span style="color: #666666">=</span>(<span style="color: #666666">10</span>,<span style="color: #666666">20</span>))
malignant <span style="color: #666666">=</span> cancer<span style="color: #666666">.</span>data[cancer<span style="color: #666666">.</span>target <span style="color: #666666">==</span> <span style="color: #666666">0</span>]
benign <span style="color: #666666">=</span> cancer<span style="color: #666666">.</span>data[cancer<span style="color: #666666">.</span>target <span style="color: #666666">==</span> <span style="color: #666666">1</span>]
ax <span style="color: #666666">=</span> axes<span style="color: #666666">.</span>ravel()
<span style="color: #008000; font-weight: bold">for</span> i <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #008000">range</span>(<span style="color: #666666">30</span>):
_, bins <span style="color: #666666">=</span> np<span style="color: #666666">.</span>histogram(cancer<span style="color: #666666">.</span>data[:,i], bins <span style="color: #666666">=50</span>)
ax[i]<span style="color: #666666">.</span>hist(malignant[:,i], bins <span style="color: #666666">=</span> bins, alpha <span style="color: #666666">=</span> <span style="color: #666666">0.5</span>)
ax[i]<span style="color: #666666">.</span>hist(benign[:,i], bins <span style="color: #666666">=</span> bins, alpha <span style="color: #666666">=</span> <span style="color: #666666">0.5</span>)
ax[i]<span style="color: #666666">.</span>set_title(cancer<span style="color: #666666">.</span>feature_names[i])
ax[i]<span style="color: #666666">.</span>set_yticks(())
ax[<span style="color: #666666">0</span>]<span style="color: #666666">.</span>set_xlabel(<span style="color: #BA2121">&quot;Feature magnitude&quot;</span>)
ax[<span style="color: #666666">0</span>]<span style="color: #666666">.</span>set_ylabel(<span style="color: #BA2121">&quot;Frequency&quot;</span>)
ax[<span style="color: #666666">0</span>]<span style="color: #666666">.</span>legend([<span style="color: #BA2121">&quot;Malignant&quot;</span>, <span style="color: #BA2121">&quot;Benign&quot;</span>], loc <span style="color: #666666">=</span><span style="color: #BA2121">&quot;best&quot;</span>)
fig<span style="color: #666666">.</span>tight_layout()
plt<span style="color: #666666">.</span>show()
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">seaborn</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">sns</span>
correlation_matrix <span style="color: #666666">=</span> cancerpd<span style="color: #666666">.</span>corr()<span style="color: #666666">.</span>round(<span style="color: #666666">1</span>)
<span style="color: #408080; font-style: italic"># use the heatmap function from seaborn to plot the correlation matrix</span>
<span style="color: #408080; font-style: italic"># annot = True to print the values inside the square</span>
plt<span style="color: #666666">.</span>figure(figsize<span style="color: #666666">=</span>(<span style="color: #666666">15</span>,<span style="color: #666666">8</span>))
sns<span style="color: #666666">.</span>heatmap(data<span style="color: #666666">=</span>correlation_matrix, annot<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>)
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="discussing-the-correlation-data">Discussing the correlation data </h2>
<p>In the above example we note two things. In the first plot we display
the overlap of benign and malignant tumors as functions of the various
features in the Wisconsin data set. We see that for
some of the features we can distinguish clearly the benign and
malignant cases while for other features we cannot. This can point to
us which features may be of greater interest when we wish to classify
a benign or not benign tumour.
</p>
<p>In the second figure we have computed the so-called correlation
matrix, which in our case with thirty features becomes a \( 30\times 30 \)
matrix.
</p>
<p>We constructed this matrix using <b>pandas</b> via the statements</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">cancerpd <span style="color: #666666">=</span> pd<span style="color: #666666">.</span>DataFrame(cancer<span style="color: #666666">.</span>data, columns<span style="color: #666666">=</span>cancer<span style="color: #666666">.</span>feature_names)
</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>and then</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;">correlation_matrix <span style="color: #666666">=</span> cancerpd<span style="color: #666666">.</span>corr()<span style="color: #666666">.</span>round(<span style="color: #666666">1</span>)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<p>Diagonalizing this matrix we can in turn say something about which
features are of relevance and which are not. This leads us to
the classical Principal Component Analysis (PCA) theorem with
applications. This will be discussed later this semester.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="other-measures-in-classification-studies">Other measures in classification studies </h2>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.model_selection</span> <span style="color: #008000; font-weight: bold">import</span> train_test_split
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> load_breast_cancer
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.linear_model</span> <span style="color: #008000; font-weight: bold">import</span> LogisticRegression
<span style="color: #408080; font-style: italic"># Load the data</span>
cancer <span style="color: #666666">=</span> load_breast_cancer()
X_train, X_test, y_train, y_test <span style="color: #666666">=</span> train_test_split(cancer<span style="color: #666666">.</span>data,cancer<span style="color: #666666">.</span>target,random_state<span style="color: #666666">=0</span>)
<span style="color: #008000">print</span>(X_train<span style="color: #666666">.</span>shape)
<span style="color: #008000">print</span>(X_test<span style="color: #666666">.</span>shape)
<span style="color: #408080; font-style: italic"># Logistic Regression</span>
logreg <span style="color: #666666">=</span> LogisticRegression(solver<span style="color: #666666">=</span><span style="color: #BA2121">&#39;lbfgs&#39;</span>)
logreg<span style="color: #666666">.</span>fit(X_train, y_train)
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.preprocessing</span> <span style="color: #008000; font-weight: bold">import</span> LabelEncoder
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.model_selection</span> <span style="color: #008000; font-weight: bold">import</span> cross_validate
<span style="color: #408080; font-style: italic">#Cross validation</span>
accuracy <span style="color: #666666">=</span> cross_validate(logreg,X_test,y_test,cv<span style="color: #666666">=10</span>)[<span style="color: #BA2121">&#39;test_score&#39;</span>]
<span style="color: #008000">print</span>(accuracy)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Test set accuracy with Logistic Regression: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X_test,y_test)))
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">scikitplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">skplt</span>
y_pred <span style="color: #666666">=</span> logreg<span style="color: #666666">.</span>predict(X_test)
skplt<span style="color: #666666">.</span>metrics<span style="color: #666666">.</span>plot_confusion_matrix(y_test, y_pred, normalize<span style="color: #666666">=</span><span style="color: #008000; font-weight: bold">True</span>)
plt<span style="color: #666666">.</span>show()
y_probas <span style="color: #666666">=</span> logreg<span style="color: #666666">.</span>predict_proba(X_test)
skplt<span style="color: #666666">.</span>metrics<span style="color: #666666">.</span>plot_roc(y_test, y_probas)
plt<span style="color: #666666">.</span>show()
skplt<span style="color: #666666">.</span>metrics<span style="color: #666666">.</span>plot_cumulative_gain(y_test, y_probas)
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="introduction-to-neural-networks">Introduction to Neural networks </h2>
<p>Artificial neural networks are computational systems that can learn to
perform tasks by considering examples, generally without being
programmed with any task-specific rules. It is supposed to mimic a
biological system, wherein neurons interact by sending signals in the
form of mathematical functions between layers. All layers can contain
an arbitrary number of neurons, and each connection is represented by
a weight variable.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="artificial-neurons">Artificial neurons </h2>
<p>The field of artificial neural networks has a long history of
development, and is closely connected with the advancement of computer
science and computers in general. A model of artificial neurons was
first developed by McCulloch and Pitts in 1943 to study signal
processing in the brain and has later been refined by others. The
general idea is to mimic neural networks in the human brain, which is
composed of billions of neurons that communicate with each other by
sending electrical signals. Each neuron accumulates its incoming
signals, which must exceed an activation threshold to yield an
output. If the threshold is not overcome, the neuron remains inactive,
i.e. has zero output.
</p>
<p>This behaviour has inspired a simple mathematical model for an artificial neuron.</p>
$$
\begin{equation}
y = f\left(\sum_{i=1}^n w_ix_i\right) = f(u)
\label{artificialNeuron}
\end{equation}
$$
<p>Here, the output \( y \) of the neuron is the value of its activation function, which have as input
a weighted sum of signals \( x_i, \dots ,x_n \) received by \( n \) other neurons.
</p>
<p>Conceptually, it is helpful to divide neural networks into four
categories:
</p>
<ol>
<li> general purpose neural networks for supervised learning,</li>
<li> neural networks designed specifically for image processing, the most prominent example of this class being Convolutional Neural Networks (CNNs),</li>
<li> neural networks for sequential data such as Recurrent Neural Networks (RNNs), and</li>
<li> neural networks for unsupervised learning such as Deep Boltzmann Machines.</li>
</ol>
<p>In natural science, DNNs and CNNs have already found numerous
applications. In statistical physics, they have been applied to detect
phase transitions in 2D Ising and Potts models, lattice gauge
theories, and different phases of polymers, or solving the
Navier-Stokes equation in weather forecasting. Deep learning has also
found interesting applications in quantum physics. Various quantum
phase transitions can be detected and studied using DNNs and CNNs,
topological phases, and even non-equilibrium many-body
localization. Representing quantum states as DNNs quantum state
tomography are among some of the impressive achievements to reveal the
potential of DNNs to facilitate the study of quantum systems.
</p>
<p>In quantum information theory, it has been shown that one can perform
gate decompositions with the help of neural.
</p>
<p>The applications are not limited to the natural sciences. There is a
plethora of applications in essentially all disciplines, from the
humanities to life science and medicine.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="neural-network-types">Neural network types </h2>
<p>An artificial neural network (ANN), is a computational model that
consists of layers of connected neurons, or nodes or units. We will
refer to these interchangeably as units or nodes, and sometimes as
neurons.
</p>
<p>It is supposed to mimic a biological nervous system by letting each
neuron interact with other neurons by sending signals in the form of
mathematical functions between layers. A wide variety of different
ANNs have been developed, but most of them consist of an input layer,
an output layer and eventual layers in-between, called <em>hidden
layers</em>. All layers can contain an arbitrary number of nodes, and each
connection between two nodes is associated with a weight variable.
</p>
<p>Neural networks (also called neural nets) are neural-inspired
nonlinear models for supervised learning. As we will see, neural nets
can be viewed as natural, more powerful extensions of supervised
learning methods such as linear and logistic regression and soft-max
methods we discussed earlier.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="feed-forward-neural-networks">Feed-forward neural networks </h2>
<p>The feed-forward neural network (FFNN) was the first and simplest type
of ANNs that were devised. In this network, the information moves in
only one direction: forward through the layers.
</p>
<p>Nodes are represented by circles, while the arrows display the
connections between the nodes, including the direction of information
flow. Additionally, each arrow corresponds to a weight variable
(figure to come). We observe that each node in a layer is connected
to <em>all</em> nodes in the subsequent layer, making this a so-called
<em>fully-connected</em> FFNN.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="convolutional-neural-network">Convolutional Neural Network </h2>
<p>A different variant of FFNNs are <em>convolutional neural networks</em>
(CNNs), which have a connectivity pattern inspired by the animal
visual cortex. Individual neurons in the visual cortex only respond to
stimuli from small sub-regions of the visual field, called a receptive
field. This makes the neurons well-suited to exploit the strong
spatially local correlation present in natural images. The response of
each neuron can be approximated mathematically as a convolution
operation. (figure to come)
</p>
<p>Convolutional neural networks emulate the behaviour of neurons in the
visual cortex by enforcing a <em>local</em> connectivity pattern between
nodes of adjacent layers: Each node in a convolutional layer is
connected only to a subset of the nodes in the previous layer, in
contrast to the fully-connected FFNN. Often, CNNs consist of several
convolutional layers that learn local features of the input, with a
fully-connected layer at the end, which gathers all the local data and
produces the outputs. They have wide applications in image and video
recognition.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="recurrent-neural-networks">Recurrent neural networks </h2>
<p>So far we have only mentioned ANNs where information flows in one
direction: forward. <em>Recurrent neural networks</em> on the other hand,
have connections between nodes that form directed <em>cycles</em>. This
creates a form of internal memory which are able to capture
information on what has been calculated before; the output is
dependent on the previous computations. Recurrent NNs make use of
sequential information by performing the same task for every element
in a sequence, where each element depends on previous elements. An
example of such information is sentences, making recurrent NNs
especially well-suited for handwriting and speech recognition.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="other-types-of-networks">Other types of networks </h2>
<p>There are many other kinds of ANNs that have been developed. One type
that is specifically designed for interpolation in multidimensional
space is the radial basis function (RBF) network. RBFs are typically
made up of three layers: an input layer, a hidden layer with
non-linear radial symmetric activation functions and a linear output
layer (''linear'' here means that each node in the output layer has a
linear activation function). The layers are normally fully-connected
and there are no cycles, thus RBFs can be viewed as a type of
fully-connected FFNN. They are however usually treated as a separate
type of NN due the unusual activation functions.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="multilayer-perceptrons">Multilayer perceptrons </h2>
<p>One uses often so-called fully-connected feed-forward neural networks
with three or more layers (an input layer, one or more hidden layers
and an output layer) consisting of neurons that have non-linear
activation functions.
</p>
<p>Such networks are often called <em>multilayer perceptrons</em> (MLPs).</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="why-multilayer-perceptrons">Why multilayer perceptrons? </h2>
<p>According to the <em>Universal approximation theorem</em>, a feed-forward
neural network with just a single hidden layer containing a finite
number of neurons can approximate a continuous multidimensional
function to arbitrary accuracy, assuming the activation function for
the hidden layer is a <b>non-constant, bounded and
monotonically-increasing continuous function</b>.
</p>
<p>Note that the requirements on the activation function only applies to
the hidden layer, the output nodes are always assumed to be linear, so
as to not restrict the range of output values.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="illustration-of-a-single-perceptron-model-and-a-multi-perceptron-model">Illustration of a single perceptron model and a multi-perceptron model </h2>
<center> <!-- FIGURE -->
<hr class="figure">
<center>
<p class="caption">Figure 1: In a) we show a single perceptron model while in b) we dispay a network with two hidden layers, an input layer and an output layer. </p>
</center>
<p><img src="figures/nns.png" width="600" align="bottom"></p>
</center>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="examples-of-xor-or-and-and-gates">Examples of XOR, OR and AND gates </h2>
<p>Let us first try to fit various gates using standard linear
regression. The gates we are thinking of are the classical XOR, OR and
AND gates, well-known elements in computer science. The tables here
show how we can set up the inputs \( x_1 \) and \( x_2 \) in order to yield a
specific target \( y_i \).
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic">Simple code that tests XOR, OR and AND gates with linear regression</span>
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #408080; font-style: italic"># Design matrix</span>
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array([ [<span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>], [<span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>], [<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>],[<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>]],dtype<span style="color: #666666">=</span>np<span style="color: #666666">.</span>float64)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The X.TX matrix:</span><span style="color: #BB6688; font-weight: bold">{</span>X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> X<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
Xinv <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linalg<span style="color: #666666">.</span>pinv(X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> X)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The invers of X.TX matrix:</span><span style="color: #BB6688; font-weight: bold">{</span>Xinv<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># The XOR gate </span>
yXOR <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array( [ <span style="color: #666666">0</span>, <span style="color: #666666">1</span> ,<span style="color: #666666">1</span>, <span style="color: #666666">0</span>])
ThetaXOR <span style="color: #666666">=</span> Xinv <span style="color: #666666">@</span> X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> yXOR
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The values of theta for the XOR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>ThetaXOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The linear regression prediction for the XOR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>X <span style="color: #666666">@</span> ThetaXOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># The OR gate </span>
yOR <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array( [ <span style="color: #666666">0</span>, <span style="color: #666666">1</span> ,<span style="color: #666666">1</span>, <span style="color: #666666">1</span>])
ThetaOR <span style="color: #666666">=</span> Xinv <span style="color: #666666">@</span> X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> yOR
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The values of theta for the OR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>ThetaOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The linear regression prediction for the OR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>X <span style="color: #666666">@</span> ThetaOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># The OR gate </span>
yAND <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array( [ <span style="color: #666666">0</span>, <span style="color: #666666">0</span> ,<span style="color: #666666">0</span>, <span style="color: #666666">1</span>])
ThetaAND <span style="color: #666666">=</span> Xinv <span style="color: #666666">@</span> X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> yAND
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The values of theta for the AND gate:</span><span style="color: #BB6688; font-weight: bold">{</span>ThetaAND<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The linear regression prediction for the AND gate:</span><span style="color: #BB6688; font-weight: bold">{</span>X <span style="color: #666666">@</span> ThetaAND<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</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>What is happening here?</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="does-logistic-regression-do-a-better-job">Does Logistic Regression do a better Job? </h2>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #BA2121; font-style: italic">Simple code that tests XOR and OR gates with linear regression</span>
<span style="color: #BA2121; font-style: italic">and logistic regression</span>
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.linear_model</span> <span style="color: #008000; font-weight: bold">import</span> LogisticRegression
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">np</span>
<span style="color: #408080; font-style: italic"># Design matrix</span>
X <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array([ [<span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>], [<span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>], [<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>],[<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>]],dtype<span style="color: #666666">=</span>np<span style="color: #666666">.</span>float64)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The X.TX matrix:</span><span style="color: #BB6688; font-weight: bold">{</span>X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> X<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
Xinv <span style="color: #666666">=</span> np<span style="color: #666666">.</span>linalg<span style="color: #666666">.</span>pinv(X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> X)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The invers of X.TX matrix:</span><span style="color: #BB6688; font-weight: bold">{</span>Xinv<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># The XOR gate </span>
yXOR <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array( [ <span style="color: #666666">0</span>, <span style="color: #666666">1</span> ,<span style="color: #666666">1</span>, <span style="color: #666666">0</span>])
ThetaXOR <span style="color: #666666">=</span> Xinv <span style="color: #666666">@</span> X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> yXOR
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The values of theta for the XOR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>ThetaXOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The linear regression prediction for the XOR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>X <span style="color: #666666">@</span> ThetaXOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># The OR gate </span>
yOR <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array( [ <span style="color: #666666">0</span>, <span style="color: #666666">1</span> ,<span style="color: #666666">1</span>, <span style="color: #666666">1</span>])
ThetaOR <span style="color: #666666">=</span> Xinv <span style="color: #666666">@</span> X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> yOR
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The values of theta for the OR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>ThetaOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The linear regression prediction for the OR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>X <span style="color: #666666">@</span> ThetaOR<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># The OR gate </span>
yAND <span style="color: #666666">=</span> np<span style="color: #666666">.</span>array( [ <span style="color: #666666">0</span>, <span style="color: #666666">0</span> ,<span style="color: #666666">0</span>, <span style="color: #666666">1</span>])
ThetaAND <span style="color: #666666">=</span> Xinv <span style="color: #666666">@</span> X<span style="color: #666666">.</span>T <span style="color: #666666">@</span> yAND
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The values of theta for the AND gate:</span><span style="color: #BB6688; font-weight: bold">{</span>ThetaAND<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;The linear regression prediction for the AND gate:</span><span style="color: #BB6688; font-weight: bold">{</span>X <span style="color: #666666">@</span> ThetaAND<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
<span style="color: #408080; font-style: italic"># Now we change to logistic regression</span>
<span style="color: #408080; font-style: italic"># Logistic Regression</span>
logreg <span style="color: #666666">=</span> LogisticRegression()
logreg<span style="color: #666666">.</span>fit(X, yOR)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Test set accuracy with Logistic Regression for OR gate: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X,yOR)))
logreg<span style="color: #666666">.</span>fit(X, yXOR)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Test set accuracy with Logistic Regression for XOR gate: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X,yXOR)))
logreg<span style="color: #666666">.</span>fit(X, yAND)
<span style="color: #008000">print</span>(<span style="color: #BA2121">&quot;Test set accuracy with Logistic Regression for AND gate: </span><span style="color: #BB6688; font-weight: bold">{:.2f}</span><span style="color: #BA2121">&quot;</span><span style="color: #666666">.</span>format(logreg<span style="color: #666666">.</span>score(X,yAND)))
</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>Not exactly impressive, but somewhat better.</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="adding-neural-networks">Adding Neural Networks </h2>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #408080; font-style: italic"># and now neural networks with Scikit-Learn and the XOR</span>
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.neural_network</span> <span style="color: #008000; font-weight: bold">import</span> MLPClassifier
<span style="color: #008000; font-weight: bold">from</span> <span style="color: #0000FF; font-weight: bold">sklearn.datasets</span> <span style="color: #008000; font-weight: bold">import</span> make_classification
X, yXOR <span style="color: #666666">=</span> make_classification(n_samples<span style="color: #666666">=100</span>, random_state<span style="color: #666666">=1</span>)
FFNN <span style="color: #666666">=</span> MLPClassifier(random_state<span style="color: #666666">=1</span>, max_iter<span style="color: #666666">=300</span>)<span style="color: #666666">.</span>fit(X, yXOR)
FFNN<span style="color: #666666">.</span>predict_proba(X)
<span style="color: #008000">print</span>(<span style="color: #BA2121">f&quot;Test set accuracy with Feed Forward Neural Network for XOR gate:</span><span style="color: #BB6688; font-weight: bold">{</span>FFNN<span style="color: #666666">.</span>score(X, yXOR)<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">&quot;</span>)
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-model">Mathematical model </h2>
<p>The output \( y \) is produced via the activation function \( f \)</p>
$$
y = f\left(\sum_{i=1}^n w_ix_i + b_i\right) = f(z),
$$
<p>This function receives \( x_i \) as inputs.
Here the activation \( z=(\sum_{i=1}^n w_ix_i+b_i) \).
In an FFNN of such neurons, the <em>inputs</em> \( x_i \) are the <em>outputs</em> of
the neurons in the preceding layer. Furthermore, an MLP is
fully-connected, which means that each neuron receives a weighted sum
of the outputs of <em>all</em> neurons in the previous layer.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-model">Mathematical model </h2>
<p>First, for each node \( i \) in the first hidden layer, we calculate a weighted sum \( z_i^1 \) of the input coordinates \( x_j \),</p>
$$
\begin{equation} z_i^1 = \sum_{j=1}^{M} w_{ij}^1 x_j + b_i^1
\label{_auto1}
\end{equation}
$$
<p>Here \( b_i \) is the so-called bias which is normally needed in
case of zero activation weights or inputs. How to fix the biases and
the weights will be discussed below. The value of \( z_i^1 \) is the
argument to the activation function \( f_i \) of each node \( i \), The
variable \( M \) stands for all possible inputs to a given node \( i \) in the
first layer. We define the output \( y_i^1 \) of all neurons in layer 1 as
</p>
$$
\begin{equation}
y_i^1 = f(z_i^1) = f\left(\sum_{j=1}^M w_{ij}^1 x_j + b_i^1\right)
\label{outputLayer1}
\end{equation}
$$
<p>where we assume that all nodes in the same layer have identical
activation functions, hence the notation \( f \). In general, we could assume in the more general case that different layers have different activation functions.
In this case we would identify these functions with a superscript \( l \) for the \( l \)-th layer,
</p>
$$
\begin{equation}
y_i^l = f^l(u_i^l) = f^l\left(\sum_{j=1}^{N_{l-1}} w_{ij}^l y_j^{l-1} + b_i^l\right)
\label{generalLayer}
\end{equation}
$$
<p>where \( N_l \) is the number of nodes in layer \( l \). When the output of
all the nodes in the first hidden layer are computed, the values of
the subsequent layer can be calculated and so forth until the output
is obtained.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-model">Mathematical model </h2>
<p>The output of neuron \( i \) in layer 2 is thus,</p>
$$
\begin{align}
y_i^2 &= f^2\left(\sum_{j=1}^N w_{ij}^2 y_j^1 + b_i^2\right)
\label{_auto2}\\
&= f^2\left[\sum_{j=1}^N w_{ij}^2f^1\left(\sum_{k=1}^M w_{jk}^1 x_k + b_j^1\right) + b_i^2\right]
\label{outputLayer2}
\end{align}
$$
<p>where we have substituted \( y_k^1 \) with the inputs \( x_k \). Finally, the ANN output reads</p>
$$
\begin{align}
y_i^3 &= f^3\left(\sum_{j=1}^N w_{ij}^3 y_j^2 + b_i^3\right)
\label{_auto3}\\
&= f_3\left[\sum_{j} w_{ij}^3 f^2\left(\sum_{k} w_{jk}^2 f^1\left(\sum_{m} w_{km}^1 x_m + b_k^1\right) + b_j^2\right)
+ b_1^3\right]
\label{_auto4}
\end{align}
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-model">Mathematical model </h2>
<p>We can generalize this expression to an MLP with \( l \) hidden
layers. The complete functional form is,
</p>
$$
\begin{align}
&y^{l+1}_i = f^{l+1}\left[\!\sum_{j=1}^{N_l} w_{ij}^3 f^l\left(\sum_{k=1}^{N_{l-1}}w_{jk}^{l-1}\left(\dots f^1\left(\sum_{n=1}^{N_0} w_{mn}^1 x_n+ b_m^1\right)\dots\right)+b_k^2\right)+b_1^3\right] &&
\label{completeNN}
\end{align}
$$
<p>which illustrates a basic property of MLPs: The only independent
variables are the input values \( x_n \).
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h2 id="mathematical-model">Mathematical model </h2>
<p>This confirms that an MLP, despite its quite convoluted mathematical
form, is nothing more than an analytic function, specifically a
mapping of real-valued vectors \( \hat{x} \in \mathbb{R}^n \rightarrow
\hat{y} \in \mathbb{R}^m \).
</p>
<p>Furthermore, the flexibility and universality of an MLP can be
illustrated by realizing that the expression is essentially a nested
sum of scaled activation functions of the form
</p>
$$
\begin{equation}
f(x) = c_1 f(c_2 x + c_3) + c_4
\label{_auto5}
\end{equation}
$$
<p>where the parameters \( c_i \) are weights and biases. By adjusting these
parameters, the activation functions can be shifted up and down or
left and right, change slope or be rescaled which is the key to the
flexibility of a neural network.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h3 id="matrix-vector-notation">Matrix-vector notation </h3>
<p>We can introduce a more convenient notation for the activations in an A NN. </p>
<p>Additionally, we can represent the biases and activations
as layer-wise column vectors \( \hat{b}_l \) and \( \hat{y}_l \), so that the \( i \)-th element of each vector
is the bias \( b_i^l \) and activation \( y_i^l \) of node \( i \) in layer \( l \) respectively.
</p>
<p>We have that \( \mathrm{W}_l \) is an \( N_{l-1} \times N_l \) matrix, while \( \hat{b}_l \) and \( \hat{y}_l \) are \( N_l \times 1 \) column vectors.
With this notation, the sum becomes a matrix-vector multiplication, and we can write
the equation for the activations of hidden layer 2 (assuming three nodes for simplicity) as
</p>
$$
\begin{equation}
\hat{y}_2 = f_2(\mathrm{W}_2 \hat{y}_{1} + \hat{b}_{2}) =
f_2\left(\left[\begin{array}{ccc}
w^2_{11} &w^2_{12} &w^2_{13} \\
w^2_{21} &w^2_{22} &w^2_{23} \\
w^2_{31} &w^2_{32} &w^2_{33} \\
\end{array} \right] \cdot
\left[\begin{array}{c}
y^1_1 \\
y^1_2 \\
y^1_3 \\
\end{array}\right] +
\left[\begin{array}{c}
b^2_1 \\
b^2_2 \\
b^2_3 \\
\end{array}\right]\right).
\label{_auto6}
\end{equation}
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h3 id="matrix-vector-notation-and-activation">Matrix-vector notation and activation </h3>
<p>The activation of node \( i \) in layer 2 is</p>
$$
\begin{equation}
y^2_i = f_2\Bigr(w^2_{i1}y^1_1 + w^2_{i2}y^1_2 + w^2_{i3}y^1_3 + b^2_i\Bigr) =
f_2\left(\sum_{j=1}^3 w^2_{ij} y_j^1 + b^2_i\right).
\label{_auto7}
\end{equation}
$$
<p>This is not just a convenient and compact notation, but also a useful
and intuitive way to think about MLPs: The output is calculated by a
series of matrix-vector multiplications and vector additions that are
used as input to the activation functions. For each operation
\( \mathrm{W}_l \hat{y}_{l-1} \) we move forward one layer.
</p>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h3 id="activation-functions">Activation functions </h3>
<p>A property that characterizes a neural network, other than its
connectivity, is the choice of activation function(s). As described
in, the following restrictions are imposed on an activation function
for a FFNN to fulfill the universal approximation theorem
</p>
<ul>
<li> Non-constant</li>
<li> Bounded</li>
<li> Monotonically-increasing</li>
<li> Continuous</li>
</ul>
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h3 id="activation-functions-logistic-and-hyperbolic-ones">Activation functions, Logistic and Hyperbolic ones </h3>
<p>The second requirement excludes all linear functions. Furthermore, in
a MLP with only linear activation functions, each layer simply
performs a linear transformation of its inputs.
</p>
<p>Regardless of the number of layers, the output of the NN will be
nothing but a linear function of the inputs. Thus we need to introduce
some kind of non-linearity to the NN to be able to fit non-linear
functions Typical examples are the logistic <em>Sigmoid</em>
</p>
$$
f(x) = \frac{1}{1 + e^{-x}},
$$
<p>and the <em>hyperbolic tangent</em> function</p>
$$
f(x) = \tanh(x)
$$
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
<h3 id="relevance">Relevance </h3>
<p>The <em>sigmoid</em> function are more biologically plausible because the
output of inactive neurons are zero. Such activation function are
called <em>one-sided</em>. However, it has been shown that the hyperbolic
tangent performs better than the sigmoid for training MLPs. has
become the most popular for <em>deep neural networks</em>
</p>
<!-- code=python (!bc pycod) typeset with pygments style "default" -->
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="inner_cell">
<div class="input_area">
<div class="highlight" style="background: #f8f8f8">
<pre style="line-height: 125%;"><span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;The sigmoid function (or the logistic curve) is a </span>
<span style="color: #BA2121; font-style: italic">function that takes any real number, z, and outputs a number (0,1).</span>
<span style="color: #BA2121; font-style: italic">It is useful in neural networks for assigning weights on a relative scale.</span>
<span style="color: #BA2121; font-style: italic">The value z is the weighted sum of parameters involved in the learning algorithm.&quot;&quot;&quot;</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">numpy</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">matplotlib.pyplot</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">plt</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">math</span> <span style="color: #008000; font-weight: bold">as</span> <span style="color: #0000FF; font-weight: bold">mt</span>
z <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>arange(<span style="color: #666666">-5</span>, <span style="color: #666666">5</span>, <span style="color: #666666">.1</span>)
sigma_fn <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>vectorize(<span style="color: #008000; font-weight: bold">lambda</span> z: <span style="color: #666666">1/</span>(<span style="color: #666666">1+</span>numpy<span style="color: #666666">.</span>exp(<span style="color: #666666">-</span>z)))
sigma <span style="color: #666666">=</span> sigma_fn(z)
fig <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>figure()
ax <span style="color: #666666">=</span> fig<span style="color: #666666">.</span>add_subplot(<span style="color: #666666">111</span>)
ax<span style="color: #666666">.</span>plot(z, sigma)
ax<span style="color: #666666">.</span>set_ylim([<span style="color: #666666">-0.1</span>, <span style="color: #666666">1.1</span>])
ax<span style="color: #666666">.</span>set_xlim([<span style="color: #666666">-5</span>,<span style="color: #666666">5</span>])
ax<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>)
ax<span style="color: #666666">.</span>set_xlabel(<span style="color: #BA2121">&#39;z&#39;</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&#39;sigmoid function&#39;</span>)
plt<span style="color: #666666">.</span>show()
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Step Function&quot;&quot;&quot;</span>
z <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>arange(<span style="color: #666666">-5</span>, <span style="color: #666666">5</span>, <span style="color: #666666">.02</span>)
step_fn <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>vectorize(<span style="color: #008000; font-weight: bold">lambda</span> z: <span style="color: #666666">1.0</span> <span style="color: #008000; font-weight: bold">if</span> z <span style="color: #666666">&gt;=</span> <span style="color: #666666">0.0</span> <span style="color: #008000; font-weight: bold">else</span> <span style="color: #666666">0.0</span>)
step <span style="color: #666666">=</span> step_fn(z)
fig <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>figure()
ax <span style="color: #666666">=</span> fig<span style="color: #666666">.</span>add_subplot(<span style="color: #666666">111</span>)
ax<span style="color: #666666">.</span>plot(z, step)
ax<span style="color: #666666">.</span>set_ylim([<span style="color: #666666">-0.5</span>, <span style="color: #666666">1.5</span>])
ax<span style="color: #666666">.</span>set_xlim([<span style="color: #666666">-5</span>,<span style="color: #666666">5</span>])
ax<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>)
ax<span style="color: #666666">.</span>set_xlabel(<span style="color: #BA2121">&#39;z&#39;</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&#39;step function&#39;</span>)
plt<span style="color: #666666">.</span>show()
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Sine Function&quot;&quot;&quot;</span>
z <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>arange(<span style="color: #666666">-2*</span>mt<span style="color: #666666">.</span>pi, <span style="color: #666666">2*</span>mt<span style="color: #666666">.</span>pi, <span style="color: #666666">0.1</span>)
t <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>sin(z)
fig <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>figure()
ax <span style="color: #666666">=</span> fig<span style="color: #666666">.</span>add_subplot(<span style="color: #666666">111</span>)
ax<span style="color: #666666">.</span>plot(z, t)
ax<span style="color: #666666">.</span>set_ylim([<span style="color: #666666">-1.0</span>, <span style="color: #666666">1.0</span>])
ax<span style="color: #666666">.</span>set_xlim([<span style="color: #666666">-2*</span>mt<span style="color: #666666">.</span>pi,<span style="color: #666666">2*</span>mt<span style="color: #666666">.</span>pi])
ax<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>)
ax<span style="color: #666666">.</span>set_xlabel(<span style="color: #BA2121">&#39;z&#39;</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&#39;sine function&#39;</span>)
plt<span style="color: #666666">.</span>show()
<span style="color: #BA2121; font-style: italic">&quot;&quot;&quot;Plots a graph of the squashing function used by a rectified linear</span>
<span style="color: #BA2121; font-style: italic">unit&quot;&quot;&quot;</span>
z <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>arange(<span style="color: #666666">-2</span>, <span style="color: #666666">2</span>, <span style="color: #666666">.1</span>)
zero <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>zeros(<span style="color: #008000">len</span>(z))
y <span style="color: #666666">=</span> numpy<span style="color: #666666">.</span>max([zero, z], axis<span style="color: #666666">=0</span>)
fig <span style="color: #666666">=</span> plt<span style="color: #666666">.</span>figure()
ax <span style="color: #666666">=</span> fig<span style="color: #666666">.</span>add_subplot(<span style="color: #666666">111</span>)
ax<span style="color: #666666">.</span>plot(z, y)
ax<span style="color: #666666">.</span>set_ylim([<span style="color: #666666">-2.0</span>, <span style="color: #666666">2.0</span>])
ax<span style="color: #666666">.</span>set_xlim([<span style="color: #666666">-2.0</span>, <span style="color: #666666">2.0</span>])
ax<span style="color: #666666">.</span>grid(<span style="color: #008000; font-weight: bold">True</span>)
ax<span style="color: #666666">.</span>set_xlabel(<span style="color: #BA2121">&#39;z&#39;</span>)
ax<span style="color: #666666">.</span>set_title(<span style="color: #BA2121">&#39;Rectified linear unit&#39;</span>)
plt<span style="color: #666666">.</span>show()
</pre>
</div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area">
<div class="output_subarea output_stream output_stdout output_text">
</div>
</div>
</div>
</div>
</div>
<!-- ------------------- 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>