diff --git a/doc/LectureNotes/_build/.doctrees/environment.pickle b/doc/LectureNotes/_build/.doctrees/environment.pickle
index 7f75321f5..7b060ebdd 100644
Binary files a/doc/LectureNotes/_build/.doctrees/environment.pickle and b/doc/LectureNotes/_build/.doctrees/environment.pickle differ
diff --git a/doc/LectureNotes/_build/.doctrees/exercisesweek34.doctree b/doc/LectureNotes/_build/.doctrees/exercisesweek34.doctree
new file mode 100644
index 000000000..a652d192b
Binary files /dev/null and b/doc/LectureNotes/_build/.doctrees/exercisesweek34.doctree differ
diff --git a/doc/LectureNotes/_build/.doctrees/exercisesweek35.doctree b/doc/LectureNotes/_build/.doctrees/exercisesweek35.doctree
new file mode 100644
index 000000000..beac0e7da
Binary files /dev/null and b/doc/LectureNotes/_build/.doctrees/exercisesweek35.doctree differ
diff --git a/doc/LectureNotes/_build/.doctrees/exercisesweek36.doctree b/doc/LectureNotes/_build/.doctrees/exercisesweek36.doctree
new file mode 100644
index 000000000..4c09c2dc8
Binary files /dev/null and b/doc/LectureNotes/_build/.doctrees/exercisesweek36.doctree differ
diff --git a/doc/LectureNotes/_build/.doctrees/intro.doctree b/doc/LectureNotes/_build/.doctrees/intro.doctree
index 32f449485..0b4af0db7 100644
Binary files a/doc/LectureNotes/_build/.doctrees/intro.doctree and b/doc/LectureNotes/_build/.doctrees/intro.doctree differ
diff --git a/doc/LectureNotes/_build/html/_images/cb756715680fbe8cbf1d070371bf3950695ddf24b29ecb476c48fb9e559af08e.png b/doc/LectureNotes/_build/html/_images/cb756715680fbe8cbf1d070371bf3950695ddf24b29ecb476c48fb9e559af08e.png
new file mode 100644
index 000000000..a16a30cd2
Binary files /dev/null and b/doc/LectureNotes/_build/html/_images/cb756715680fbe8cbf1d070371bf3950695ddf24b29ecb476c48fb9e559af08e.png differ
diff --git a/doc/LectureNotes/_build/html/_sources/exercisesweek34.ipynb b/doc/LectureNotes/_build/html/_sources/exercisesweek34.ipynb
new file mode 100644
index 000000000..50e773ede
--- /dev/null
+++ b/doc/LectureNotes/_build/html/_sources/exercisesweek34.ipynb
@@ -0,0 +1,315 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "232d1306",
+ "metadata": {},
+ "source": [
+ "# Exercises week 34\n",
+ "\n",
+ "## Coding Setup and Linear Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9b66a351",
+ "metadata": {},
+ "source": [
+ "Welcome to FYS-STK3155/4155!\n",
+ "\n",
+ "In this first week will focus on getting you set up with the programs you are going to be using throughout this course. We expect that many of you will encounter some trouble with setting these programs up, as they can be extremely finnicky and prone to not working the same on all machines, so we strongly encourage you to not get discouraged, and to show up to the group-sessions where we can help you along. The group sessions are also the best place to find group partners for the projects and to be challenged on your understanding of the material, which are both essential to doing well in this course. We strongly encourage you to form groups of 2-3 participants. \n",
+ "\n",
+ "If you are unable to complete this week's exercises, don't worry, this will likely be the most frustrating week for many of you. You have time to get back on track next week, especially if you come to the group-sessions! Note also that this week's set of exercises does not count for the additional score. The deadline for the weekly exercises is set to Fridays, at midnight."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "36d8750b",
+ "metadata": {},
+ "source": [
+ "### Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "\n",
+ "- Create and use a Github repository\n",
+ "- Set up and use a virtual environment in Python\n",
+ "- Fit an OLS model to data using scikit-learn\n",
+ "- Fit a model on training data and evaluate it on test data\n",
+ "\n",
+ "### Deliverables\n",
+ "\n",
+ "Complete the following exercises while working in a jupyter notebook. Exercises 1,2 and 3 require no writing in the notebook. Then, in canvas, include\n",
+ "- The jupyter notebook with the exercises completed\n",
+ "- An exported PDF of the notebook (https://code.visualstudio.com/docs/datascience/jupyter-notebooks#_export-your-jupyter-notebook)\n",
+ "- Optional: A link to your github repository, which must be set to public, include the notebook file, a README file, requirements file and gitignore file.\n",
+ "\n",
+ "We require you to deliver a jupyter notebook so that we can evaluate the results of your code without needing to download and run the code of every student, as well as to teach you to use this useful tool."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a9c7ef8",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Github Setup\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1498aed1",
+ "metadata": {},
+ "source": [
+ "In this course, we require you to pay extra mind to the reproducibility of your results and the shareability of your code. The first step toward these goals is using a version control system like git and online repository like Github.\n",
+ "\n",
+ "**a)** Download git if you don't already have it on your machine, check with the terminal command ´git --version´ (https://git-scm.com/downloads).\n",
+ "\n",
+ "**b)** Create a Github account(https://github.com/), or log in to github with your UiO account (https://github.uio.no/login).\n",
+ "\n",
+ "**c)** Learn the basics of opening the terminal and navigating folders on your operating system. Things to learn: Opening a terminal, opening a terminal in a specific folder, listing the contents of the current folder, navigating into a folder, navigating out of a folder.\n",
+ "\n",
+ "**d)** Download the Github CLI tool and run ´gh auth login´ in your terminal to authenticate your local machine for some of the later steps. (https://github.com/cli/cli#installation). You might need to change file permissions to make it work, ask us or ChatGPT for help with these issues.\n",
+ "\n",
+ "**e)** As an alternative to the above terminal based instructions, you could install GitHub Desktop (see https://desktop.github.com/download/) or if you prefer GitLab, GitLab desktop (see https://about.gitlab.com/install/). This sets up all communications between your PC/Laptop and the repository. This allows you to combine exercises 1 and 2 in an easy way if you don't want to use terminarl. Keep in mind that these GUIs (graphical user interfaces) are not text editors."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c56fbefa",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Setting up a Github repository\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb9b8acd",
+ "metadata": {
+ "vscode": {
+ "languageId": "plaintext"
+ }
+ },
+ "source": [
+ "**a)** Create an empty repository for your coursework in this course in your browser at github.com (or uio github).\n",
+ "\n",
+ "**b)** Open a terminal in the location you want to create your local folder for this repository, like your desktop.\n",
+ "\n",
+ "**c)** Clone the repository to your laptop using the terminal command ´gh repo clone username/repository-name´. This creates a folder with the same name as the repository. Moving it or renaming it might require some extra steps.\n",
+ "\n",
+ "**d)** Download this jupyter notebook. Add the notebook to the local folder.\n",
+ "\n",
+ "**e)** Run the ´git add .´ command command in a terminal opened in the local folder to stage the current changes in the folder to be commited to the version control history. Run ´git status´ to see the staged files.\n",
+ "\n",
+ "**f)** Run the ´git commit -m \"Adding first weekly assignment file\"´ command to commit the staged changes to the version control history. Run ´git status´ to see that no files are staged.\n",
+ "\n",
+ "**g)** Run the ´git push\" command to upload the commited changes to the remote repository on Github.\n",
+ "\n",
+ "**h)** Add a file called README.txt to the repository at Github.com. Don't do this in your local folder. Add a suitable title for your repository and some inforomation to the file.\n",
+ "\n",
+ "**i)** Run the ´git fetch origin´ command to fetch the latest remote changes to your repository.\n",
+ "\n",
+ "**j)** Run the ´git pull´ command to download and update files to match the remote changes.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f84d0db6",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Setting up a Python virtual environment\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b5a4818a",
+ "metadata": {},
+ "source": [
+ "Following the themes from the previous exercises, another way of improving the reproducibility of your results and shareability of your code is having a good handle on which python packages you are using.\n",
+ "\n",
+ "There are many ways to manage your packages in Python, and you are free to use any approach you want, but in this course we encourage you to use something called a virtual environment. A virtual environemnt is a folder in your project which contains a Python runtime executable as well as all the packages you are using in the current project. In this way, each of your projects has its required set of packages installed in the same folder, so that if anything goes wrong while managing your packages it only affects the one project, and if multiple projects require different versions of the same package, you don't need to worry about messing up old projects. Also, it's easy to just delete the folder and start over if anything goes wrong.\n",
+ "\n",
+ "Virtual environments are typically created, activated, managed and updated using terminal commands, but for now we recommend that you let for example VS Code (a popular cross-paltform package) handle it for you to make the coding experience much easier. If you are familiar with another approach for virtual environments that works for you, feel free to keep doing it that way.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0f6de364",
+ "metadata": {},
+ "source": [
+ "**a)** Open this notebook in VS Code (https://code.visualstudio.com/Download). Download the Python and Jupyter extensions.\n",
+ "\n",
+ "**b)** Press ´Cmd + Shift + P´, then search and run ´Python: Create Environment...´\n",
+ "\n",
+ "**c)** Select ´Venv´\n",
+ "\n",
+ "**d)** Choose the most up-to-date version of Python your have installed.\n",
+ "\n",
+ "**e)** Press ´Cmd + Shift + P´, then search and run ´Python: Select Interpreter´\n",
+ "\n",
+ "**f)** Selevet the (.venv) option you just created.\n",
+ "\n",
+ "**g)** Open a terminal in VS Code, the venv name should be visible at the beginning of the line. Run `pip list` to see that there are no packages install in the environment.\n",
+ "\n",
+ "**h)** In this terminal, run `pip install matplotlib numpy scikit-learn`. This will install the listed packages.\n",
+ "\n",
+ "**i)** To make these installations reproducible, which is important for reproducing results and sharing your code, run ´pip freeze > requirements.txt´ to create the file requirements.txt with all your dependencies.\n",
+ "\n",
+ "Now, anyone who wants to recreate your package setup can download your requirements.txt file and run ´pip install -r requirements.txt´ to install the correct packages and versions. To keep the requirements.txt file up to date with your environment, you will need to re-run the freeze command whenever you install a new package.\n",
+ "\n",
+ "**j)** Create a .gitignore file at the root of your project folder, and add the line ´.venv´ to it. This way, you won't try to upload a copy of all your python packages when you regularly push your changes to Github. Ignored files should not show up when you run ´git status´, and are not staged when running ´git add .´, try it!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d184ab1",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Fitting an OLS model to data\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d19ebd67",
+ "metadata": {},
+ "source": [
+ "Great job on getting through all of that! Now it is time to do some actual machine learning!\n",
+ "\n",
+ "**a)** Complete the code below so that you fit a second order polynomial to the data. You will need to look up some scikit-learn documentation online (look at the imported functions for hints).\n",
+ "\n",
+ "**b)** Compute the mean square error for the line model and for the second degree polynomial model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b58fb9bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.preprocessing import PolynomialFeatures # use the fit_transform method of the created object!\n",
+ "from sklearn.linear_model import LinearRegression\n",
+ "from sklearn.metrics import mean_squared_error"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0208e9ca",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "n = 100\n",
+ "x = np.random.rand(n, 1)\n",
+ "y = 2.0 + 5 * x**2 + 0.1 * np.random.randn(n, 1)\n",
+ "\n",
+ "line_model = LinearRegression().fit(x, y)\n",
+ "line_predict = line_model.predict(x)\n",
+ "#line_mse = ...\n",
+ "\n",
+ "#poly_features = ...\n",
+ "#poly_model = LinearRegression().fit(..., y)\n",
+ "#poly_predict = ...\n",
+ "#poly_mse = ...\n",
+ "\n",
+ "plt.scatter(x, y, label = \"Data\")\n",
+ "plt.scatter(x, line_predict, label = \"Line model\")\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "248d8931",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - The train-test split\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1efd3376",
+ "metadata": {},
+ "source": [
+ "Hopefully your model fit the data quite well, but to know how well the model actually generalizes to unseen data, which is most often what we care about, we need to split our data into training and testing data. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0f8d75fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "edb213fc",
+ "metadata": {},
+ "source": [
+ "**a)** Complete the code below so that the polynomial features and the targets y get split into training and test data.\n",
+ "\n",
+ "**b)** What is the shape of X_test?\n",
+ "\n",
+ "**c)** Fit your model to X_train\n",
+ "\n",
+ "**d)** Compute the MSE when your model predicts on the training data and on the testing data, using y_train and y_test as targets for the two cases.\n",
+ "\n",
+ "**e)** Why do we not fit the model to X_test?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a03e0388",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "polynomial_features = ...\n",
+ "\n",
+ "#X_train, X_test, y_train, y_test = train_test_split(polynomial_features, y, test_size=0.2)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "22e7536e",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/LectureNotes/_build/html/_sources/exercisesweek35.ipynb b/doc/LectureNotes/_build/html/_sources/exercisesweek35.ipynb
new file mode 100644
index 000000000..8ce6a6c3d
--- /dev/null
+++ b/doc/LectureNotes/_build/html/_sources/exercisesweek35.ipynb
@@ -0,0 +1,539 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b4005770",
+ "metadata": {},
+ "source": [
+ "# Exercises week 35\n",
+ "\n",
+ "## Deriving and Implementing Ordinary Least Squares"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ca1b589",
+ "metadata": {},
+ "source": [
+ "This week you will be deriving the analytical expressions for linear regression, building up the model from scratch. This will include taking several derivatives of products of vectors and matrices. Such derivatives are central to the optimization of many machine learning models. Although we will often use automatic differentiation in actual calculations, to be able to have analytical expressions is extremely helpful in case we have simpler derivatives as well as when we analyze various properties (like second derivatives) of the chosen cost functions.\n",
+ "\n",
+ "Vectors are always written as boldfaced lower case letters and matrices as upper case boldfaced letters. You will find useful the notes from week 35 on derivatives of vectors and matrices. See also the textbook of Faisal at al, chapter 5 and in particular sections 5.3-5.5 at "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41e92bf9",
+ "metadata": {},
+ "source": [
+ "### Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "- Take the derivatives of simple products between vectors and matrices\n",
+ "- Implement OLS using the analytical expressions\n",
+ "- Create a feature matrix from a set of data\n",
+ "- Create a feature matrix for a polynomial model\n",
+ "- Evaluate the MSE score of various model on training and test data, and comparing their performance\n",
+ "\n",
+ "### Deliverables\n",
+ "\n",
+ "Complete the following exercises while working in a jupyter notebook. Then, in canvas, include\n",
+ "- The jupyter notebook with the exercises completed\n",
+ "- An exported PDF of the notebook (https://code.visualstudio.com/docs/datascience/jupyter-notebooks#_export-your-jupyter-notebook)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7a9209d",
+ "metadata": {},
+ "source": [
+ "## How to take derivatives of Matrix-Vector expressions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "45f3712e",
+ "metadata": {},
+ "source": [
+ "In these exercises it is always useful to write out with summation indices the various quantities. Take also a look at the weekly slides from week 35 and the various examples included there.\n",
+ "\n",
+ "As an example, consider the function\n",
+ "\n",
+ "$$\n",
+ "f(\\boldsymbol{x}) =\\boldsymbol{A}\\boldsymbol{x},\n",
+ "$$\n",
+ "\n",
+ "which reads for a specific component $f_i$ (we define the matrix $\\boldsymbol{A}$ to have dimension $n\\times n$ and the vector $\\boldsymbol{x}$ to have length $n$)\n",
+ "\n",
+ "$$\n",
+ "f_i =\\sum_{j=0}^{n-1}a_{ij}x_j,\n",
+ "$$\n",
+ "\n",
+ "which leads to\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial f_i}{\\partial x_j}= a_{ij},\n",
+ "$$\n",
+ "\n",
+ "and written out in terms of the vector $\\boldsymbol{x}$ we have\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial f(\\boldsymbol{x})}{\\partial \\boldsymbol{x}}= \\boldsymbol{A}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5fa8a4e6",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Finding the derivative of Matrix-Vector expressions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "df7a2270",
+ "metadata": {},
+ "source": [
+ "**a)** Consider the expression\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial (\\boldsymbol{a}^T\\boldsymbol{x})}{\\partial \\boldsymbol{x}},\n",
+ "$$\n",
+ "\n",
+ "Where $\\boldsymbol{a}$ and $\\boldsymbol{x}$ are column-vectors with length $n$.\n",
+ "\n",
+ "What is the *shape* of the expression we are taking the derivative of?\n",
+ "\n",
+ "What is the *shape* of the thing we are taking the derivative with respect to?\n",
+ "\n",
+ "What is the *shape* of the result of the expression?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c0396734",
+ "metadata": {},
+ "source": [
+ "**b)** Show that\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial (\\boldsymbol{a}^T\\boldsymbol{x})}{\\partial \\boldsymbol{x}} = \\boldsymbol{a}^T,\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dc39d541",
+ "metadata": {},
+ "source": [
+ "**c)** Show that\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial (\\boldsymbol{a}^T\\boldsymbol{A}\\boldsymbol{a})}{\\partial \\boldsymbol{a}} = \\boldsymbol{a}^T(\\boldsymbol{A}+\\boldsymbol{A}^T),\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "498d13ec",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Deriving the expression for OLS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f3f771de",
+ "metadata": {},
+ "source": [
+ "The ordinary least squares method finds the parameters $\\boldsymbol{\\theta}$ which minimizes the squared error between our model $\\boldsymbol{X\\theta}$ and the true values $\\boldsymbol{y}$.\n",
+ "\n",
+ "To find the parameters $\\boldsymbol{\\theta}$ which minimizes this error, we take the derivative of the squared error expression with respect to $\\boldsymbol{\\theta}$, and set it equal to 0."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "49690237",
+ "metadata": {},
+ "source": [
+ "**a)** Very briefly explain why the approach above finds the parameters $\\boldsymbol{\\theta}$ which minimizes this error."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b7cccc9d",
+ "metadata": {},
+ "source": [
+ "We typically write the squared error as\n",
+ "\n",
+ "$$\n",
+ "\\vert\\vert\\boldsymbol{y} - \\boldsymbol{X\\theta}\\vert\\vert^2\n",
+ "$$\n",
+ "\n",
+ "which we can rewrite in matrix-vector form as\n",
+ "\n",
+ "$$\n",
+ "\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\theta}\\right)^T\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\theta}\\right)\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8fbecf74",
+ "metadata": {},
+ "source": [
+ "**b)** If $\\boldsymbol{X}$ is invertible, what is the expression for the optimal parameters $\\boldsymbol{\\theta}$? (**Hint:** Don't compute any derivatives, but solve $\\boldsymbol{X\\theta}=\\boldsymbol{y}$ for $\\boldsymbol{\\theta}$)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f37af8f0",
+ "metadata": {},
+ "source": [
+ "**c)** Show that\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial \\left(\\boldsymbol{x}-\\boldsymbol{A}\\boldsymbol{s}\\right)^T\\left(\\boldsymbol{x}-\\boldsymbol{A}\\boldsymbol{s}\\right)}{\\partial \\boldsymbol{s}} = -2\\left(\\boldsymbol{x}-\\boldsymbol{A}\\boldsymbol{s}\\right)^T\\boldsymbol{A},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "869fca4d",
+ "metadata": {},
+ "source": [
+ "**d)** Using the expression from **c)**, but substituting back in $\\boldsymbol{\\theta}$, $\\boldsymbol{y}$ and $\\boldsymbol{X}$, find the expression for the optimal parameters $\\boldsymbol{\\theta}$ in the case that $\\boldsymbol{X}$ is not invertible, but $\\boldsymbol{X^T X}$ is, which is most often the case.\n",
+ "\n",
+ "$$\n",
+ "\\boldsymbol{\\hat{\\theta}_{OLS}} = ...\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "57ca3d74",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Creating feature matrix and implementing OLS using the analytical expression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5dc179f7",
+ "metadata": {},
+ "source": [
+ "With the expression for $\\boldsymbol{\\hat{\\theta}_{OLS}}$, you now have what you need to implement OLS regression with your input data and target data $\\boldsymbol{y}$. But before you can do that, you need to set up you input data as a feature matrix $\\boldsymbol{X}$.\n",
+ "\n",
+ "In a feature matrix, each row is a datapoint and each column is a feature of that data. If you want to predict someones spending based on their income and number of children, for instance, you would create a row for each person in your dataset, with the montly income and the number of children as columns.\n",
+ "\n",
+ "We typically also include an intercept in our models. The intercept is a value that is added to our prediction regardless of the value of the other features. The intercept tries to account for constant effects in our data that are not dependant on anything else. In our current example, the intercept could account for living expenses which are typical regardless of income or childcare expenses.\n",
+ "\n",
+ "We calculate the optimal intercept by including a feature with the constant value of 1 in our model, which is then multplied by some parameter $\\theta_0$ from the OLS method into the optimal intercept value (which will be $\\theta_0$). In practice, we include the intercept in our model by adding a column of ones to the start of our feature matrix."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "e5ff2a69",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a3cf2792",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 20\n",
+ "income = np.array([116., 161., 167., 118., 172., 163., 179., 173., 162., 116., 101., 176., 178., 172., 143., 135., 160., 101., 149., 125.])\n",
+ "children = np.array([5, 3, 0, 4, 5, 3, 0, 4, 4, 3, 3, 5, 1, 0, 2, 3, 2, 1, 5, 4])\n",
+ "spending = np.array([152., 141., 102., 136., 161., 129., 99., 159., 160., 107., 98., 164., 121., 93., 112., 127., 117., 69., 156., 131.])\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5da61481",
+ "metadata": {},
+ "source": [
+ "**a)** Create a feature matrix $\\boldsymbol{X}$ for the features income and children, including an intercept column of ones at the start."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "5ad87a65",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X = np.zeros((n, 3))\n",
+ "#X[:, 0] = ...\n",
+ "#X[:, 1] = ...\n",
+ "#X[:, 2] = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0ddfac2",
+ "metadata": {},
+ "source": [
+ "**b)** Use the expression from **3d)** to find the optimal parameters $\\boldsymbol{\\hat{\\beta}_{OLS}}$ for predicting spending based on these features. Create a function for this operation, as you are going to need to use it a lot."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "8f3f68aa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def OLS_parameters(X, y):\n",
+ " return ...\n",
+ "\n",
+ "#beta = OLS_parameters(X, y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb6da80",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Fitting a polynomial"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71015064",
+ "metadata": {},
+ "source": [
+ "In this course, we typically do linear regression using polynomials, though in real world applications it is also very common to make linear models based on measured features like you did in the previous exercise.\n",
+ "\n",
+ "When fitting a polynomial with linear regression, we make each polynomial degree($x, x^2, x^3, ..., x^p$) its own feature."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "d7476c84",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 100\n",
+ "x = np.linspace(-3, 3, n)\n",
+ "y = np.exp(-x**2) + 1.5 * np.exp(-(x-2)**2) + np.random.normal(0, 0.1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8321451b",
+ "metadata": {},
+ "source": [
+ "**a)** Create a feature matrix $\\boldsymbol{X}$ for the features $x, x^2, x^3, x^4, x^5$, including an intercept column of ones at the start. Make this into a function, as you will do this a lot over the next weeks."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "91496e40",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p + 1))\n",
+ " #X[:, 0] = ...\n",
+ " #X[:, 1] = ...\n",
+ " #X[:, 2] = ...\n",
+ " # could this be a loop?\n",
+ "\n",
+ "#X = polynomial_features(x, 5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b84b1e31",
+ "metadata": {},
+ "source": [
+ "**b)** Use the expression from **3d)** to find the optimal parameters $\\boldsymbol{\\hat{\\beta}_{OLS}}$ for predicting $\\boldsymbol{y}$ based on these features. If you have done everything right so far, this code will not need changing."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "034f502c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#beta = OLS_parameters(X, y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d703f788",
+ "metadata": {},
+ "source": [
+ "**c)** Like in exercise 4 last week, split your feature matrix and target data into a training split and test split."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "29171358",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "#X_train, X_test, y_train, y_test = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a0e3509f",
+ "metadata": {},
+ "source": [
+ "**d)** Train your model on the training data(find the parameters which best fit) and compute the MSE on both the training and test data."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "1e346f4c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Ellipsis"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e431889",
+ "metadata": {},
+ "source": [
+ "**e)** Do the same for each polynomial degree from 2 to 10, and plot the MSE on both the training and test data as a function of polynomial degree. The aim is to reproduce Figure 2.11 of [Hastie et al](https://github.com/CompPhysics/MLErasmus/blob/master/doc/Textbooks/elementsstat.pdf). Feel free to read the discussions leading to figure 2.11 of Hastie et al. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "ceb57457",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Ellipsis"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e5b5954",
+ "metadata": {},
+ "source": [
+ "**f)** Interpret the graph. Why do the lines move as they do? What does it tell us about model performance and generalizability?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ad2acfb9",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5994f0c5",
+ "metadata": {},
+ "source": [
+ "## Exercise 5 - Comparing your code with sklearn"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8f595b7a",
+ "metadata": {},
+ "source": [
+ "When implementing different algorithms for the first time, it can be helpful to double check your results with established implementations before you go on to add more complexity."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8ab310c1",
+ "metadata": {},
+ "source": [
+ "**a)** Make sure your `polynomial_features` function creates the same feature matrix as sklearns PolynomialFeatures.\n",
+ "\n",
+ "(https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "85b964d1",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "73c32c52",
+ "metadata": {},
+ "source": [
+ "**b)** Make sure your `OLS_parameters` function computes the same parameters as sklearns LinearRegression with fit_intercept set to False, since the intercept is included in the feature matrix. Use `your_model_object.coef_` to extract the computed parameters.\n",
+ "\n",
+ "(https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "35b04126",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/LectureNotes/_build/html/_sources/exercisesweek36.ipynb b/doc/LectureNotes/_build/html/_sources/exercisesweek36.ipynb
new file mode 100644
index 000000000..e3365bb50
--- /dev/null
+++ b/doc/LectureNotes/_build/html/_sources/exercisesweek36.ipynb
@@ -0,0 +1,383 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "9dd8f8d0",
+ "metadata": {},
+ "source": [
+ "# Weekly Exercises 3\n",
+ "\n",
+ "## Deriving and Implementing Ridge Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e5cc5739",
+ "metadata": {},
+ "source": [
+ "## Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "- Take more derivatives of simple products between vectors and matrices\n",
+ "- Implement Ridge regression using the analytical expressions\n",
+ "- Scale data appropriately for linear regression\n",
+ "- Evaluate a model across two different hyperparameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "427d9b9d",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Choice of model and degrees of freedom"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff6ebdb5",
+ "metadata": {},
+ "source": [
+ "**a)** How many degrees of freedom does an OLS model fit to the features $x, x^2, x^3$ and the intercept have?\n",
+ "\n",
+ "**b)** Why is it bad for a model to have too many degrees of freedom?\n",
+ "\n",
+ "**c)** Why is it bad for a model to have too few degrees of freedom?\n",
+ "\n",
+ "**d)** Read [chapter 3.4.1 of Hastie et al.'s book](https://link.springer.com/book/10.1007/978-0-387-84858-7). What is the expression for the effective degrees of freedom of the ridge regression fit?\n",
+ "\n",
+ "**e)** Why might we want to use Ridge regression instead of OLS?\n",
+ "\n",
+ "**f)** Why migth we want to use OLS instead of Ridge regression?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a78b2ce2",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Deriving the expression for Ridge Regression\n",
+ "\n",
+ "The aim here is to derive the expression for the optimal parameters using Ridge regression.\n",
+ "\n",
+ "The expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, was given by the optimization problem"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "93a7ad16",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "{\\displaystyle \\min_{\\boldsymbol{\\beta}\\in {\\mathbb{R}}^{p}}}\\frac{1}{n}\\left\\{\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\right)^T\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\right)\\right\\}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6b182c01",
+ "metadata": {},
+ "source": [
+ "By minimizing the above equation with respect to the parameters $\\boldsymbol{\\beta}$ we could then obtain an analytical expression for the parameters $\\boldsymbol{\\hat\\beta_{OLS}}$.\n",
+ "\n",
+ "We can add a regularization parameter $\\lambda$ by\n",
+ "defining a new cost function to be optimized, that is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb065daf",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "{\\displaystyle \\min_{\\boldsymbol{\\beta}\\in\n",
+ "{\\mathbb{R}}^{p}}}\\frac{1}{n}\\vert\\vert \\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\vert\\vert_2^2+\\lambda\\vert\\vert \\boldsymbol{\\beta}\\vert\\vert_2^2\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "89ae11e8",
+ "metadata": {},
+ "source": [
+ "which leads to the Ridge regression minimization problem. (One can require as part of the optimization problem that $\\vert\\vert \\boldsymbol{\\beta}\\vert\\vert_2^2\\le t$, where $t$ is a finite number larger than zero. We will not implement that in this course.)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "456d58d4",
+ "metadata": {},
+ "source": [
+ "### a) Expression for Ridge regression\n",
+ "\n",
+ "Show that the optimal parameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a5677efd",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{Ridge}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}+\\lambda\\boldsymbol{I}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7b08048",
+ "metadata": {},
+ "source": [
+ "with $\\boldsymbol{I}$ being a $p\\times p$ identity matrix.\n",
+ "\n",
+ "The ordinary least squares result is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bb0e6af",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{OLS}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2faaae78",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Scaling data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "8ed79466",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.preprocessing import StandardScaler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "59d6f347",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 100\n",
+ "x = np.linspace(-3, 3, n)\n",
+ "y = np.exp(-x**2) + 1.5 * np.exp(-(x-2)**2) + np.random.normal(0, 0.1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9fc9fe0",
+ "metadata": {},
+ "source": [
+ "**a)** Adapt your function from last week to only include the intercept column if the boolean argument `intercept` is set to true."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "5aa9c86d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p, intercept=False):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p + 1))\n",
+ " #X[:, 0] = ...\n",
+ " #X[:, 1] = ...\n",
+ " #X[:, 2] = ...\n",
+ " # could this be a loop?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "id": "2ebf249a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p, intercept=False):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p))\n",
+ " X[:, 0] = x[:]\n",
+ " X[:, 1] = x**2\n",
+ " X[:, 2] = x**3\n",
+ " return X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5924634",
+ "metadata": {},
+ "source": [
+ "**b)** Split your data into training and test data(80/20 split)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "id": "676541e7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X = polynomial_features(x, 3)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "id": "f895606f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\n",
+ "x_train = X_train[:, 0] # These are used for plotting\n",
+ "x_test = X_test[:, 0] # These are used for plotting"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a58f05ad",
+ "metadata": {},
+ "source": [
+ "**c)** Scale your design matrix with the sklearn standard scaler, though based on the mean and standard deviation of the training data only."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "id": "0c07995a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "scaler = StandardScaler()\n",
+ "scaler.fit(X_train)\n",
+ "X_train_s = scaler.transform(X_train)\n",
+ "X_test_s = scaler.transform(X_test)\n",
+ "y_offset = np.mean(y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63b86003",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Implementing Ridge Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a2f52ef2",
+ "metadata": {},
+ "source": [
+ "**a)** Implement a function for computing the optimal Ridge parameters using the expression from **2a)**."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "id": "69f19bde",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def Ridge_parameters(X, y):\n",
+ " # Assumes X is scaled and has no intercept column\n",
+ " return np.linalg.inv(X.T @ X) @ X.T @ y\n",
+ "\n",
+ "beta = Ridge_parameters(X_train_s, y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "626c81ba",
+ "metadata": {},
+ "source": [
+ "**b)** Fit a model to the data, and plot the prediction using both the training and test x-values extracted before scaling, and the y_offset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "id": "f9ba0655",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 82,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plt.plot(x, y)\n",
+ "plt.scatter(x_train, X_train_s @ beta + y_offset)\n",
+ "plt.scatter(x_test, X_test_s @ beta + y_offset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2993cfae",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Testing multiple hyperparameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e6cdc89a",
+ "metadata": {},
+ "source": [
+ "**a)** Compute the MSE of your ridge model for polynomials of degrees 1 to 5 with lambda set to 0.01. Plot the MSE as a function of polynomial degree.\n",
+ "\n",
+ "**b)** Compute the MSE of your ridge model for a polynomial with degree 3, and with lambdas from $10^{-1}$ to $10^{-5}$ on a logarithmic scale. Plot the MSE as a function of lambda.\n",
+ "\n",
+ "**c)** Compute the MSE of your ridge model for polynomials of degrees 1 to 5, and with lambdas from $10^{-1}$ to $10^{-5}$ on a logarithmic scale. Plot the MSE as a function of polynomial degree and lambda using a [heatmap](https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/LectureNotes/_build/html/chapter1.html b/doc/LectureNotes/_build/html/chapter1.html
index 5fced352b..df8db8de4 100644
--- a/doc/LectureNotes/_build/html/chapter1.html
+++ b/doc/LectureNotes/_build/html/chapter1.html
@@ -223,10 +223,11 @@
In this first week will focus on getting you set up with the programs you are going to be using throughout this course. We expect that many of you will encounter some trouble with setting these programs up, as they can be extremely finnicky and prone to not working the same on all machines, so we strongly encourage you to not get discouraged, and to show up to the group-sessions where we can help you along. The group sessions are also the best place to find group partners for the projects and to be challenged on your understanding of the material, which are both essential to doing well in this course. We strongly encourage you to form groups of 2-3 participants.
+
If you are unable to complete this week’s exercises, don’t worry, this will likely be the most frustrating week for many of you. You have time to get back on track next week, especially if you come to the group-sessions! Note also that this week’s set of exercises does not count for the additional score. The deadline for the weekly exercises is set to Fridays, at midnight.
Optional: A link to your github repository, which must be set to public, include the notebook file, a README file, requirements file and gitignore file.
+
+
We require you to deliver a jupyter notebook so that we can evaluate the results of your code without needing to download and run the code of every student, as well as to teach you to use this useful tool.
In this course, we require you to pay extra mind to the reproducibility of your results and the shareability of your code. The first step toward these goals is using a version control system like git and online repository like Github.
+
a) Download git if you don’t already have it on your machine, check with the terminal command ´git –version´ (https://git-scm.com/downloads).
c) Learn the basics of opening the terminal and navigating folders on your operating system. Things to learn: Opening a terminal, opening a terminal in a specific folder, listing the contents of the current folder, navigating into a folder, navigating out of a folder.
+
d) Download the Github CLI tool and run ´gh auth login´ in your terminal to authenticate your local machine for some of the later steps. (cli/cli). You might need to change file permissions to make it work, ask us or ChatGPT for help with these issues.
+
e) As an alternative to the above terminal based instructions, you could install GitHub Desktop (see https://desktop.github.com/download/) or if you prefer GitLab, GitLab desktop (see https://about.gitlab.com/install/). This sets up all communications between your PC/Laptop and the repository. This allows you to combine exercises 1 and 2 in an easy way if you don’t want to use terminarl. Keep in mind that these GUIs (graphical user interfaces) are not text editors.
a) Create an empty repository for your coursework in this course in your browser at github.com (or uio github).
+
b) Open a terminal in the location you want to create your local folder for this repository, like your desktop.
+
c) Clone the repository to your laptop using the terminal command ´gh repo clone username/repository-name´. This creates a folder with the same name as the repository. Moving it or renaming it might require some extra steps.
+
d) Download this jupyter notebook. Add the notebook to the local folder.
+
e) Run the ´git add .´ command command in a terminal opened in the local folder to stage the current changes in the folder to be commited to the version control history. Run ´git status´ to see the staged files.
+
f) Run the ´git commit -m “Adding first weekly assignment file”´ command to commit the staged changes to the version control history. Run ´git status´ to see that no files are staged.
+
g) Run the ´git push” command to upload the commited changes to the remote repository on Github.
+
h) Add a file called README.txt to the repository at Github.com. Don’t do this in your local folder. Add a suitable title for your repository and some inforomation to the file.
+
i) Run the ´git fetch origin´ command to fetch the latest remote changes to your repository.
+
j) Run the ´git pull´ command to download and update files to match the remote changes.
+
+
+
Exercise 3 - Setting up a Python virtual environment#
+
Following the themes from the previous exercises, another way of improving the reproducibility of your results and shareability of your code is having a good handle on which python packages you are using.
+
There are many ways to manage your packages in Python, and you are free to use any approach you want, but in this course we encourage you to use something called a virtual environment. A virtual environemnt is a folder in your project which contains a Python runtime executable as well as all the packages you are using in the current project. In this way, each of your projects has its required set of packages installed in the same folder, so that if anything goes wrong while managing your packages it only affects the one project, and if multiple projects require different versions of the same package, you don’t need to worry about messing up old projects. Also, it’s easy to just delete the folder and start over if anything goes wrong.
+
Virtual environments are typically created, activated, managed and updated using terminal commands, but for now we recommend that you let for example VS Code (a popular cross-paltform package) handle it for you to make the coding experience much easier. If you are familiar with another approach for virtual environments that works for you, feel free to keep doing it that way.
b) Press ´Cmd + Shift + P´, then search and run ´Python: Create Environment…´
+
c) Select ´Venv´
+
d) Choose the most up-to-date version of Python your have installed.
+
e) Press ´Cmd + Shift + P´, then search and run ´Python: Select Interpreter´
+
f) Selevet the (.venv) option you just created.
+
g) Open a terminal in VS Code, the venv name should be visible at the beginning of the line. Run piplist to see that there are no packages install in the environment.
+
h) In this terminal, run pipinstallmatplotlibnumpyscikit-learn. This will install the listed packages.
+
i) To make these installations reproducible, which is important for reproducing results and sharing your code, run ´pip freeze > requirements.txt´ to create the file requirements.txt with all your dependencies.
+
Now, anyone who wants to recreate your package setup can download your requirements.txt file and run ´pip install -r requirements.txt´ to install the correct packages and versions. To keep the requirements.txt file up to date with your environment, you will need to re-run the freeze command whenever you install a new package.
+
j) Create a .gitignore file at the root of your project folder, and add the line ´.venv´ to it. This way, you won’t try to upload a copy of all your python packages when you regularly push your changes to Github. Ignored files should not show up when you run ´git status´, and are not staged when running ´git add .´, try it!
Great job on getting through all of that! Now it is time to do some actual machine learning!
+
a) Complete the code below so that you fit a second order polynomial to the data. You will need to look up some scikit-learn documentation online (look at the imported functions for hints).
+
b) Compute the mean square error for the line model and for the second degree polynomial model.
+
+
+
importnumpyasnp
+importmatplotlib.pyplotasplt
+fromsklearn.preprocessingimportPolynomialFeatures# use the fit_transform method of the created object!
+fromsklearn.linear_modelimportLinearRegression
+fromsklearn.metricsimportmean_squared_error
+
Hopefully your model fit the data quite well, but to know how well the model actually generalizes to unseen data, which is most often what we care about, we need to split our data into training and testing data.
This week you will be deriving the analytical expressions for linear regression, building up the model from scratch. This will include taking several derivatives of products of vectors and matrices. Such derivatives are central to the optimization of many machine learning models. Although we will often use automatic differentiation in actual calculations, to be able to have analytical expressions is extremely helpful in case we have simpler derivatives as well as when we analyze various properties (like second derivatives) of the chosen cost functions.
+
Vectors are always written as boldfaced lower case letters and matrices as upper case boldfaced letters. You will find useful the notes from week 35 on derivatives of vectors and matrices. See also the textbook of Faisal at al, chapter 5 and in particular sections 5.3-5.5 at CompPhysics/MachineLearning
How to take derivatives of Matrix-Vector expressions#
+
In these exercises it is always useful to write out with summation indices the various quantities. Take also a look at the weekly slides from week 35 and the various examples included there.
which reads for a specific component \(f_i\) (we define the matrix \(\boldsymbol{A}\) to have dimension \(n\times n\) and the vector \(\boldsymbol{x}\) to have length \(n\))
The ordinary least squares method finds the parameters \(\boldsymbol{\theta}\) which minimizes the squared error between our model \(\boldsymbol{X\theta}\) and the true values \(\boldsymbol{y}\).
+
To find the parameters \(\boldsymbol{\theta}\) which minimizes this error, we take the derivative of the squared error expression with respect to \(\boldsymbol{\theta}\), and set it equal to 0.
+
a) Very briefly explain why the approach above finds the parameters \(\boldsymbol{\theta}\) which minimizes this error.
b) If \(\boldsymbol{X}\) is invertible, what is the expression for the optimal parameters \(\boldsymbol{\theta}\)? (Hint: Don’t compute any derivatives, but solve \(\boldsymbol{X\theta}=\boldsymbol{y}\) for \(\boldsymbol{\theta}\))
d) Using the expression from c), but substituting back in \(\boldsymbol{\theta}\), \(\boldsymbol{y}\) and \(\boldsymbol{X}\), find the expression for the optimal parameters \(\boldsymbol{\theta}\) in the case that \(\boldsymbol{X}\) is not invertible, but \(\boldsymbol{X^T X}\) is, which is most often the case.
+
+\[
+\boldsymbol{\hat{\theta}_{OLS}} = ...
+\]
+
+
+
Exercise 3 - Creating feature matrix and implementing OLS using the analytical expression#
+
With the expression for \(\boldsymbol{\hat{\theta}_{OLS}}\), you now have what you need to implement OLS regression with your input data and target data \(\boldsymbol{y}\). But before you can do that, you need to set up you input data as a feature matrix \(\boldsymbol{X}\).
+
In a feature matrix, each row is a datapoint and each column is a feature of that data. If you want to predict someones spending based on their income and number of children, for instance, you would create a row for each person in your dataset, with the montly income and the number of children as columns.
+
We typically also include an intercept in our models. The intercept is a value that is added to our prediction regardless of the value of the other features. The intercept tries to account for constant effects in our data that are not dependant on anything else. In our current example, the intercept could account for living expenses which are typical regardless of income or childcare expenses.
+
We calculate the optimal intercept by including a feature with the constant value of 1 in our model, which is then multplied by some parameter \(\theta_0\) from the OLS method into the optimal intercept value (which will be \(\theta_0\)). In practice, we include the intercept in our model by adding a column of ones to the start of our feature matrix.
b) Use the expression from 3d) to find the optimal parameters \(\boldsymbol{\hat{\beta}_{OLS}}\) for predicting spending based on these features. Create a function for this operation, as you are going to need to use it a lot.
In this course, we typically do linear regression using polynomials, though in real world applications it is also very common to make linear models based on measured features like you did in the previous exercise.
+
When fitting a polynomial with linear regression, we make each polynomial degree(\(x, x^2, x^3, ..., x^p\)) its own feature.
a) Create a feature matrix \(\boldsymbol{X}\) for the features \(x, x^2, x^3, x^4, x^5\), including an intercept column of ones at the start. Make this into a function, as you will do this a lot over the next weeks.
+
+
+
defpolynomial_features(x,p):
+ n=len(x)
+ X=np.zeros((n,p+1))
+ #X[:, 0] = ...
+ #X[:, 1] = ...
+ #X[:, 2] = ...
+ # could this be a loop?
+
+#X = polynomial_features(x, 5)
+
+
+
+
+
b) Use the expression from 3d) to find the optimal parameters \(\boldsymbol{\hat{\beta}_{OLS}}\) for predicting \(\boldsymbol{y}\) based on these features. If you have done everything right so far, this code will not need changing.
+
+
+
#beta = OLS_parameters(X, y)
+
+
+
+
+
c) Like in exercise 4 last week, split your feature matrix and target data into a training split and test split.
d) Train your model on the training data(find the parameters which best fit) and compute the MSE on both the training and test data.
+
+
+
...
+
+
+
+
+
Ellipsis
+
+
+
+
+
e) Do the same for each polynomial degree from 2 to 10, and plot the MSE on both the training and test data as a function of polynomial degree. The aim is to reproduce Figure 2.11 of Hastie et al. Feel free to read the discussions leading to figure 2.11 of Hastie et al.
+
+
+
...
+
+
+
+
+
Ellipsis
+
+
+
+
+
f) Interpret the graph. Why do the lines move as they do? What does it tell us about model performance and generalizability?
When implementing different algorithms for the first time, it can be helpful to double check your results with established implementations before you go on to add more complexity.
+
a) Make sure your polynomial_features function creates the same feature matrix as sklearns PolynomialFeatures.
b) Make sure your OLS_parameters function computes the same parameters as sklearns LinearRegression with fit_intercept set to False, since the intercept is included in the feature matrix. Use your_model_object.coef_ to extract the computed parameters.
e) Why might we want to use Ridge regression instead of OLS?
+
f) Why migth we want to use OLS instead of Ridge regression?
+
+
+
Exercise 2 - Deriving the expression for Ridge Regression#
+
The aim here is to derive the expression for the optimal parameters using Ridge regression.
+
The expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, was given by the optimization problem
By minimizing the above equation with respect to the parameters \(\boldsymbol{\beta}\) we could then obtain an analytical expression for the parameters \(\boldsymbol{\hat\beta_{OLS}}\).
+
We can add a regularization parameter \(\lambda\) by
+defining a new cost function to be optimized, that is
which leads to the Ridge regression minimization problem. (One can require as part of the optimization problem that \(\vert\vert \boldsymbol{\beta}\vert\vert_2^2\le t\), where \(t\) is a finite number larger than zero. We will not implement that in this course.)
b) Split your data into training and test data(80/20 split)
+
+
+
X=polynomial_features(x,3)
+
+
+
+
+
+
+
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2)
+x_train=X_train[:,0]# These are used for plotting
+x_test=X_test[:,0]# These are used for plotting
+
+
+
+
+
c) Scale your design matrix with the sklearn standard scaler, though based on the mean and standard deviation of the training data only.
a) Implement a function for computing the optimal Ridge parameters using the expression from 2a).
+
+
+
defRidge_parameters(X,y):
+ # Assumes X is scaled and has no intercept column
+ returnnp.linalg.inv(X.T@X)@X.T@y
+
+beta=Ridge_parameters(X_train_s,y_train)
+
+
+
+
+
b) Fit a model to the data, and plot the prediction using both the training and test x-values extracted before scaling, and the y_offset.
a) Compute the MSE of your ridge model for polynomials of degrees 1 to 5 with lambda set to 0.01. Plot the MSE as a function of polynomial degree.
+
b) Compute the MSE of your ridge model for a polynomial with degree 3, and with lambdas from \(10^{-1}\) to \(10^{-5}\) on a logarithmic scale. Plot the MSE as a function of lambda.
+
c) Compute the MSE of your ridge model for polynomials of degrees 1 to 5, and with lambdas from \(10^{-1}\) to \(10^{-5}\) on a logarithmic scale. Plot the MSE as a function of polynomial degree and lambda using a heatmap.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/LectureNotes/_build/html/genindex.html b/doc/LectureNotes/_build/html/genindex.html
index 10764068d..9f60090ee 100644
--- a/doc/LectureNotes/_build/html/genindex.html
+++ b/doc/LectureNotes/_build/html/genindex.html
@@ -220,10 +220,11 @@
diff --git a/doc/LectureNotes/_build/jupyter_execute/cb756715680fbe8cbf1d070371bf3950695ddf24b29ecb476c48fb9e559af08e.png b/doc/LectureNotes/_build/jupyter_execute/cb756715680fbe8cbf1d070371bf3950695ddf24b29ecb476c48fb9e559af08e.png
new file mode 100644
index 000000000..a16a30cd2
Binary files /dev/null and b/doc/LectureNotes/_build/jupyter_execute/cb756715680fbe8cbf1d070371bf3950695ddf24b29ecb476c48fb9e559af08e.png differ
diff --git a/doc/LectureNotes/_build/jupyter_execute/exercisesweek34.ipynb b/doc/LectureNotes/_build/jupyter_execute/exercisesweek34.ipynb
new file mode 100644
index 000000000..851509f7b
--- /dev/null
+++ b/doc/LectureNotes/_build/jupyter_execute/exercisesweek34.ipynb
@@ -0,0 +1,315 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "232d1306",
+ "metadata": {},
+ "source": [
+ "# Exercises week 34\n",
+ "\n",
+ "## Coding Setup and Linear Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9b66a351",
+ "metadata": {},
+ "source": [
+ "Welcome to FYS-STK3155/4155!\n",
+ "\n",
+ "In this first week will focus on getting you set up with the programs you are going to be using throughout this course. We expect that many of you will encounter some trouble with setting these programs up, as they can be extremely finnicky and prone to not working the same on all machines, so we strongly encourage you to not get discouraged, and to show up to the group-sessions where we can help you along. The group sessions are also the best place to find group partners for the projects and to be challenged on your understanding of the material, which are both essential to doing well in this course. We strongly encourage you to form groups of 2-3 participants. \n",
+ "\n",
+ "If you are unable to complete this week's exercises, don't worry, this will likely be the most frustrating week for many of you. You have time to get back on track next week, especially if you come to the group-sessions! Note also that this week's set of exercises does not count for the additional score. The deadline for the weekly exercises is set to Fridays, at midnight."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "36d8750b",
+ "metadata": {},
+ "source": [
+ "### Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "\n",
+ "- Create and use a Github repository\n",
+ "- Set up and use a virtual environment in Python\n",
+ "- Fit an OLS model to data using scikit-learn\n",
+ "- Fit a model on training data and evaluate it on test data\n",
+ "\n",
+ "### Deliverables\n",
+ "\n",
+ "Complete the following exercises while working in a jupyter notebook. Exercises 1,2 and 3 require no writing in the notebook. Then, in canvas, include\n",
+ "- The jupyter notebook with the exercises completed\n",
+ "- An exported PDF of the notebook (https://code.visualstudio.com/docs/datascience/jupyter-notebooks#_export-your-jupyter-notebook)\n",
+ "- Optional: A link to your github repository, which must be set to public, include the notebook file, a README file, requirements file and gitignore file.\n",
+ "\n",
+ "We require you to deliver a jupyter notebook so that we can evaluate the results of your code without needing to download and run the code of every student, as well as to teach you to use this useful tool."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2a9c7ef8",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Github Setup\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1498aed1",
+ "metadata": {},
+ "source": [
+ "In this course, we require you to pay extra mind to the reproducibility of your results and the shareability of your code. The first step toward these goals is using a version control system like git and online repository like Github.\n",
+ "\n",
+ "**a)** Download git if you don't already have it on your machine, check with the terminal command ´git --version´ (https://git-scm.com/downloads).\n",
+ "\n",
+ "**b)** Create a Github account(https://github.com/), or log in to github with your UiO account (https://github.uio.no/login).\n",
+ "\n",
+ "**c)** Learn the basics of opening the terminal and navigating folders on your operating system. Things to learn: Opening a terminal, opening a terminal in a specific folder, listing the contents of the current folder, navigating into a folder, navigating out of a folder.\n",
+ "\n",
+ "**d)** Download the Github CLI tool and run ´gh auth login´ in your terminal to authenticate your local machine for some of the later steps. (https://github.com/cli/cli#installation). You might need to change file permissions to make it work, ask us or ChatGPT for help with these issues.\n",
+ "\n",
+ "**e)** As an alternative to the above terminal based instructions, you could install GitHub Desktop (see https://desktop.github.com/download/) or if you prefer GitLab, GitLab desktop (see https://about.gitlab.com/install/). This sets up all communications between your PC/Laptop and the repository. This allows you to combine exercises 1 and 2 in an easy way if you don't want to use terminarl. Keep in mind that these GUIs (graphical user interfaces) are not text editors."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c56fbefa",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Setting up a Github repository\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb9b8acd",
+ "metadata": {
+ "vscode": {
+ "languageId": "plaintext"
+ }
+ },
+ "source": [
+ "**a)** Create an empty repository for your coursework in this course in your browser at github.com (or uio github).\n",
+ "\n",
+ "**b)** Open a terminal in the location you want to create your local folder for this repository, like your desktop.\n",
+ "\n",
+ "**c)** Clone the repository to your laptop using the terminal command ´gh repo clone username/repository-name´. This creates a folder with the same name as the repository. Moving it or renaming it might require some extra steps.\n",
+ "\n",
+ "**d)** Download this jupyter notebook. Add the notebook to the local folder.\n",
+ "\n",
+ "**e)** Run the ´git add .´ command command in a terminal opened in the local folder to stage the current changes in the folder to be commited to the version control history. Run ´git status´ to see the staged files.\n",
+ "\n",
+ "**f)** Run the ´git commit -m \"Adding first weekly assignment file\"´ command to commit the staged changes to the version control history. Run ´git status´ to see that no files are staged.\n",
+ "\n",
+ "**g)** Run the ´git push\" command to upload the commited changes to the remote repository on Github.\n",
+ "\n",
+ "**h)** Add a file called README.txt to the repository at Github.com. Don't do this in your local folder. Add a suitable title for your repository and some inforomation to the file.\n",
+ "\n",
+ "**i)** Run the ´git fetch origin´ command to fetch the latest remote changes to your repository.\n",
+ "\n",
+ "**j)** Run the ´git pull´ command to download and update files to match the remote changes.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f84d0db6",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Setting up a Python virtual environment\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b5a4818a",
+ "metadata": {},
+ "source": [
+ "Following the themes from the previous exercises, another way of improving the reproducibility of your results and shareability of your code is having a good handle on which python packages you are using.\n",
+ "\n",
+ "There are many ways to manage your packages in Python, and you are free to use any approach you want, but in this course we encourage you to use something called a virtual environment. A virtual environemnt is a folder in your project which contains a Python runtime executable as well as all the packages you are using in the current project. In this way, each of your projects has its required set of packages installed in the same folder, so that if anything goes wrong while managing your packages it only affects the one project, and if multiple projects require different versions of the same package, you don't need to worry about messing up old projects. Also, it's easy to just delete the folder and start over if anything goes wrong.\n",
+ "\n",
+ "Virtual environments are typically created, activated, managed and updated using terminal commands, but for now we recommend that you let for example VS Code (a popular cross-paltform package) handle it for you to make the coding experience much easier. If you are familiar with another approach for virtual environments that works for you, feel free to keep doing it that way.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0f6de364",
+ "metadata": {},
+ "source": [
+ "**a)** Open this notebook in VS Code (https://code.visualstudio.com/Download). Download the Python and Jupyter extensions.\n",
+ "\n",
+ "**b)** Press ´Cmd + Shift + P´, then search and run ´Python: Create Environment...´\n",
+ "\n",
+ "**c)** Select ´Venv´\n",
+ "\n",
+ "**d)** Choose the most up-to-date version of Python your have installed.\n",
+ "\n",
+ "**e)** Press ´Cmd + Shift + P´, then search and run ´Python: Select Interpreter´\n",
+ "\n",
+ "**f)** Selevet the (.venv) option you just created.\n",
+ "\n",
+ "**g)** Open a terminal in VS Code, the venv name should be visible at the beginning of the line. Run `pip list` to see that there are no packages install in the environment.\n",
+ "\n",
+ "**h)** In this terminal, run `pip install matplotlib numpy scikit-learn`. This will install the listed packages.\n",
+ "\n",
+ "**i)** To make these installations reproducible, which is important for reproducing results and sharing your code, run ´pip freeze > requirements.txt´ to create the file requirements.txt with all your dependencies.\n",
+ "\n",
+ "Now, anyone who wants to recreate your package setup can download your requirements.txt file and run ´pip install -r requirements.txt´ to install the correct packages and versions. To keep the requirements.txt file up to date with your environment, you will need to re-run the freeze command whenever you install a new package.\n",
+ "\n",
+ "**j)** Create a .gitignore file at the root of your project folder, and add the line ´.venv´ to it. This way, you won't try to upload a copy of all your python packages when you regularly push your changes to Github. Ignored files should not show up when you run ´git status´, and are not staged when running ´git add .´, try it!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5d184ab1",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Fitting an OLS model to data\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d19ebd67",
+ "metadata": {},
+ "source": [
+ "Great job on getting through all of that! Now it is time to do some actual machine learning!\n",
+ "\n",
+ "**a)** Complete the code below so that you fit a second order polynomial to the data. You will need to look up some scikit-learn documentation online (look at the imported functions for hints).\n",
+ "\n",
+ "**b)** Compute the mean square error for the line model and for the second degree polynomial model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b58fb9bf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.preprocessing import PolynomialFeatures # use the fit_transform method of the created object!\n",
+ "from sklearn.linear_model import LinearRegression\n",
+ "from sklearn.metrics import mean_squared_error"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0208e9ca",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAASZ5JREFUeJzt3QuczPX++PH37GItdpclLVIuiSSV08U1KUVJOnXSr4vLOV1Jkn+FOn6ojqXboZtup1Kd8lMhKioJSeIkHZduWJdEInZdF7vzf7y/s7PNzs7l+535zv31fDzmrJ35zsx3J8f3vZ/P++JwOp1OAQAAsEGaHS8CAACgCCwAAIBtCCwAAIBtCCwAAIBtCCwAAIBtCCwAAIBtCCwAAIBtCCwAAIBtqkiUlZaWyi+//CJZWVnicDii/fYAACAE2k9z37590rBhQ0lLS4ufwEKDisaNG0f7bQEAgA22bt0qJ5xwgj2BRZMmTWTz5s2V7h88eLA888wzpl5DVyrcJ5adnW3l7QEAQIwUFRUZCwPu67gtgcWKFSukpKSk/Ps1a9bIxRdfLNdcc43p13Bvf2hQQWABAEBiCZbGYCmwOO644yp8P2HCBGnevLl07do1tLMDAABJJeQciyNHjsgbb7whw4cPDxi9FBcXGzfPpRQAAJCcQi43nTVrluzdu1cGDhwY8Lj8/HzJyckpv5G4CQBA8nI4tX4kBD169JBq1arJnDlzAh7na8VCg4vCwkK/ORaax3H06NFQTgsJJj09XapUqULpMQDEOb1+6wJBoOt3yFshWhkyf/58mTFjRtBjMzIyjJtZ+/fvl59//tmol0VqqFGjhjRo0MAIVAEAiS2kwOKVV16R+vXrS69evWw9GV2p0KBCLzSaKMpvsclNg0fN1fntt9+koKBAWrRoEbDpCgAgCQML7ZypgcWAAQOMJWw76faHXmw0qMjMzLT1tRGf9L9z1apVjVUwDTKqV68e61MCAITB8q+HugWyZcsW+dvf/iaRwkpFamGVAgCSh+Ulh0suuYT8BwAA4kxJqVOWF/wuO/cdlvpZ1eXcprmSnhb9X9SjPisEAADYG0x8sm6HzFr1i/x+4Ej5Yw1yqsuY3q2lZ5sGEk0EFgAAJKB5a7bLuDnrZHvhYZ+P7yg8LIPeWClTbmwX1eCCzW0baJMwzQvRmyYiHn/88cYMlZdfftlIdjXr1Vdfldq1a0f0XAEAyRFUDHpjpd+gQrmTFjT40JWNaEnKwEI/wC837Jb3Vm0zvkbjA+3Zs6ds375dNm3aJHPnzpVu3brJXXfdJZdffrkcO3Ys4u8PAEhuJWXXtpnfbJP7Z64uDxwC0WM0+NDtkmipkgpLQ9HYZ9ImYHl5ecafGzVqJO3atZP27dvLRRddZKxE3HzzzfLEE08YpbobN26U3Nxc6d27tzzyyCNSq1YtWbhwofz1r3+tUBUzZswYGTt2rLz++usyefJk+eGHH6RmzZpy4YUXyqRJk4xeIgCA5DcvyLZHMJrQGS1pqbA05N5n0sejSQOAM844o7xDqZZVPvnkk7J27VqZOnWqLFiwQO677z7jsY4dOxrBgrZJ1ZUPvd1zzz3l/T0eeugh+fbbb40ZLboqEmxGCwAgdbY9gtEqkWipkkxLRBrN+Voa0vt0DUAfv7h1XlTLb1q1aiX//e9/jT8PGzas/P4mTZrIww8/LLfffrs8++yzRjtr7cGuqxXulQ83z54hzZo1M4KTc845x2h/rqsdAIDkVBLg2maGXu3yclylp9GSNCsWun8ULIkl2vtMxvs6neVbG9pcTLdGdKskKytL+vXrJ7t375aDBw8GfI2vv/7a2DY58cQTjed17drVuF8blQEAktfyINe2QNy/QmsqQDR/oU6awMLs/lE095nUd999J02bNjW2LzSRs23btvLuu+8awcIzzzxjHKOtrP05cOCAMUlWt0j+/e9/y4oVK2TmzJlBnwcASHw7w7hm6UpFtEtNk2orxOz+UTT3mTSHYvXq1XL33XcbgYSWnj7++OPlLaynT59e4XjdDtFBbJ6+//57Y1VjwoQJxrh59Z///CdqPwMAIHbq1TI/HdzTkG7N5e6LW8ak82bSrFjo/pFWf/j7CPX+BhHcZyouLpYdO3bItm3bZOXKlTJ+/Hjp06ePsUrRv39/Ofnkk40kzKeeesqoCtFKj+eee67Ca2jeheZNfPrpp7Jr1y5ji0S3PzTgcD9v9uzZRiInACAFOEN7WqeTj4tJUJFUgYV+gLqPpBwx2GeaN2+eNGjQwAgOtKfFZ599ZiRZvvfee5Kenm5Uh2i56cSJE6VNmzbGtkZ+fn6F19DKEE3mvPbaa40Jr1qKql+1XPXtt9+W1q1bGysXjz32WER+BgBAfNl1oNjS8ZH+JdrUOTijPFGsqKjIqH4oLCw08gY8HT58WAoKCoychFDHZ8eqjwVCZ8d/dwBIRl9u2C3XvbjM1LHuX5sjlVcR6PqdlDkWbvphaklpPEx4AwDAjm1+7cfkNJGsGQ+/RCddYKE0iOjQvG6sTwMAgLD9zzknyj/n/1jpfv11WYONv3VqYvxCHS+/RCdlYAEAQLK38c6LkxUKbwQWAADEaRtvp5/H7+7eQoZc2CIuViiStioEAIBUaOPtEJFpK7ZKvCKwAAAgjiyP0xEVZhFYAAAQR3bG6YgKswgsAACII/XjcESFFSRvAgAQ5RyK5QF6LQXrXRGLUehWsGIRBTo2fdasWZIsxo4dK2eeeabp43Wyq34Gq1atiuh5AUAiVHt0nrjA6KZ517RVxlf9Xu/37l3hL3lT77/ijAZxWRGSvCsWpSUim5eK7P9VpNbxIid1FElLj9jbDRw4UPbu3es3eNi+fbvUqVMnYu8PAIh//kpIdWVC79dW3CpQ7wq3FxYXyFkn1om7HhbJGVismy0yb4RI0S9/3JfdUKTnRJHWV8TklPLy8mLyvgCA+C8hdZZtb4yasVr2HDxq+jX19bTjZrytXKQlXVAxvX/FoEIVbXfdr4/HeCvEvS0wY8YM6datm9SoUcOYfPrll19WeM6SJUukS5cukpmZKY0bN5ahQ4fKgQMHgm5PvPzyy8ao9Vq1asngwYOlpKTEmJKqwU39+vXlH//4R4XnbdmyxRjvrsfrUJm+ffvKr7/+WuEYnah6/PHHS1ZWltx0003G0DBvL730kpx66qnGELFWrVrJs88+G+anBgCpVUK6x0JQEc8lp2lJtf2hKxV+40FdhxrpOi4OPPDAA3LPPfcYeQennHKKXHfddXLs2DHjsQ0bNhij16+++mr573//K//3f/9nBBpDhgwJ+Jr6vLlz5xoj3N966y3517/+Jb169ZKff/5ZFi1aZIxs//vf/y5fffWVcXxpaakRVPz+++/G45988ols3LjRGNvuNn36dCNoGT9+vPznP/8xRsN7Bw06Av5///d/jaDlu+++M44dPXq0TJ06NSKfHQAkmp0RKg2Nx5LT5NkK0ZwK75WKCpwiRdtcxzXtIrGmQYVe9NW4cePktNNOk/Xr1xu/7efn58sNN9wgw4YNMx5v0aKFPPnkk9K1a1eZMmWK39HiGijoioWuLLRu3dpYEfnhhx/kww8/lLS0NGnZsqURXHz22Wdy3nnnyaeffiqrV682Rpbrqoh67bXXjHNZsWKFnHPOOTJp0iRjlUJv6uGHH5b58+dXWLUYM2aMPP7443LVVVcZ3+v483Xr1snzzz8vAwYMiPhnCQDxrn6ESkPjseQ0eVYsNFHTzuMirG3btuV/1lUAtXPnTuPrt99+K6+++qqxPeG+9ejRwwgcNAjwp0mTJkZQ4abbFxpgaFDheZ/7fXR1QQMKd1Ch9PjatWsbj7mP0SDEU4cOHcr/rNszulKigYfn+WoAovcDAET+dFIdsTMVQl+qQZyWnCbPioVWf9h5XIRVrVq1/M+ac6E0cFD79++X2267zcir8Kb5E2Ze0/26vu5zv48d9FzViy++WCkASU+PXCUOACSSrzfvkVJ/9aMWueMTnWwab4mbyRVYaEmpVn9ooqa/liL6uB4X59q1a2dsJZx88skRfR9Ntty6datxc69a6Ptq6ayuXLiP0ZyM/v37lz9v2bJlFVZAGjZsaORm6PYNACC8XAgNFQLFIPE6Lj35AgvtU6ElpVr9Uek/S1lE13NCxPpZFBYWVmoAVbdu3QrbDGaNGDFC2rdvbyRr3nzzzVKzZk3jgq/JlU8//bRt59y9e3c5/fTTjYBAcyk0eVQrSTSX4+yzzzaOueuuu4w+Hfp9p06djETNtWvXSrNmzcpfR3NEdHUlJyfHSDotLi42Ej337Nkjw4cPt+18ASBR1TeZC6Hj0HVyqWcFSV52hlx37onSpF5Nn506403yBBZK+1T0fc1PH4sJEe1jsXDhQjnrrLMq3Kd5B1qGGUr+hVZpaOWIlpw6nU5p3rx5hWoNO+i2yHvvvSd33nmnnH/++UYuhgYGTz31VPkx+p6aK3HfffcZCZtaqTJo0CD56KOPyo/R4EfLZh999FG59957jUBIAxZ38ikApLpzTbbpHnJhC+MWqOV3vHM49aoVRUVFRcZvtvobvvZN8KQXLk1O1KoCf5UP8dh5E+Gx7b87ACRA503xvaZudN6M1+2NYNfv5F2xcNMgIg5KSgEAqafEz5AxDRo0ePBu2R3vORNWJWdgAQBAjFYlxnkFDg08Age9aRvuRN7qCIbAAgCAKA0Z69nGNZW0Q/O69p9AnKQBEFgAABCFIWPjIjk0LI4GcMZl580o55MixvjvDSAVhoxtj8TQMF2lWKitFvrFzQDOuAos3J0ajxw5EutTQRQdPHjQ+OrdJRQAkq0B1k47h4atnSXyaAuRheP9HBCbAZxxtRVSpUoVox/Cb7/9ZlxkPGdcIDlXKjSo0NklOp+EFuAAEqXCw/vxn37dF92hYR+PFln6pIkDoz+AM64CC23YpAO5tKfB5s2bY306iBINKvLy8mJ9GgBgqcLD1+P+uBtg2TI0bM0sk0FFbAZwxlVgoapVq2aMCWc7JDXoyhQrFQASrcLj1vObyguLCwLO9LB9aNixIyLLXxD59EHrz43iAM64CyyUboHQgREAEI8VHurFz80FFbY0wNL8iHdvFlk7M8h4MomLAZxxGVgAABCvFR7KzAj0Id1Olk4n1wuvAZZue8y6TeRYGEmfERzA6QuBBQAAEajcaHF8rfAaYZlO0PQju1HEB3D6QmABAEAEKjfqh/o6uvWx6JHwgoquI0W63kfnTQAAYu1PJ9WR3JrV5PcDoRcRpDlE9oTyfG1mNfc+kX3bQ35v6ThUpNsoiRUaRQAA4FEN0vXRz8IKKtw5GHe8udJ4PUtBhXbKDDWoqFFP5C9TRS55SGLJcmCxbds2ufHGG6Vu3bqSmZkpp59+uvznP/+JzNkBABDlElMzfSnMGjdnnVFlYmr7Q2d9WK76UA6RG2aI3POjSJsrJdYsbYXs2bNHOnXqJN26dZO5c+fKcccdJz/99JPUqVMncmcIAEAMS0xD5fSYDxI0iVM7Y3rP+jCr450iLS6SeGEpsJg4caI0btxYXnnllfL7mjZtGvA5xcXFxs2tqKgolPMEACCmJaa2VZkcOyKy4kWRPZtE6jQROeeWEDtjOlxBRYy3PsIKLGbPni09evSQa665RhYtWiSNGjWSwYMHyy233OL3Ofn5+TJu3Dg7zhUAgIiwdThYoOoQLSH98mkRZ6nHfX8XaW1xC6NJF5EbZ4hUqSbxxlKOxcaNG2XKlClGy+2PPvpIBg0aJEOHDpWpU6f6fc6oUaOksLCw/LZ161Y7zhsAANuEWhqaVb1Kectub46y2SLl80HcfSk8gwql36+dIVKtpkcD8AAJmtdMFRn4flwGFZZXLEpLS+Xss8+W8eNdI1rPOussWbNmjTz33HMyYMAAn8/JyMgwbgAAxCu9+GsQoLNArORZXPOnE+SVLzYZ4YAz0HyQY0dcKxWBHDlY9irer1bmgvtFzr8nJr0pIrZioZNHW7duXeG+U089VbZs2WL3eQEAEDV68dcgQFlpvn1x6zyZcmM7Yx6Ip7yc6sb95fNBNKfCe6WiEqfIGTeIZDeo3EGz7+siF4yI+6DC8oqFVoT88MMPFe778ccf5aSTTrL7vAAAiGpVSE5mNflbpyYyc9U2+f3AUdNj0DUo0QBDE0B37jtsbKtUmg+iiZpmZNQUGbbGVSWiCZ06lVQHiCVAQBFSYHH33XdLx44dja2Qvn37yvLly+WFF14wbgAAJGr/Ci019awK0c6bZzbOkQXf/xZ8m6NsxaO8pLS0RGTzkoqBgVZ/mKHHaRDRtIskKofT6bRUtvv+++8bCZnav0JLTYcPHx6wKsSblpvm5OQYiZzZ2dmhnDMAALY2xfK+ELqDh1vPbyqzv91eIehoEGgM+rrZrkZXnj0pdGz5Jf8QefemwNshjnSRB3bEbVKm2eu35cAiWicGAECktz86T1zgt3+Fe7tj0b3d5OvNe/xvc7hXKRY/JrJwvJ9XEpGWl4r88GHgGR9x1pMilOs3Q8gAACkpWFMsd+dMDSr8ds50BxTLnhU5vDfAKzlEtn8r0mGI61jPlQtdqehwR1wHFVYQWAAAUpLZplh+j9NtjzlDRQ7tMfEqTpGibSKn9BS5aEzlzptxuv0RCgILAEBKMtsUq9JxAbc9gtCETg0idIUiSRFYAABSkpmmWHVrVpM/nVSn4irF3PtCH21e63hJdpbHpgMAkCpNsXYfOCLdHpkvyxfMEpk3SmR6vxCDCoer0ZWWniY5AgsAQMrSklFfnTPdLk37SmYX/03OXTzAlXQZ1ptNSKhGV6FiKwQAIKkeXBw75pQ7p31TYUtkZPqbcluV98Vhpce3L7pSoUFF6yskFRBYAAAk1ZtkDZn2Tfn3VeSY5Fd5Uf6S/nn4L35BYgwOsxOBBQAgpZtkaTtvlSalMqnK03J5+jLx7n9lWWauSO/JKbNK4YnAAgAgqd4kq2faMvln1SmS6Qg8fCyozDoi5w1KuVUKTwQWAICUpc2vbMulSMFtD18ILAAAKavV7gVyRZX3w3uRFEvODIbAAgCQmkpL5JSvx4S+UqFbHq16uXpTpPgqhScCCwBAatq8VBwHd4f23DifRBpLBBYAgNSkczusqlFP5LLHRdpcGYkzSgoEFgCA1GR1bsdpV4lc/RLbHkEQWAAAkqovhZaQarWHTiXVQWM6E8QnzY3IbihS9EuQV3WIdLyTrQ+TCCwAAEnTQVObXWlfCjedXqqDxrRtdyW68tBzosj0/iL+5ps26SJy4wzXqHOYwhAyAEBSBBWD3lgpvxYelPZp6+SKtKXG152FB4379XGftES072uulQvvXIprpooMfJ+gwiJWLAAASdGW+5K05TKm6mvS0PF7+WO/OHPlwaP9Zdyc6nJx6zzf2yIaXGjZ6OalroROzb2ghDRkBBYAgISmORVt9y2WKVUnVXosT36XZ6tOkkH79LgzpUPzur5fRIOIpl0if7IpgK0QAEBC21l0wFipUN4LEu7vx1R93TgOkUdgAQBIaCcfXG1sf/gr/tD7Gzp2G8ch8ggsAAAJ7dSsg7Yeh/AQWAAAElpaVp6txyE8BBYAgMRW1ujKqY2sfDDu1wmkehwijsACAJDYyhpdaVjhHVzo98Y9Otac8tGoILAAACS+skZXjuyKHTYd2vhKG2Dp44gK+lgAAJIDja7iAoEFACB+lJaEFxjQ6CrmCCwAAPFh3WyReSMqThvVrQwdFMZWRsIgxwIAEB9BhU4Z9R5hXrTddb8+joRAYAEAiP32h65U+BxdXnbfvJGu4xD3CCwAALGlORXeKxUVOEWKtrmOQ9wjsAAAxJYmatp5HGKKwAIAEFta/WHncYgpqkIAADEtIS1p3EF2SV05zrnb54TSUqfITkddOa5xB6EjRfwjsAAAxLSEdPnmQnn1SD+ZUnWSEUR4Bhf6vRpzpJ8M3FwoHZrXjfZPAIvYCgEAxLSEdOe+w/JR6bky6Ogw2SG5FQ7dIXWN+/VxPQ7xjxULAEAMSkgdrhLSVr2kflZ1414NHj4pPlvOTfte6ste2Sm1ZXlpKykt+x3YfRziG4EFACCmJaTnNu0sDXKqy47Cw0YQsay0dYUjdWckL6e6nNu04moG4hNbIQCAmJaQpqc5ZExvVzDhnbvp/l4f1+MQ/wgsAAAxLyHt2aaBTLmxnbEy4Um/1/v1cSQGtkIAAPbTklKt/tBETZ95Fg7X43pcGQ0eLm6dJ8sLfjcSNTWnQrc/WKlILAQWAAD7aZ8KLSnV6g9jQ8MzuCgLFHpOqDQSXYMISkoTG1shAIDI0D4VfV8TZ3bFbQynrlT0fY1R6EmKFQsAQMTMKz1HHjo8WRof+ba8hHTr4TNkdOnp0jPWJ4eIILAAAETEvDXbZdAbK41NkG3yRwmpo+iocT9JmcmJrRAAgO1KSp0ybs46v+2xlD6uxyGFA4uxY8eKw+GocGvVqlXkzg4AkJC0smN7of8W3BpO6ON6HFJ8K+S0006T+fPn//ECVdhNAYBUmURqltm5Hsz/SD6WowINJPLy8kwfX1xcbNzcioqKrL4lACBOJpGaZXauB/M/ko/lHIuffvpJGjZsKM2aNZMbbrhBtmzZEvD4/Px8ycnJKb81btw4nPMFAMRwEqlZ2thK53/4a22l9+vjzP9IPg6n02k6c2bu3Lmyf/9+admypWzfvl3GjRsn27ZtkzVr1khWVpbpFQsNLgoLCyU7O9uenwIAEPrWx6YlIm/3Fzm0189BZV0yh622tC3irgoR3+2xqApJMHr91gWCYNdvS4GFt71798pJJ50kTzzxhNx00022nhgAIMIBxeLHRL56NkBA4WXA+yJNu1h6Gw0utPrDM5FTVyp0qBhBRWIxe/0OK/Oydu3acsopp8j69evDeRkAQDStnSUye4hI8b7ITCz1wPyP1BNWYKHbIhs2bJB+/frZd0YAgMj5eLTI0icjO7HUC/M/Uoul5M177rlHFi1aJJs2bZKlS5fKn//8Z0lPT5frrrsucmcIALDHmlkhBhWaY9GowiRSwJYVi59//tkIInbv3i3HHXecdO7cWZYtW2b8GQAQ5zkVHw4P4Yn+J5ECYQcW06ZNs3I4ACBeaNOrg7stP00nkTo0qGASKUyibSYAJNvKRMHnIpuXuGo8tYqjSWdLiZc6vqNQasngo0Nly+GzmEQKSwgsACBZaBOrOUNFDu35477PHxXJzBU573ZTL+FuQDDy6M3yZWkbJpHCMqabAkAyrFIsnCgyvV/FoMLt0O8iC8eLZNYJ+lJ7pJYMOjpMPio91/ieSaSwihULAEj0VYoP7xXZv8PEwY6AKxWzS9rL3ceGSKnX75yek0gpG0UwrFgAQELP9+hnMqgoW7m44H45lFlxkOQuZ7YMOjpU7jo2tFJQ4YlJpDCDFQsASNTtD82nsOjbg7ly1Z7H5Jy076W+7JWdUluWl7YKGFC4MYkUZhBYAEAi0soPX/kUQTz/zUEpkTRZVtra9HN0AyWPSaQwia0QAEhEWk5qUXGNBjJvXzNLz3FnZejQMOZ7wAwCCwBIRCEUaHzbZqSpLQ9PulJBqSmsILAAgERkZXy59rHo+7qUtOxt6S1G9zpVloy4kKAClpBjAQCJSLtpasCglR7+pFcXuW6aSLPzjTkf55Y6pUFOdaN01Ix6WRlsf8AyViwAIB5bcq9+x/VVv/dFB4L1nhz4ta5+UeTkbuXDwzRIuOIM86sPVIEgFKxYAEA89aWYN0Kk6Jc/7stuKNJzou8hYHpf39crPUeTNDWfoiSjk7FK4V51mLdmu7ywuCDoaVAFgnA4nE53Z/joKCoqkpycHCksLJTs7OxovjUAxHmzq/4+sjLLtiL6vuZ/wqiuamxeKt9+971RTqqVH+4kTd360IqOi1vnSeeJC4Jug7g3PkjYRKjXb7ZCACDWNDDQVQefpR5l980b6XdbRPtSTN6QJ30WN5QP951cofJDA4nb31gpTy9Ybyq3IrdmNYIKhIWtEACItc1LK25/VOIUKdrmOs6rGkS3N8bOXis7iooDvsXzizeYOpW/9zqVoAJhIbAAgFjb/2tIx2lQoSPNzexnHzziJwnUS15OprlzAfxgKwQAYq3W8ZaP0xHmOsrcSpKcI8hjmo9BwibCRWABALF2UkdX9YffS79DJLuR67gyOsLcbD8KN3cQ4v0utO2GnQgsACDWtM+ElpQGuuz3nFDejyKcEeY3dWpilJJ6om037ESOBQBEglZwbFoiUrBIZO/PIrVPEGlyviv50iNAqNiT4jU/fSwmVCo1DbV5VffWeXJ/r9bGiocGJ/o6uv3BSgXsQmABAHZbO0tk9hCR4n0V7//8cZHMOiK9n/Tf8KpVL1f1hyZqak6Fbn/4CET+dFId0Vig1GSShWfTKw0iOjSvG+pPBwREYAEAdvp4tMjSJ/0/fmiPyPR+ro6ZvoILDSJMDBj7evMeS0GFIocC0UCOBQDYZc2swEGFp7kj/M8BMcFKjgU5FIgmViwAwA4aJHw43Pzx+37x2fBKy0jN5D+YzbHQ0ecDOzVlpQJRQ2ABAKEqm9Fh5EPo7eBua8/30fBKe1N4lpG6Z314rzZowKGP7Sg87LOXhTungqAC0UZgAQB2TSK1yqPhlb8umho46P3eWxkaLGjAoY9p2OD5PHIqEEvkWABAqJNIwwkqshqWN7wK1EXTfZ8+rsd50kBDAw76UiCesGIBALZNIrXg0onlZaTBumjqO+njepx3magGDzoSnb4UiBcEFgBg6yTSIDJzRXpPrlBqarbCw99x9KVAPCGwAIBITCL1VCVT5OSLRc65yWfnTbMVHqF22wSiicACAIJVfHh2wDQ7ibTHeCmtWV++21dD1tc4Xepn1/S7RWG2woPJo0gEBBYAYKbiw5jZMdHVclv/XLTdT56FTiJtKPNq9ZFx7/9QljuxOmDpKBUeSCYOp9MZZgaSNUVFRZKTkyOFhYWSnZ0dzbcGAJMVH/38P66tuJVWhRgqhwHfdJgsV31Wr1LY4Q4L/FVsWOljAUSb2es3gQUAeG5/PHqyyKHfAydf3rte5PsPfKxqNJKSHvnSeXYtv1Ue7m2NJSMu9LkCYbbzJhBtZq/fbIUAgJuOOQ8UVCh9XI/zM4l0ecFe2V64LKTSUUWFBxIdgQUAuBV8bv64Zl19TiKdv26H7UPEgERCYAEgNfmq+jC74+DnOM2R+NcXm0y9BKWjSFYEFgBSj7+qj7PcCZlBnNS50l3uttzBUDqKZEdgASA153x412xo+eiiCSLVaokc2R84edNr+8NMW243fVdKR5HMGEIGIHUEnPOh9zlE0qsFfg1tx+3VOdNKzsTfOjWhdBRJjcACQOoIOufD6ar6uOB+kawGlaeRag8LjxkfoeRM6MAwIJmxFQIgdZIzzc75qNtc5O61vlt6+0FbbsCFwAJA6iRnthto7vkaSPgoJQ0kUFtuKfv+f85pbPr1gETFVgiA5FqlWDjR1ZLbe8tDkzMX5otk1vFfL2rM+WjkWp0IgeZOaLtuXZnw5Z/zf5LOExcYZalAsiKwAJA8qxT/PE1k4Xg/B7jXENzrCd7BRdn3PScE3PIwE1xou+67u5/i83HdKtFVDYILJCsCCwCJvUKxcZHI//V3rVLsC3ax9kjOzPZKztStkr6v+U3OtGraii3+zsCgPS+09wWQbMixAJC4KxSzh4oc3mP9uZqcOWyNpeRMK4L1tAg2LwRI2RWLCRMmiMPhkGHDhtl3RgAQzNpZrhWKUIIK7+TM0//i+mpTUGGlpwXzQpCMQl6xWLFihTz//PPStm1be88IAAJZM0vkHZPVHT6TMxuGnJxpltmeFswLQTIKacVi//79csMNN8iLL74odepohjUARGn7450BfjpnmhRmcqYnzZH4csNueW/VNuOrO2diz4EjEqhjtz6kPS/oaYFkFNKKxR133CG9evWS7t27y8MPPxzw2OLiYuPmVlRUFMpbAkh15e24Q6RlpBpUmEzO1CBBcyB0u0JXFjQI8JzvoVUdmoDpmUuhwcIVZzSQFxYXBA19mBeCZGU5sJg2bZqsXLnS2AoxIz8/X8aNGxfKuQFIdZ7dM/UWsB13AFoFcv49plcqNGgYO3ut7Cj645eivOwMGXvFaUY5qT6uJaPewYMGGc8vLgj42hpLPH3dWcwLQdKyFFhs3bpV7rrrLvnkk0+kenVze4OjRo2S4cOHV1ixaNyY7nMAQuieGeFVCqVBw+1vrKx0vwYZev+z158lD33wXcibMbpbUqdmRojPBpIssPj6669l586d0q5du/L7SkpKZPHixfL0008bWx7p6RV/I8jIyDBuABD2aHMruo4U6XqfpXwK3f4YOWN1wGPuffe/cqC4JPTzohoESc5SYHHRRRfJ6tUV/0/317/+VVq1aiUjRoyoFFQAgOVtD21yNW9keEFFx6Ei3UZZftqyDbtl78GjAY8JN6hQVIMgmVkKLLKysqRNmzYV7qtZs6bUrVu30v0AENVtD5WRJXLF0yKnXRnS07/cuEsiiQmnSAV03gSQ+NseOljsvEGWEjR9M1elUSsj3Vi5CHTG3hNO3a9MNQiSXdiBxcKFC+05EwCpt/VR8LnInKGhBRU9xrs6aNrYjlvbaz/92fqgx93cuZlM/vQnv8HDrec3ldnfbq9QiqorFRpUUA2CZMeKBYAE2/oo65553u22tuFW7ZvVldo1qgbMs6hTo6rceVELadUgq1IfC8/g4b6epwbsgwEkKwILAAm09WHPaHN/9MI/4arTfZabuuVfdbpxnAYPF7fO8xs86FcGjCEVEVgAiN7Wx6YlInPuDD2fQlcqLPalsEoDhudubCdjZ6+THUUVu2p6b2UQPACVEVgAiOOtD4dIjboiPfNFshrYOto8kGCrEQD8I7AAEKdbH2UX8cv/GdEVCn9YjQBCQ2ABIAqDw5xR3/YINkQMQGQQWACIHO2kaXX7Q3tSXDNVpEnnkLc9/E0epdwTiLy0KLwHgFSlE0lN09UEh0jvJ0WadQ0rqNDJo55BhdpReNi4Xx8HEDkEFgAiR5tXWdn66PtaWPkUuv2hKxW+Nl7c9+njehyAyGArBEDkaBWHBgxFukrg52KemSvyl1dEmnYJu+Jj2cbdlVYqPOkZ6OOae0FiJhAZrFgAiBwNFHpOLPvG4WfrY7JI8wvCDip0i+OOf/tvbOWJseVA5BBYAIgs3drQLY7sBrZvfXjnVew9FHjkuZtWieh2yJcbdst7q7YZX9keAezBVgiAyNPgoVUvV5WIJnTaODgsUF6Fv7Hlew4US+eJC6gaASKAwAJAdGgQoXkUNtKg4uUlBQHzKrxdcUYDuePNbyoFIu6qkSk3tiO4AMLAVgiAhKTbH+0e+lj+8eF3po7XqaXPXN/OGGdO1QgQOaxYAIhb/rpnalARaAKpL89c107S0hxUjQARRmABIC6DCM2DeOiD7yrlQYzudarcP3ON6dd151W0b15X3v+vuS6gVI0AoSOwABBzvlpw+6J5EIPf/Mby62tSpq50aMBihtnjAFRGYAEgptylomayGqxmPmhexYSrTi9PxtStFF310ADFGWB1Q48DEBqSNwHEjJVS0VBoXoVnhYeuWujqhb92XZ6rGwBCQ2ABpPJI84LPRVa/4/qq30eZ5lRYKRW1ok6NqkZehTcNNLSkVFcmPOn3lJoC4WMrBEhF62aLzBtRcaS5dsLU9ts2dMI0K5JJkv+4so3flQcNHi5uneez4gRAeAgsgFQMKqb3r5yxoIPC9H6b2mxHMklSL/+Btk9uO7+pXNa2YcDX0CCCklLAfgQWQCrQbQ5tp71vu8i8UX4uy3qfQ2TeSFf7bRvabQcTLJnSH3/H1sqoIo9c3VYua8t2BhAr5FgAyW7NLJHHWohMvVxkxi0iB3cFONgpUrTNFYREQaBkSl+C7VTUykiXHm3y7Dk5ACFhxQJIZh+PFln6pPXn6aCwKHEnU3r3sXA1w2otdWpWM/Igdu1zNcwKZEdRMV0zgRgjsACS1dpZoQUVSqePRpGZZEodb24GXTOB2CKwAJI1p+KD/xfCEx2u6hAdaR5lwZIp6ZoJJAZyLIBkpDkSAXMpfClbHeg5ISqJm6EmevpLs9D79XG6ZgKxRWABJGOjq1ByJHSlIoqlplbRNRNIDGyFAMnY6KrdQHPPz8gW6fW4SFYD1/ZHBFcqvKeX/umkOvL15j2WGlT5S/TUrpkaVNA1E4g9h9PpjFSbfp+KiookJydHCgsLJTs7O5pvDaRGoyt3+6jMXJFDvwd+jb9MFWlzpcRieqnGEKUep97AQnDgHaTQNROIn+s3KxZAom59zBkauNFVsB6VHYdGLajwNb3UM6hQ2iRLjzMzr4OumUD8IscCSLRVikltRF7vI3JoT4ADna7VigtGubZGPNWoJ3LNVJFLHoqr6aXuY/R4fR6AxMSKBZDwWx8B1G0uMmyNq0pEEzq1P0WEcynCmV6qP5keT5MrIHERWACJsv2hSZqWJmqUNbrSIKJpF4mFUJtV0eQKSFwEFkAi0BUHz8qPOG50ZUezKppcAYmLHAsgEVjqSxE/ja6CNbXyRpMrIPERWACJwMrsjjhqdGVleilNroDkQGABJALd0jCqOwJccDPriPSfLTJsdVwEFd5NrbSJlSfv2EEfN1NqCiC+kWMBJALd0ug5sawqxLs3RdkVuveTIs26SjzyNb00lM6bAOIfnTeBhG/h3ciVTxFHqxQAkg+dN4F4Lh0Nta+EBg+tesWsLwUABENgAcTD0DDd5jC74hDDvhQAEAzJm0C0O2d696Mo2u66Xx8HgARHYAHEvHNm2X3zRrqOA4AExlYIEI18ioJFQTpnOkWKtrmOtXmbgxHjAKKJwAKIZj6FrR02zY0s12mhnoPAtLOlNqGiXwSASGArBLB7haLgc5F5o0Sm97M438Nih00TQcWgN1ZWmi66o/Cwcb8+DgAxDSymTJkibdu2NepX9dahQweZO3eu7ScFJOwKxaQ2IlMvF1n2rMUn69CwRrYNDdPtD12pCJDRYTyuxwFAzLZCTjjhBJkwYYK0aNFCtK/W1KlTpU+fPvLNN9/IaaedZuuJAQm1SrH4MZGF40N8AfuHhmlOhfdKhScNJ/TxV78okHpZGeReAIifzpu5ubny6KOPyk033WTqeDpvIulWKebeJ7IvjG2FCHTOfG/VNrlr2ipLzyH3AkBMO2+WlJTI22+/LQcOHDC2RPwpLi42bp4nBiRVXwqfGw4mdLnXNdsjAp0zdQXCKnfuBYPAAEQ1eXP16tVSq1YtycjIkNtvv11mzpwprVu7xiL7kp+fb0Q47lvjxo3DOmEgLrY+Ni4SmXNniEFFWT5Ft1Gu0tIItOPWbQ1dgbCysUHuBYCYBBYtW7aUVatWyVdffSWDBg2SAQMGyLp16/weP2rUKGPZxH3bunVruOcMxD5B87UrRA7tjYt8Cl80V0K3NTze0RR37oXmaABATHIsunfvLs2bN5fnn3/e1PHkWCBltz5iMInUVx8LMyb/z5nS58xGETsvAIknatNNS0tLK+RQAKnXktuE9oNFWl5mSz6FlU6amitxceu88uN37SuWhz74LiI5GgBgObDQbY1LL71UTjzxRNm3b5+8+eabsnDhQvnoo4/4NJHctNW21WZXEVihCKWTpgYdHZrXLQ9KXlpSYCRq+gqRNDzJy3EFKwAQ8cBi586d0r9/f9m+fbuxHKLNsjSouPjii0N6cyDuZ3xoi23thhlKOekF94ucf49tuRTuTprOMKo53LkXerwGEZ6v5V7z0MfpZwEgZjkWVpFjgbh27IjInGEi62aKHD34x/016ooc3B2zPApdaeg8cYHfXAn3SsOSEReaCgqYIQIgbnMsgKTx8WiRpU/5zqMwE1Rk5or85ZWIlJCa7aSpx7m3PQLxzr2g8yYAuxBYILXplsemJSILHhL5eYXJJ/nZROg9WaT5BZE4S+PiH85x/hI+zQQhAGAFgQVSu3x0zlCRQ3usPc/YFtn1x/fZDSNeQmq2SsPXcWx7AIgmAgukcE+Kfsa6g+XF/575IlkN/kjstFhCaqVc1LuTptVqDjsSPgHACgILpOb2x5yhoQUVSoMKzaMIIYjYc+CIPPSB9dWDQNUcUvb9ZW1cORPuQCXY6HR9HX1ccy3IrQBgF6pCkHp0zoe25A6FVnwMW+13hcIzkNi064C8tXyL7CgK3EDOfUk3s3rga1tDYwLP0R7uQCUns5pc9+KyoD/SW7e0J9cCQFBUhQD++lL89HHorxNgxkeo7bOtrB54VnN8sm6HvPzFpgpBhec2x187NbE1MRQAzCCwQPIHFIsfE/nq2RCHhpWpVkvkyil+EzT95TKYZaVcVAMP3e4YPn2V39fS0OS9VeY6hdK+G4CdCCyQ3AHF0skiRw6E/DLGRfq0q0Sufing9oe/XAarzK4emOlrsfvAEcmtWVX2HDhK+24A8Ts2HYh7a2aJTDhRZOH4gEGFv0BAs470NsdxgZTev1PkmlcCVn0Eu8hbYXb1wGwA8ueyCaXemyu07wYQKQQWSL7ume8MEDmyP+ihgS6nzx+7XKpe/ZykV8uISo6Coyzp0uzqgdkApHvrPCMpVFcmPOn3lJoCiAS2QpA81s4SWfpkWC+xy5klj1e5TbpcfbNRVfHeqm1Be02Em6MQyuqBlb4W+pq07wYQLQQWSJ6cig/+X0hPLblkvGw4WEN2OmtLepNO0uXQMUu9JoJd5IPJC6ELptUppbTvBhAt9LFAcij4XGTq5WH3pfBX3RGo14Qmbz69YL38c/6PQd9OA5DRvU6VOjUzbFk9oF03gGihjwVSi/anCLMvRSidKoP1rtCL/P+cc6I0qVcjIlsQTCkFEG8ILJAcdGaHFTrivPdkKWnVW5Zv2G1clHftKzY1mnzZht2SluaQ+et2yL++2OT3+Lu7t5AhF7aI+EWebQ4A8YTAAslBB4HplNGiIE2hqtYU6XSXyPn3yLx1O2XcxAWWS0XveHOl7D10NOAxGkpMW7HVCCwAIJVQborkoNsZPScGLiLVRlejtopcMMIIKjSXIpT+E8GCCu9OmgCQSggskDy03Xbf11wrF55q1BO5Zmp5oys7O2UGwxwOAKmGrRAkxuAwzaHQ7Y4AHTDLg4tWvQI+z85OmcEwhwNAqiGwQOIMDtOVCN3u8DMIrJwGEU27+B1n/tOvwbtyhos5HABSFYEF4su62eKcc5c4DvnITSjaLjK9v2u7I1hwYcM481AxhwNAKiOwQHwFFRo4+B8P5rpszxvp2u4IMG3UvTpR8Nt+mfTpeltOr2ZGuhwsLgmamxFKJ00ASBYEFogPpSVyaM69Ut3pFEfAX/KdIkXbXDkUXtsdkV6duKVzM5n86U8+W2jr93/r1MRoVkWDKgCpjMAiDnn+xp3UnRQ9kjNL9v0qmYd2BB45GqTTpr923HaoU6Oq3HlRC2nVIKtS4MIKBQD8gcAizqTM7Id1s0XmjShvaBWk1iNop81Il5DmX3W6EdzRQhsAAiOwiCP+fuPWqZl6v68BWAkbVATMpfDPyLLQwWFaQuohUiWkvoI6WmgDgH8EFnEilAFYCdmPouZxInPv8xtU6KxdfzkWxhxeR8XBYZFqRFU7s6o8c0M7ad+sbuJ93gAQQwQWcSLYb9yeLaIT6rdlrfSYO0Ic+4LM8CgTKHFzr6OWZF/zrKT7KDW1qxGV++0nXH26dDq5ni2vCQCphJbeccLsb9wJ1SLaKB/tJ2IyqPBnj7OWPH70L/LV1V9J+ml9fB6jeQ66bWGWLkLc0qVJpedoImbSbDkBQAywYhEnzP7GnRAtonXro+BzOfbubZIeYGsjkAeP3ii7nLVlp9SWrbXOkNHXnB7wYq/bFaN7tZbBb6409fpPX9dOLmvbQEZe2ppETACwEYFFnHD/xq2Jms5EbhHtUe1h/OWyeI0udYrskLpyQo9hckZ2DUsX+zo1q5l6j7u7n2IEFYpETACwF1shcUIvcFp9oBxx1CJak0q/3LBb3lu1zfiq3wet9igrIbXK/dLjjvaTutk1pM+ZjYyLvtmf2ew2UZN6NUI6PwBAcKxYxBFd6tf9fTMNmOxuouXr9T5Zt8N8Tw3d/tCVijA6SehKhQYVH5WeKwND2PJJqu0kAEhQBBZRphfwZRt3G7/960W4Q7N60t7jt3IzDZjsbqLl6/Vq16gqew8erXSs354aWk4awkrFQ0evl9+cuUYuxfLSVuKUNONn0Z/ZavCUNNtJAJDAHE6n0R0gaoqKiiQnJ0cKCwslOztbUolewEfOWF3pgq0X8QlXBU5ODNZEy325tVrREEobbPcFesmIC/+40K9+R+Tdm0y/hv6t2yO15Ozi56S0bEfO82dQoQRP7p/HeA+vc3a/NhUfABC56zc5FlGiF7zb31jpcxVA79PH9JhAOQ3BmmjpbezstYHzIGxog+3ZU8Nfi+2Az3e6XuPhtNvLgwrPUk+lwYF3Xw/3aol+TsG2k/S1PFFGCgDRwVZIFOgFfOzsdUGPG/Huf43jdhT5/i3dTNvqHUXF8vSC9XJX9xbl763P09f8fX+x5NasJnk5mcZ2QLhtsCskS2qL7eyGIkV60Q8cqvzqyJXtHcbKoxf3l2u8tjpU54kLwupAyjwPAIgdAosocF/Ygyk8dMy4+ctpKD5Waur9/jn/R2mZV8v4s78R4hqwXNYmT8JRIQlSW2z3nGhUhTjFIQ6P0MD9pw3N+0txs57S6rweklfF9VfPu9RTV2ns6EBKGSkAxAaBRRSE0y3T87f0x645w/TzNJej8OBRv2sHenH+1xebgr5OmpTKuWnfS33ZWyHB0mcSZOsr5JsOk6Xhl+PkeNHkVJdfpa5s7zBGzuoxIDU7kAJACiGwiIJwyxvdv6XrH3Slwcz2ha9cDl90d8Cd8+CtR9pyGVP1NWno+COX4hdnrjx4tL9c2fv2SlsLRuLkZ/XEIZMrBCMrSltJ6WdpMqXR9qA5DpSMAkBiI3kzCvQ3+7zs8C+Euw4UlzfRsovmebpXRTz1TFsuU6pOkjyPoELp91OqTZaeaSv8JoJqQuay0tYyu7Sj8bWk7K+ZPh4ssdRdMuovG0Lvd5ejAgDiT0oGFpa6SdpAf7Mfe0X4AYH+lq5JiTUzKo4MD9ffOjUxtjZ026N92jrpk7ZExld72Zjx4f0XRL83LvrzRrqaYlmczvrqFwUBP+947UAKADAn5bZC7G4uZZa+9nM3tvPdxyKzihwpccrBI39cqL1prwt3JceBYv/HhUKDlV7pX0nT5WMkV4pMPMMpUrTN1RSraRdLOQ8PffCdvLSkIODnbaUDKQAgvqRUYOGvGZTfbpI2c5dBenfePKdprpz54McBn3u0rCLE7qRFDarqL3tYmv3oWqGwZP+vIeU8mPm8KRkFgMSUMoFFsOZSZvoj2EFfu9PJ9Yyb2xc/7Qq4WqEOHCmRZRt225q0qD/l02dskWbLXw7tBTyaYgVrpx3K503JKAAknpTJsTCbA1Chm2SUfLlxl+njgiU3mqWvMeWGM6Tttw8ar2VttcIhkt3I1RTLRG5EvH3eAIDISZnAIr77I5i9qjsqXMBDlVuzqiy6t5v0rFUgVYt/D+1ce05wNcUy0U47EPpRAEBySZnAIlb9EcxUoJhd7ncf576Aa4Bglrvi44q0pXLKoW/l64JdFXIkTNO23X1fM5ph+aLnpsPJRvc61dTL0Y8CAFI4xyI/P19mzJgh33//vWRmZkrHjh1l4sSJ0rJlS4l30Rqp7Tnqe9Oug/LW8i1+Z3+4aYdM3YoINGe2To2q0r7ZHwGIPv/CVsdL+/xP5fcDRwKek69GV4fefVGkvblppEVSQ2r9eZKkaVCh2x9eKxXedFVlYKemRvUHI8wBILVYWrFYtGiR3HHHHbJs2TL55JNP5OjRo3LJJZfIgQMHJN7Z0R8h2OqDVp3oAK3rXlwmd01bZczs8J4R4j2hU7/e8ebKgEGFyr/q9ErnVq1Kmoz/cxtXjoSfVYqh6e/Kc1UnSQOpuOVR/fBOkYXjRTJz/SZbGh05nSIb2o+XtDOudZWWBgkq3OhHAQCpyeF0Bruk+ffbb79J/fr1jYDj/PPPt3Wee7z1sQj2PH+lrBLgt3XNc+j66GcBk0r1uvv0dWfJZW0bWjo3XaXIr/qi5DoCBX0Okcw6Iof2iNMYHVaR/iwFp9wkza5/wsRPFV99QwAA9jJ7/Q6r3FRfXOXm+l/OLi4uNm6eJxZLofRHCNb/4pnr28lDH/guZQ1UEfH6l5uCzv3QRZE6NTMs/Uzp38+Ry76bZCIl1Cly6HeRC+4Xx8pXRYp+KX/kSEZdSe/9uDRr82eTP5W5c6MfBQAkt5ADi9LSUhk2bJh06tRJ2rRpEzAvY9y4cRJPrPRHMNP/YvR7a2R3kDwHXzb/ftC2yol0KZUOaetE0raLbJ4oTof5WhOp21xk2BpXJ01N6Kx1vFQzkUthFv0oACB1hBxYaK7FmjVrZMmSJQGPGzVqlAwfPrzCikXjxo3FTp4Jk3b/Rmym/0UoQYU6KbeGPZUT62aLzBtRYcXBYbXRlQYRZe25AQCIamAxZMgQef/992Xx4sVywgknBDw2IyPDuEVKpPfwI9FnwZ1j0a9Dk/AqJ3QI2KJHRBZNCP1kvBpdAQAQtaoQzfPUoGLmzJmyYMECadq0qcSSO/fBe0XBu/IiHGb7LGhPCSurBBr4aFVHyJUTa2eJTDgxvKDCT6MrAACiEljo9scbb7whb775pmRlZcmOHTuM26FDhyTaguU+KH083JHowVpo6/36+MN9XHkmwYILjRFuPb9p+WqKv26V+r3fIV0fjxZ5e4DIkf2h/VDGiaaL/GWq30ZXAABEvNzU4WegxCuvvCIDBw6Marmp9pHQfhHBvHVL+6CJg8FyNNwrI8rzw3If4Q4AfG3LePN+jtlzKLdmlsg7AyRs10wVOe3K8F8HAJASiiJRbhpGy4u4nf1hJkfDvargfVyej+OMsegbdhtNr/YeOmp6sqepygnNqfjwj0TYkGTmivSezEoFACAiqqTy7I9g/Sk8VxXM9mPQ79PSHD6DCl+TPS2VYWo56MHdYklmXZGz/+oKZ7Tqo0lncioAABGTsIFFuLM/zPSnCGlVIZKTVEMZGtZ7EqsTAICoSdjppuHOojDTn8K9qhDV1RTd7ti4SOTTh0UWPCyyYaHrPne/CbNIzgQAxEDCrlhYyX2I6qpCOKsp2uhqzlBjdscfHnXN8+j9pEirXq6x5R6NsPz6y8skZwIAoi6hA4twZlHYkaMRbDVF8zQcfipJKq2mBKr20EBjej+Rvq+L9JwoMr2/16t6qFZL5MoprFQAAGIiYbdCPLlzH/qc2cj4aqadt9n+FH67XgZhqT+FNrt6x0S57twRrlWLvq+5Vi48VcsSOX+kyMgtBBUAgJhJ+BWLUIW0qhCJ1RTd/tBmV2bs+8VVGaKBgwYYHkPDjLbcVHsAAGIsZQOLcHM0zApYSaJJmTo8LJTKEIaGAQDiUEoHFuHkaIRMg4lNS0QKPhcp3GIuEdOTlcoQAACiLOUDCyv9KcJmVH3cJXLIeglreR4Fk0gBAHGMwCLSdIVCcyF++FBk2bPhvdYVT5JHAQCIawQWkV6hmHufyL7wx7dLy8tE2lxlx1kBABAxBBaRDCq094QdOtwp0uNhe14LAIAIIrCIxNaHJmbOuj2816lWU6R1H5HLJ4tUqWbX2QEAEFEEFnavUmj5qNVKD09d7hVp1pW+FACAhERgYevWR4BW22ZkNRTpNoqAAgCQsJKipXfMlTe6CiOoUJdOJKgAACQ0Ags7aDlpONsfmbmuAWPM+AAAJDi2QuzgbrNtRZVMkQ6DRZqc72rNzUoFACAJEFjYIZQ221e9wAoFACDpEFiE0kXTe6KoftUx5kXbg+dZZDcS6TmBoAIAkJQILMIpJdVgoudEV5CgX42qEO8h7GXaD3Z1z6SMFACQxEjetFJK6p2gqSsUer8+rsFF39dEshtUXqHQxMye+eRSAACSHisWYZWS6n0OkXkjRVr1cgUX+tXXdgkAACmAwCLsUlKnSNE213HuFQn9CgBACmIrxK5S0lBKTgEASDKsWASq9rBSShpKySkAAEmGwCJYtUfQUlKH63E9DgCAFJeW0qPN540Smd4vcLWHrlxokGHQUlJPZd9rXwoSNAEASMHAQoOFSW1Epl4usuxZPweVrUxotYcGIX5LSRu67qfZFQAAKbgVYmm0uVe1B6WkAAAElTqBRaijzT2rPSglBQAgoNTZCgl1tDnVHgAAmJY6KxaW+0xQ7QEAgFWps2JhaeWBag8AAEKROoGFux9FpZJRH6j2AAAghbdCAnXOdHP3o2C0OQAAEVMl6TtnenL3o6h0fCPXtgcrFAAAhMXhdDot1l+Gp6ioSHJycqSwsFCys7Mj1JeibLvD33aGmRUOAABg+fpdJTn7Uuh9DlfnTG1q5WtbhH4UAADYLi15+1J4dM4EAABRkZb0fSks968AAACpF1iY7UtB50wAAKImLXn7UmjnzEZ0zgQAIIoSN7Bw96UweAcXdM4EACAWEjew8OxLkd2g4v10zgQAICYSt9zUTYMHLSmlLwUAADGX+IGFoi8FAABxIbG3QgAAQGIHFosXL5bevXtLw4YNxeFwyKxZsyJzZgAAIPkDiwMHDsgZZ5whzzzzTGTOCAAApE6OxaWXXmrcAAAAop68WVxcbNw8p6MBAIDkFPHkzfz8fGPMqvvWuHHjSL8lAABI1sBi1KhRxux2923r1q2RfksAAJCsWyEZGRnGDQAAJD/6WAAAgNitWOzfv1/Wr19f/n1BQYGsWrVKcnNz5cQTTwz6fKfTaXwliRMAgMThvm67r+N+OS367LPP9BUr3QYMGGDq+Vu3bvX5fG7cuHHjxo2bxP1Nr+OBOPR/JIpKS0vll19+kaysLKNzZziRk1aYaDJodna2recI3/jMo4/PPPr4zKOPzzwxPnMNF/bt22d03k5LS4ufIWR6MieccIJtr6cfCH8Ro4vPPPr4zKOPzzz6+Mzj/zPXthHBkLwJAABsQ2ABAABsk7CBhfbGGDNmDD0yoojPPPr4zKOPzzz6+MyT6zOPevImAABIXgm7YgEAAOIPgQUAALANgQUAALANgQUAALANgQUAAEiNwOKZZ56RJk2aSPXq1eW8886T5cuXBzz+7bffllatWhnHn3766fLhhx9G7VyThZXP/MUXX5QuXbpInTp1jFv37t2D/jdC+H/P3aZNm2a0xb/yyisjfo6p/pnv3btX7rjjDmnQoIFRnnfKKafw70sEP+9JkyZJy5YtJTMz02g7fffdd8vhw4ejdr6JbvHixdK7d2+j9bb+GzFr1qygz1m4cKG0a9fO+Pt98skny6uvvhr6CTjj1LRp05zVqlVzvvzyy861a9c6b7nlFmft2rWdv/76q8/jv/jiC2d6errzkUceca5bt87597//3Vm1alXn6tWro37uicrqZ3799dc7n3nmGec333zj/O6775wDBw505uTkOH/++eeon3uqfOZuBQUFzkaNGjm7dOni7NOnT9TONxU/8+LiYufZZ5/tvOyyy5xLliwxPvuFCxc6V61aFfVzT4XP+9///rczIyPD+Kqf9UcffeRs0KCB8+677476uSeqDz/80PnAAw84Z8yYYQwNmzlzZsDjN27c6KxRo4Zz+PDhxvXzqaeeMq6n8+bNC+n94zawOPfcc5133HFH+fclJSXOhg0bOvPz830e37dvX2evXr0q3Hfeeec5b7vttoifa7Kw+pl7O3bsmDMrK8s5derUCJ5lcgnlM9fPuWPHjs6XXnrJmCpMYBHZz3zKlCnOZs2aOY8cORLFs0zdz1uPvfDCCyvcpxe8Tp06Rfxck5GYCCzuu+8+52mnnVbhvmuvvdbZo0ePkN4zLrdCjhw5Il9//bWxtO45vEy///LLL30+R+/3PF716NHD7/EI/zP3dvDgQTl69Kjk5uZG8EyTR6if+YMPPij169eXm266KUpnmtqf+ezZs6VDhw7GVsjxxx8vbdq0kfHjx0tJSUkUzzx1Pu+OHTsaz3Fvl2zcuNHYdrrsssuidt6p5kubr59Rn25qxq5du4z/0+r/iT3p999//73P5+zYscPn8Xo/IvOZexsxYoSxp+f9FxT2feZLliyRf/3rX7Jq1aoonWVyCeUz1wvbggUL5IYbbjAucOvXr5fBgwcbQbS2RIa9n/f1119vPK9z587GmO5jx47J7bffLvfff3+Uzjr17PBz/dTR6ocOHTJyXayIyxULJJ4JEyYYyYQzZ840ErRgv3379km/fv2MpNl69erF+nRSRmlpqbFC9MILL8if/vQnufbaa+WBBx6Q5557LtanlpQ0iVBXhJ599llZuXKlzJgxQz744AN56KGHYn1qSOQVC/1HMz09XX799dcK9+v3eXl5Pp+j91s5HuF/5m6PPfaYEVjMnz9f2rZtG+EzTd3PfMOGDbJp0yYj29vzoqeqVKkiP/zwgzRv3jwKZ55af8+1EqRq1arG89xOPfVU47c8XeqvVq1axM87lT7v0aNHGwH0zTffbHyvFX4HDhyQW2+91QjodCsF9vJ3/czOzra8WqHi8r+Q/h9VfzP49NNPK/wDqt/rXqcver/n8eqTTz7xezzC/8zVI488YvwmMW/ePDn77LOjdLap+ZlrKfXq1auNbRD37YorrpBu3boZf9ayPNj/97xTp07G9oc7iFM//vijEXAQVNj/eWuulnfw4A7qmJkZGbZfP51xXKKkJUevvvqqUf5y6623GiVKO3bsMB7v16+fc+TIkRXKTatUqeJ87LHHjNLHMWPGUG4a4c98woQJRhnZO++849y+fXv5bd++fTH8KZL7M/dGVUjkP/MtW7YY1U5Dhgxx/vDDD87333/fWb9+fefDDz8cw58ieT9v/bdbP++33nrLKIP8+OOPnc2bNzcq/2CO/husbQD0ppf5J554wvjz5s2bjcf189bP3bvc9N577zWun9pGICnLTZXW0p544onGxUtLlpYtW1b+WNeuXY1/VD1Nnz7decoppxjHa+nMBx98EIOzTmxWPvOTTjrJ+EvrfdN/GBC5v+eeCCyi85kvXbrUKF/XC6SWnv7jH/8wyn5h/+d99OhR59ixY41gonr16s7GjRs7Bw8e7NyzZ0+Mzj7xfPbZZz7/bXZ/zvpVP3fv55x55pnGfyP9O/7KK6+E/P4O/R97FlMAAECqi8scCwAAkJgILAAAgG0ILAAAgG0ILAAAgG0ILAAAgG0ILAAAgG0ILAAAgG0ILAAAgG0ILAAAgG0ILAAAgG0ILAAAgNjl/wOB6vqgznVLNAAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "n = 100\n",
+ "x = np.random.rand(n, 1)\n",
+ "y = 2.0 + 5 * x**2 + 0.1 * np.random.randn(n, 1)\n",
+ "\n",
+ "line_model = LinearRegression().fit(x, y)\n",
+ "line_predict = line_model.predict(x)\n",
+ "#line_mse = ...\n",
+ "\n",
+ "#poly_features = ...\n",
+ "#poly_model = LinearRegression().fit(..., y)\n",
+ "#poly_predict = ...\n",
+ "#poly_mse = ...\n",
+ "\n",
+ "plt.scatter(x, y, label = \"Data\")\n",
+ "plt.scatter(x, line_predict, label = \"Line model\")\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "248d8931",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - The train-test split\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1efd3376",
+ "metadata": {},
+ "source": [
+ "Hopefully your model fit the data quite well, but to know how well the model actually generalizes to unseen data, which is most often what we care about, we need to split our data into training and testing data. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0f8d75fb",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "edb213fc",
+ "metadata": {},
+ "source": [
+ "**a)** Complete the code below so that the polynomial features and the targets y get split into training and test data.\n",
+ "\n",
+ "**b)** What is the shape of X_test?\n",
+ "\n",
+ "**c)** Fit your model to X_train\n",
+ "\n",
+ "**d)** Compute the MSE when your model predicts on the training data and on the testing data, using y_train and y_test as targets for the two cases.\n",
+ "\n",
+ "**e)** Why do we not fit the model to X_test?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a03e0388",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "polynomial_features = ...\n",
+ "\n",
+ "#X_train, X_test, y_train, y_test = train_test_split(polynomial_features, y, test_size=0.2)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "22e7536e",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/doc/LectureNotes/_build/jupyter_execute/exercisesweek35.ipynb b/doc/LectureNotes/_build/jupyter_execute/exercisesweek35.ipynb
new file mode 100644
index 000000000..6b559d91e
--- /dev/null
+++ b/doc/LectureNotes/_build/jupyter_execute/exercisesweek35.ipynb
@@ -0,0 +1,539 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b4005770",
+ "metadata": {},
+ "source": [
+ "# Exercises week 35\n",
+ "\n",
+ "## Deriving and Implementing Ordinary Least Squares"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2ca1b589",
+ "metadata": {},
+ "source": [
+ "This week you will be deriving the analytical expressions for linear regression, building up the model from scratch. This will include taking several derivatives of products of vectors and matrices. Such derivatives are central to the optimization of many machine learning models. Although we will often use automatic differentiation in actual calculations, to be able to have analytical expressions is extremely helpful in case we have simpler derivatives as well as when we analyze various properties (like second derivatives) of the chosen cost functions.\n",
+ "\n",
+ "Vectors are always written as boldfaced lower case letters and matrices as upper case boldfaced letters. You will find useful the notes from week 35 on derivatives of vectors and matrices. See also the textbook of Faisal at al, chapter 5 and in particular sections 5.3-5.5 at "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41e92bf9",
+ "metadata": {},
+ "source": [
+ "### Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "- Take the derivatives of simple products between vectors and matrices\n",
+ "- Implement OLS using the analytical expressions\n",
+ "- Create a feature matrix from a set of data\n",
+ "- Create a feature matrix for a polynomial model\n",
+ "- Evaluate the MSE score of various model on training and test data, and comparing their performance\n",
+ "\n",
+ "### Deliverables\n",
+ "\n",
+ "Complete the following exercises while working in a jupyter notebook. Then, in canvas, include\n",
+ "- The jupyter notebook with the exercises completed\n",
+ "- An exported PDF of the notebook (https://code.visualstudio.com/docs/datascience/jupyter-notebooks#_export-your-jupyter-notebook)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f7a9209d",
+ "metadata": {},
+ "source": [
+ "## How to take derivatives of Matrix-Vector expressions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "45f3712e",
+ "metadata": {},
+ "source": [
+ "In these exercises it is always useful to write out with summation indices the various quantities. Take also a look at the weekly slides from week 35 and the various examples included there.\n",
+ "\n",
+ "As an example, consider the function\n",
+ "\n",
+ "$$\n",
+ "f(\\boldsymbol{x}) =\\boldsymbol{A}\\boldsymbol{x},\n",
+ "$$\n",
+ "\n",
+ "which reads for a specific component $f_i$ (we define the matrix $\\boldsymbol{A}$ to have dimension $n\\times n$ and the vector $\\boldsymbol{x}$ to have length $n$)\n",
+ "\n",
+ "$$\n",
+ "f_i =\\sum_{j=0}^{n-1}a_{ij}x_j,\n",
+ "$$\n",
+ "\n",
+ "which leads to\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial f_i}{\\partial x_j}= a_{ij},\n",
+ "$$\n",
+ "\n",
+ "and written out in terms of the vector $\\boldsymbol{x}$ we have\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial f(\\boldsymbol{x})}{\\partial \\boldsymbol{x}}= \\boldsymbol{A}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5fa8a4e6",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Finding the derivative of Matrix-Vector expressions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "df7a2270",
+ "metadata": {},
+ "source": [
+ "**a)** Consider the expression\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial (\\boldsymbol{a}^T\\boldsymbol{x})}{\\partial \\boldsymbol{x}},\n",
+ "$$\n",
+ "\n",
+ "Where $\\boldsymbol{a}$ and $\\boldsymbol{x}$ are column-vectors with length $n$.\n",
+ "\n",
+ "What is the *shape* of the expression we are taking the derivative of?\n",
+ "\n",
+ "What is the *shape* of the thing we are taking the derivative with respect to?\n",
+ "\n",
+ "What is the *shape* of the result of the expression?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c0396734",
+ "metadata": {},
+ "source": [
+ "**b)** Show that\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial (\\boldsymbol{a}^T\\boldsymbol{x})}{\\partial \\boldsymbol{x}} = \\boldsymbol{a}^T,\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dc39d541",
+ "metadata": {},
+ "source": [
+ "**c)** Show that\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial (\\boldsymbol{a}^T\\boldsymbol{A}\\boldsymbol{a})}{\\partial \\boldsymbol{a}} = \\boldsymbol{a}^T(\\boldsymbol{A}+\\boldsymbol{A}^T),\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "498d13ec",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Deriving the expression for OLS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f3f771de",
+ "metadata": {},
+ "source": [
+ "The ordinary least squares method finds the parameters $\\boldsymbol{\\theta}$ which minimizes the squared error between our model $\\boldsymbol{X\\theta}$ and the true values $\\boldsymbol{y}$.\n",
+ "\n",
+ "To find the parameters $\\boldsymbol{\\theta}$ which minimizes this error, we take the derivative of the squared error expression with respect to $\\boldsymbol{\\theta}$, and set it equal to 0."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "49690237",
+ "metadata": {},
+ "source": [
+ "**a)** Very briefly explain why the approach above finds the parameters $\\boldsymbol{\\theta}$ which minimizes this error."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b7cccc9d",
+ "metadata": {},
+ "source": [
+ "We typically write the squared error as\n",
+ "\n",
+ "$$\n",
+ "\\vert\\vert\\boldsymbol{y} - \\boldsymbol{X\\theta}\\vert\\vert^2\n",
+ "$$\n",
+ "\n",
+ "which we can rewrite in matrix-vector form as\n",
+ "\n",
+ "$$\n",
+ "\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\theta}\\right)^T\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\theta}\\right)\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8fbecf74",
+ "metadata": {},
+ "source": [
+ "**b)** If $\\boldsymbol{X}$ is invertible, what is the expression for the optimal parameters $\\boldsymbol{\\theta}$? (**Hint:** Don't compute any derivatives, but solve $\\boldsymbol{X\\theta}=\\boldsymbol{y}$ for $\\boldsymbol{\\theta}$)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f37af8f0",
+ "metadata": {},
+ "source": [
+ "**c)** Show that\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial \\left(\\boldsymbol{x}-\\boldsymbol{A}\\boldsymbol{s}\\right)^T\\left(\\boldsymbol{x}-\\boldsymbol{A}\\boldsymbol{s}\\right)}{\\partial \\boldsymbol{s}} = -2\\left(\\boldsymbol{x}-\\boldsymbol{A}\\boldsymbol{s}\\right)^T\\boldsymbol{A},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "869fca4d",
+ "metadata": {},
+ "source": [
+ "**d)** Using the expression from **c)**, but substituting back in $\\boldsymbol{\\theta}$, $\\boldsymbol{y}$ and $\\boldsymbol{X}$, find the expression for the optimal parameters $\\boldsymbol{\\theta}$ in the case that $\\boldsymbol{X}$ is not invertible, but $\\boldsymbol{X^T X}$ is, which is most often the case.\n",
+ "\n",
+ "$$\n",
+ "\\boldsymbol{\\hat{\\theta}_{OLS}} = ...\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "57ca3d74",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Creating feature matrix and implementing OLS using the analytical expression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5dc179f7",
+ "metadata": {},
+ "source": [
+ "With the expression for $\\boldsymbol{\\hat{\\theta}_{OLS}}$, you now have what you need to implement OLS regression with your input data and target data $\\boldsymbol{y}$. But before you can do that, you need to set up you input data as a feature matrix $\\boldsymbol{X}$.\n",
+ "\n",
+ "In a feature matrix, each row is a datapoint and each column is a feature of that data. If you want to predict someones spending based on their income and number of children, for instance, you would create a row for each person in your dataset, with the montly income and the number of children as columns.\n",
+ "\n",
+ "We typically also include an intercept in our models. The intercept is a value that is added to our prediction regardless of the value of the other features. The intercept tries to account for constant effects in our data that are not dependant on anything else. In our current example, the intercept could account for living expenses which are typical regardless of income or childcare expenses.\n",
+ "\n",
+ "We calculate the optimal intercept by including a feature with the constant value of 1 in our model, which is then multplied by some parameter $\\theta_0$ from the OLS method into the optimal intercept value (which will be $\\theta_0$). In practice, we include the intercept in our model by adding a column of ones to the start of our feature matrix."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "e5ff2a69",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a3cf2792",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 20\n",
+ "income = np.array([116., 161., 167., 118., 172., 163., 179., 173., 162., 116., 101., 176., 178., 172., 143., 135., 160., 101., 149., 125.])\n",
+ "children = np.array([5, 3, 0, 4, 5, 3, 0, 4, 4, 3, 3, 5, 1, 0, 2, 3, 2, 1, 5, 4])\n",
+ "spending = np.array([152., 141., 102., 136., 161., 129., 99., 159., 160., 107., 98., 164., 121., 93., 112., 127., 117., 69., 156., 131.])\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5da61481",
+ "metadata": {},
+ "source": [
+ "**a)** Create a feature matrix $\\boldsymbol{X}$ for the features income and children, including an intercept column of ones at the start."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "5ad87a65",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X = np.zeros((n, 3))\n",
+ "#X[:, 0] = ...\n",
+ "#X[:, 1] = ...\n",
+ "#X[:, 2] = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e0ddfac2",
+ "metadata": {},
+ "source": [
+ "**b)** Use the expression from **3d)** to find the optimal parameters $\\boldsymbol{\\hat{\\beta}_{OLS}}$ for predicting spending based on these features. Create a function for this operation, as you are going to need to use it a lot."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "8f3f68aa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def OLS_parameters(X, y):\n",
+ " return ...\n",
+ "\n",
+ "#beta = OLS_parameters(X, y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0cb6da80",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Fitting a polynomial"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "71015064",
+ "metadata": {},
+ "source": [
+ "In this course, we typically do linear regression using polynomials, though in real world applications it is also very common to make linear models based on measured features like you did in the previous exercise.\n",
+ "\n",
+ "When fitting a polynomial with linear regression, we make each polynomial degree($x, x^2, x^3, ..., x^p$) its own feature."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "d7476c84",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 100\n",
+ "x = np.linspace(-3, 3, n)\n",
+ "y = np.exp(-x**2) + 1.5 * np.exp(-(x-2)**2) + np.random.normal(0, 0.1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8321451b",
+ "metadata": {},
+ "source": [
+ "**a)** Create a feature matrix $\\boldsymbol{X}$ for the features $x, x^2, x^3, x^4, x^5$, including an intercept column of ones at the start. Make this into a function, as you will do this a lot over the next weeks."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "91496e40",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p + 1))\n",
+ " #X[:, 0] = ...\n",
+ " #X[:, 1] = ...\n",
+ " #X[:, 2] = ...\n",
+ " # could this be a loop?\n",
+ "\n",
+ "#X = polynomial_features(x, 5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b84b1e31",
+ "metadata": {},
+ "source": [
+ "**b)** Use the expression from **3d)** to find the optimal parameters $\\boldsymbol{\\hat{\\beta}_{OLS}}$ for predicting $\\boldsymbol{y}$ based on these features. If you have done everything right so far, this code will not need changing."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "034f502c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#beta = OLS_parameters(X, y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d703f788",
+ "metadata": {},
+ "source": [
+ "**c)** Like in exercise 4 last week, split your feature matrix and target data into a training split and test split."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "29171358",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "#X_train, X_test, y_train, y_test = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a0e3509f",
+ "metadata": {},
+ "source": [
+ "**d)** Train your model on the training data(find the parameters which best fit) and compute the MSE on both the training and test data."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "1e346f4c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Ellipsis"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7e431889",
+ "metadata": {},
+ "source": [
+ "**e)** Do the same for each polynomial degree from 2 to 10, and plot the MSE on both the training and test data as a function of polynomial degree. The aim is to reproduce Figure 2.11 of [Hastie et al](https://github.com/CompPhysics/MLErasmus/blob/master/doc/Textbooks/elementsstat.pdf). Feel free to read the discussions leading to figure 2.11 of Hastie et al. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "ceb57457",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Ellipsis"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e5b5954",
+ "metadata": {},
+ "source": [
+ "**f)** Interpret the graph. Why do the lines move as they do? What does it tell us about model performance and generalizability?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ad2acfb9",
+ "metadata": {},
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5994f0c5",
+ "metadata": {},
+ "source": [
+ "## Exercise 5 - Comparing your code with sklearn"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8f595b7a",
+ "metadata": {},
+ "source": [
+ "When implementing different algorithms for the first time, it can be helpful to double check your results with established implementations before you go on to add more complexity."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8ab310c1",
+ "metadata": {},
+ "source": [
+ "**a)** Make sure your `polynomial_features` function creates the same feature matrix as sklearns PolynomialFeatures.\n",
+ "\n",
+ "(https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "85b964d1",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "id": "73c32c52",
+ "metadata": {},
+ "source": [
+ "**b)** Make sure your `OLS_parameters` function computes the same parameters as sklearns LinearRegression with fit_intercept set to False, since the intercept is included in the feature matrix. Use `your_model_object.coef_` to extract the computed parameters.\n",
+ "\n",
+ "(https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "35b04126",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/doc/LectureNotes/_build/jupyter_execute/exercisesweek36.ipynb b/doc/LectureNotes/_build/jupyter_execute/exercisesweek36.ipynb
new file mode 100644
index 000000000..843407984
--- /dev/null
+++ b/doc/LectureNotes/_build/jupyter_execute/exercisesweek36.ipynb
@@ -0,0 +1,383 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "9dd8f8d0",
+ "metadata": {},
+ "source": [
+ "# Weekly Exercises 3\n",
+ "\n",
+ "## Deriving and Implementing Ridge Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e5cc5739",
+ "metadata": {},
+ "source": [
+ "## Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "- Take more derivatives of simple products between vectors and matrices\n",
+ "- Implement Ridge regression using the analytical expressions\n",
+ "- Scale data appropriately for linear regression\n",
+ "- Evaluate a model across two different hyperparameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "427d9b9d",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Choice of model and degrees of freedom"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff6ebdb5",
+ "metadata": {},
+ "source": [
+ "**a)** How many degrees of freedom does an OLS model fit to the features $x, x^2, x^3$ and the intercept have?\n",
+ "\n",
+ "**b)** Why is it bad for a model to have too many degrees of freedom?\n",
+ "\n",
+ "**c)** Why is it bad for a model to have too few degrees of freedom?\n",
+ "\n",
+ "**d)** Read [chapter 3.4.1 of Hastie et al.'s book](https://link.springer.com/book/10.1007/978-0-387-84858-7). What is the expression for the effective degrees of freedom of the ridge regression fit?\n",
+ "\n",
+ "**e)** Why might we want to use Ridge regression instead of OLS?\n",
+ "\n",
+ "**f)** Why migth we want to use OLS instead of Ridge regression?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a78b2ce2",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Deriving the expression for Ridge Regression\n",
+ "\n",
+ "The aim here is to derive the expression for the optimal parameters using Ridge regression.\n",
+ "\n",
+ "The expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, was given by the optimization problem"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "93a7ad16",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "{\\displaystyle \\min_{\\boldsymbol{\\beta}\\in {\\mathbb{R}}^{p}}}\\frac{1}{n}\\left\\{\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\right)^T\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\right)\\right\\}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6b182c01",
+ "metadata": {},
+ "source": [
+ "By minimizing the above equation with respect to the parameters $\\boldsymbol{\\beta}$ we could then obtain an analytical expression for the parameters $\\boldsymbol{\\hat\\beta_{OLS}}$.\n",
+ "\n",
+ "We can add a regularization parameter $\\lambda$ by\n",
+ "defining a new cost function to be optimized, that is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb065daf",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "{\\displaystyle \\min_{\\boldsymbol{\\beta}\\in\n",
+ "{\\mathbb{R}}^{p}}}\\frac{1}{n}\\vert\\vert \\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\vert\\vert_2^2+\\lambda\\vert\\vert \\boldsymbol{\\beta}\\vert\\vert_2^2\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "89ae11e8",
+ "metadata": {},
+ "source": [
+ "which leads to the Ridge regression minimization problem. (One can require as part of the optimization problem that $\\vert\\vert \\boldsymbol{\\beta}\\vert\\vert_2^2\\le t$, where $t$ is a finite number larger than zero. We will not implement that in this course.)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "456d58d4",
+ "metadata": {},
+ "source": [
+ "### a) Expression for Ridge regression\n",
+ "\n",
+ "Show that the optimal parameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a5677efd",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{Ridge}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}+\\lambda\\boldsymbol{I}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7b08048",
+ "metadata": {},
+ "source": [
+ "with $\\boldsymbol{I}$ being a $p\\times p$ identity matrix.\n",
+ "\n",
+ "The ordinary least squares result is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bb0e6af",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{OLS}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2faaae78",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Scaling data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "8ed79466",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.preprocessing import StandardScaler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "59d6f347",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 100\n",
+ "x = np.linspace(-3, 3, n)\n",
+ "y = np.exp(-x**2) + 1.5 * np.exp(-(x-2)**2) + np.random.normal(0, 0.1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9fc9fe0",
+ "metadata": {},
+ "source": [
+ "**a)** Adapt your function from last week to only include the intercept column if the boolean argument `intercept` is set to true."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "5aa9c86d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p, intercept=False):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p + 1))\n",
+ " #X[:, 0] = ...\n",
+ " #X[:, 1] = ...\n",
+ " #X[:, 2] = ...\n",
+ " # could this be a loop?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "id": "2ebf249a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p, intercept=False):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p))\n",
+ " X[:, 0] = x[:]\n",
+ " X[:, 1] = x**2\n",
+ " X[:, 2] = x**3\n",
+ " return X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5924634",
+ "metadata": {},
+ "source": [
+ "**b)** Split your data into training and test data(80/20 split)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "id": "676541e7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X = polynomial_features(x, 3)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "id": "f895606f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\n",
+ "x_train = X_train[:, 0] # These are used for plotting\n",
+ "x_test = X_test[:, 0] # These are used for plotting"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a58f05ad",
+ "metadata": {},
+ "source": [
+ "**c)** Scale your design matrix with the sklearn standard scaler, though based on the mean and standard deviation of the training data only."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "id": "0c07995a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "scaler = StandardScaler()\n",
+ "scaler.fit(X_train)\n",
+ "X_train_s = scaler.transform(X_train)\n",
+ "X_test_s = scaler.transform(X_test)\n",
+ "y_offset = np.mean(y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63b86003",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Implementing Ridge Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a2f52ef2",
+ "metadata": {},
+ "source": [
+ "**a)** Implement a function for computing the optimal Ridge parameters using the expression from **2a)**."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "id": "69f19bde",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def Ridge_parameters(X, y):\n",
+ " # Assumes X is scaled and has no intercept column\n",
+ " return np.linalg.inv(X.T @ X) @ X.T @ y\n",
+ "\n",
+ "beta = Ridge_parameters(X_train_s, y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "626c81ba",
+ "metadata": {},
+ "source": [
+ "**b)** Fit a model to the data, and plot the prediction using both the training and test x-values extracted before scaling, and the y_offset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "id": "f9ba0655",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 82,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plt.plot(x, y)\n",
+ "plt.scatter(x_train, X_train_s @ beta + y_offset)\n",
+ "plt.scatter(x_test, X_test_s @ beta + y_offset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2993cfae",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Testing multiple hyperparameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e6cdc89a",
+ "metadata": {},
+ "source": [
+ "**a)** Compute the MSE of your ridge model for polynomials of degrees 1 to 5 with lambda set to 0.01. Plot the MSE as a function of polynomial degree.\n",
+ "\n",
+ "**b)** Compute the MSE of your ridge model for a polynomial with degree 3, and with lambdas from $10^{-1}$ to $10^{-5}$ on a logarithmic scale. Plot the MSE as a function of lambda.\n",
+ "\n",
+ "**c)** Compute the MSE of your ridge model for polynomials of degrees 1 to 5, and with lambdas from $10^{-1}$ to $10^{-5}$ on a logarithmic scale. Plot the MSE as a function of polynomial degree and lambda using a [heatmap](https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/doc/LectureNotes/_toc.yml b/doc/LectureNotes/_toc.yml
index ad41afbdd..88cafbfde 100644
--- a/doc/LectureNotes/_toc.yml
+++ b/doc/LectureNotes/_toc.yml
@@ -41,7 +41,8 @@ parts:
- caption: Weekly material, notes and exercises
numbered: false
chapters:
- - file: E1.ipynb
+ - file: exercisesweek34.ipynb
- file: week34.ipynb
- - file: E2.ipynb
- - file: week35.ipynb
\ No newline at end of file
+ - file: exercisesweek35.ipynb
+ - file: week35.ipynb
+ - file: exercisesweek36.ipynb
\ No newline at end of file
diff --git a/doc/LectureNotes/exercisesweek36.ipynb b/doc/LectureNotes/exercisesweek36.ipynb
new file mode 100644
index 000000000..e3365bb50
--- /dev/null
+++ b/doc/LectureNotes/exercisesweek36.ipynb
@@ -0,0 +1,383 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "9dd8f8d0",
+ "metadata": {},
+ "source": [
+ "# Weekly Exercises 3\n",
+ "\n",
+ "## Deriving and Implementing Ridge Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e5cc5739",
+ "metadata": {},
+ "source": [
+ "## Learning goals\n",
+ "\n",
+ "After completing these exercises, you will know how to\n",
+ "- Take more derivatives of simple products between vectors and matrices\n",
+ "- Implement Ridge regression using the analytical expressions\n",
+ "- Scale data appropriately for linear regression\n",
+ "- Evaluate a model across two different hyperparameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "427d9b9d",
+ "metadata": {},
+ "source": [
+ "## Exercise 1 - Choice of model and degrees of freedom"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff6ebdb5",
+ "metadata": {},
+ "source": [
+ "**a)** How many degrees of freedom does an OLS model fit to the features $x, x^2, x^3$ and the intercept have?\n",
+ "\n",
+ "**b)** Why is it bad for a model to have too many degrees of freedom?\n",
+ "\n",
+ "**c)** Why is it bad for a model to have too few degrees of freedom?\n",
+ "\n",
+ "**d)** Read [chapter 3.4.1 of Hastie et al.'s book](https://link.springer.com/book/10.1007/978-0-387-84858-7). What is the expression for the effective degrees of freedom of the ridge regression fit?\n",
+ "\n",
+ "**e)** Why might we want to use Ridge regression instead of OLS?\n",
+ "\n",
+ "**f)** Why migth we want to use OLS instead of Ridge regression?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a78b2ce2",
+ "metadata": {},
+ "source": [
+ "## Exercise 2 - Deriving the expression for Ridge Regression\n",
+ "\n",
+ "The aim here is to derive the expression for the optimal parameters using Ridge regression.\n",
+ "\n",
+ "The expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, was given by the optimization problem"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "93a7ad16",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "{\\displaystyle \\min_{\\boldsymbol{\\beta}\\in {\\mathbb{R}}^{p}}}\\frac{1}{n}\\left\\{\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\right)^T\\left(\\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\right)\\right\\}.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6b182c01",
+ "metadata": {},
+ "source": [
+ "By minimizing the above equation with respect to the parameters $\\boldsymbol{\\beta}$ we could then obtain an analytical expression for the parameters $\\boldsymbol{\\hat\\beta_{OLS}}$.\n",
+ "\n",
+ "We can add a regularization parameter $\\lambda$ by\n",
+ "defining a new cost function to be optimized, that is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fb065daf",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "{\\displaystyle \\min_{\\boldsymbol{\\beta}\\in\n",
+ "{\\mathbb{R}}^{p}}}\\frac{1}{n}\\vert\\vert \\boldsymbol{y}-\\boldsymbol{X}\\boldsymbol{\\beta}\\vert\\vert_2^2+\\lambda\\vert\\vert \\boldsymbol{\\beta}\\vert\\vert_2^2\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "89ae11e8",
+ "metadata": {},
+ "source": [
+ "which leads to the Ridge regression minimization problem. (One can require as part of the optimization problem that $\\vert\\vert \\boldsymbol{\\beta}\\vert\\vert_2^2\\le t$, where $t$ is a finite number larger than zero. We will not implement that in this course.)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "456d58d4",
+ "metadata": {},
+ "source": [
+ "### a) Expression for Ridge regression\n",
+ "\n",
+ "Show that the optimal parameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a5677efd",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{Ridge}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}+\\lambda\\boldsymbol{I}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e7b08048",
+ "metadata": {},
+ "source": [
+ "with $\\boldsymbol{I}$ being a $p\\times p$ identity matrix.\n",
+ "\n",
+ "The ordinary least squares result is"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bb0e6af",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "\\hat{\\boldsymbol{\\beta}}_{\\mathrm{OLS}} = \\left(\\boldsymbol{X}^T\\boldsymbol{X}\\right)^{-1}\\boldsymbol{X}^T\\boldsymbol{y},\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2faaae78",
+ "metadata": {},
+ "source": [
+ "## Exercise 3 - Scaling data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "8ed79466",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn.preprocessing import StandardScaler"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "id": "59d6f347",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n = 100\n",
+ "x = np.linspace(-3, 3, n)\n",
+ "y = np.exp(-x**2) + 1.5 * np.exp(-(x-2)**2) + np.random.normal(0, 0.1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c9fc9fe0",
+ "metadata": {},
+ "source": [
+ "**a)** Adapt your function from last week to only include the intercept column if the boolean argument `intercept` is set to true."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "id": "5aa9c86d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p, intercept=False):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p + 1))\n",
+ " #X[:, 0] = ...\n",
+ " #X[:, 1] = ...\n",
+ " #X[:, 2] = ...\n",
+ " # could this be a loop?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "id": "2ebf249a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def polynomial_features(x, p, intercept=False):\n",
+ " n = len(x)\n",
+ " X = np.zeros((n, p))\n",
+ " X[:, 0] = x[:]\n",
+ " X[:, 1] = x**2\n",
+ " X[:, 2] = x**3\n",
+ " return X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c5924634",
+ "metadata": {},
+ "source": [
+ "**b)** Split your data into training and test data(80/20 split)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "id": "676541e7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X = polynomial_features(x, 3)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "id": "f895606f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)\n",
+ "x_train = X_train[:, 0] # These are used for plotting\n",
+ "x_test = X_test[:, 0] # These are used for plotting"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a58f05ad",
+ "metadata": {},
+ "source": [
+ "**c)** Scale your design matrix with the sklearn standard scaler, though based on the mean and standard deviation of the training data only."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "id": "0c07995a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "scaler = StandardScaler()\n",
+ "scaler.fit(X_train)\n",
+ "X_train_s = scaler.transform(X_train)\n",
+ "X_test_s = scaler.transform(X_test)\n",
+ "y_offset = np.mean(y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63b86003",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Implementing Ridge Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a2f52ef2",
+ "metadata": {},
+ "source": [
+ "**a)** Implement a function for computing the optimal Ridge parameters using the expression from **2a)**."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "id": "69f19bde",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def Ridge_parameters(X, y):\n",
+ " # Assumes X is scaled and has no intercept column\n",
+ " return np.linalg.inv(X.T @ X) @ X.T @ y\n",
+ "\n",
+ "beta = Ridge_parameters(X_train_s, y_train)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "626c81ba",
+ "metadata": {},
+ "source": [
+ "**b)** Fit a model to the data, and plot the prediction using both the training and test x-values extracted before scaling, and the y_offset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "id": "f9ba0655",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 82,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plt.plot(x, y)\n",
+ "plt.scatter(x_train, X_train_s @ beta + y_offset)\n",
+ "plt.scatter(x_test, X_test_s @ beta + y_offset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2993cfae",
+ "metadata": {},
+ "source": [
+ "## Exercise 4 - Testing multiple hyperparameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e6cdc89a",
+ "metadata": {},
+ "source": [
+ "**a)** Compute the MSE of your ridge model for polynomials of degrees 1 to 5 with lambda set to 0.01. Plot the MSE as a function of polynomial degree.\n",
+ "\n",
+ "**b)** Compute the MSE of your ridge model for a polynomial with degree 3, and with lambdas from $10^{-1}$ to $10^{-5}$ on a logarithmic scale. Plot the MSE as a function of lambda.\n",
+ "\n",
+ "**c)** Compute the MSE of your ridge model for polynomials of degrees 1 to 5, and with lambdas from $10^{-1}$ to $10^{-5}$ on a logarithmic scale. Plot the MSE as a function of polynomial degree and lambda using a [heatmap](https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}