From 46e8b9e1749976cad863c36a7a1e0448d82b3b06 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Mon, 4 Oct 2021 13:55:07 +0200 Subject: [PATCH] Rework the introduction on numpy - expand section on indexing and slicing in Chapter 1 on arrays - add section on dimensionality and shapes of arrays - streamline text in Chapter 1 - include thumbnails in links to scientific libraries - add explanation on slicing to core Python introduction and adjust the list example - streamline some text and titles in Chapter 0 --- .../02_content_logic.ipynb | 260 +++- .../05_content_functions.ipynb | 8 +- 01_scientific_stack/00_content.ipynb | 674 -------- 01_scientific_stack/00_content_numpy.ipynb | 1354 +++++++++++++++++ static/link/to_np.png | Bin 0 -> 1306 bytes static/link/to_pd.png | Bin 0 -> 862 bytes static/link/to_plt.png | Bin 0 -> 1148 bytes static/link/to_skl.png | Bin 0 -> 837 bytes 8 files changed, 1576 insertions(+), 720 deletions(-) delete mode 100644 01_scientific_stack/00_content.ipynb create mode 100644 01_scientific_stack/00_content_numpy.ipynb create mode 100644 static/link/to_np.png create mode 100644 static/link/to_pd.png create mode 100644 static/link/to_plt.png create mode 100644 static/link/to_skl.png diff --git a/00_python_in_a_nutshell/02_content_logic.ipynb b/00_python_in_a_nutshell/02_content_logic.ipynb index 43a5c5f..c40c754 100644 --- a/00_python_in_a_nutshell/02_content_logic.ipynb +++ b/00_python_in_a_nutshell/02_content_logic.ipynb @@ -36,7 +36,7 @@ "\n", "The syntax to create a `list` are brackets, `[` and `]`, another example of delimiters, listing the individual **elements** of the `list` in between them, separated by commas.\n", "\n", - "For example, the next code snippet creates a `list` named `numbers` with the numbers `1`, `2`, `3`, and `4` in it." + "For example, the next code snippet creates a `list` named `numbers` with the numbers `1`, `2`, `3`, `4`, and `5` in it." ] }, { @@ -47,7 +47,7 @@ { "data": { "text/plain": [ - "[1, 2, 3, 4]" + "[1, 2, 3, 4, 5]" ] }, "execution_count": 1, @@ -56,7 +56,7 @@ } ], "source": [ - "numbers = [1, 2, 3, 4]\n", + "numbers = [1, 2, 3, 4, 5]\n", "\n", "numbers" ] @@ -65,7 +65,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Whenever we use any kind of delimiter, we may break the lines in between them as we wish and add other so-called **whitespace** characters like spaces to format the way the code looks like. So, the following two code cells do *exactly* the same as the previous one, even the `,` after the `4` in the second cell is ignored." + "Whenever we use any kind of delimiter, we may break the lines in between them as we wish and add other so-called **whitespace** characters like spaces to format the way the code looks like. So, the following two code cells do *exactly* the same as the previous one, even the `,` after the `5` in the second cell is ignored." ] }, { @@ -76,7 +76,7 @@ { "data": { "text/plain": [ - "[1, 2, 3, 4]" + "[1, 2, 3, 4, 5]" ] }, "execution_count": 2, @@ -86,7 +86,7 @@ ], "source": [ "numbers = [\n", - " 1, 2, 3, 4\n", + " 1, 2, 3, 4, 5\n", "]\n", "\n", "numbers" @@ -100,7 +100,7 @@ { "data": { "text/plain": [ - "[1, 2, 3, 4]" + "[1, 2, 3, 4, 5]" ] }, "execution_count": 3, @@ -114,6 +114,7 @@ " 2,\n", " 3,\n", " 4,\n", + " 5,\n", "]\n", "\n", "numbers" @@ -135,6 +136,13 @@ "num" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Indexing & Slicing" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -183,7 +191,7 @@ { "data": { "text/plain": [ - "4" + "5" ] }, "execution_count": 5, @@ -210,7 +218,7 @@ "metadata": {}, "outputs": [], "source": [ - "numbers[0] = 4" + "numbers[0] = 5" ] }, { @@ -219,7 +227,7 @@ "metadata": {}, "outputs": [], "source": [ - "numbers[3] = 1" + "numbers[4] = 1" ] }, { @@ -230,7 +238,7 @@ { "data": { "text/plain": [ - "[4, 2, 3, 1]" + "[5, 2, 3, 4, 1]" ] }, "execution_count": 8, @@ -255,7 +263,7 @@ "metadata": {}, "outputs": [], "source": [ - "numbers[0], numbers[3] = numbers[3], numbers[0]" + "numbers[0], numbers[4] = numbers[4], numbers[0]" ] }, { @@ -266,7 +274,7 @@ { "data": { "text/plain": [ - "[1, 2, 3, 4]" + "[1, 2, 3, 4, 5]" ] }, "execution_count": 10, @@ -278,6 +286,174 @@ "numbers" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a generalization, we may also **slice** out some elements in the `list`. That is done with the `[...]` notation as well. Yet, instead of a single integer index, we now provide a *start* and a *stop* index separated by a `:`. While the element corresponding to the *start* index is included, this is not the case for *stop*.\n", + "\n", + "For example, to slice out the middle three elements, we write the following." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 4]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers[1:4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We may combine positive and negative indexes.\n", + "\n", + "So, the following yields the same result." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 4]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers[1:-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While ommitting the *start* index makes a slice begin at the first element, ..." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers[:-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "... leaving out the *stop* index makes a slice go to the last element." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 4, 5]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers[1:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Providing a third integer as the *step* value after another `:` makes a slice skip some elements.\n", + "\n", + "For example, `[1:-1:2]` means \"go from the second element (including) to the last element (excluding) and take every second element\" ..." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 4]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers[1:-1:2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "... while `[::2]` simply downsamples the `list` by taking every other element." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 3, 5]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers[::2]" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -333,21 +509,21 @@ "\n", "Many beginners struggle with the term \"loop.\" To visualize the looping behavior of this code, we use the online tool [PythonTutor ](http://pythontutor.com/visualize.html#code=numbers%20%3D%20%5B1,%202,%203,%204%5D%0A%0Atotal%20%3D%200%0A%0Afor%20number%20in%20numbers%3A%0A%20%20%20%20total%20%3D%20total%20%2B%20number%0A%0Atotal&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false). That tool is helpful for two reasons:\n", "1. It allows us to execute code in \"slow motion\" (i.e., by clicking the \"next\" button on the left side, only the next atomic step of the code snippet is executed).\n", - "2. It shows what happens inside the computer's memory on the right-hand side (cf., the \"*Thinking like a Computer*\" section further below)." + "2. It shows what happens inside the computer's memory on the right-hand side." ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "10" + "15" ] }, - "execution_count": 11, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -370,16 +546,16 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "10" + "15" ] }, - "execution_count": 12, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -395,16 +571,16 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "10" + "15" ] }, - "execution_count": 13, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -434,7 +610,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -443,7 +619,7 @@ "1" ] }, - "execution_count": 14, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -454,7 +630,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -463,7 +639,7 @@ "0" ] }, - "execution_count": 15, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -481,7 +657,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -490,7 +666,7 @@ "False" ] }, - "execution_count": 16, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -501,7 +677,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -510,7 +686,7 @@ "True" ] }, - "execution_count": 17, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -544,7 +720,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -553,7 +729,7 @@ "6" ] }, - "execution_count": 18, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -579,21 +755,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "`if` statements may have more than one header line: For example, the code in the `else`-clause's body is only executed if the condition in the `if`-clause is `False`. In the code cell below, we calculate the sum of all even numbers and subtract the sum of all odd numbers. The result is `(2 + 4) - (1 + 3)`, or `-1 + 2 - 3 + 4` resembling the order of the numbers in the `for`-loop." + "`if` statements may have more than one header line: For example, the code in the `else`-clause's body is only executed if the condition in the `if`-clause is `False`. In the code cell below, we calculate the sum of all even numbers and subtract the sum of all odd numbers. The result is `(2 + 4) - (1 + 3 + 5)`, or `-1 + 2 - 3 + 4 - 5` resembling the order of the numbers in the `for`-loop." ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "2" + "-3" ] }, - "execution_count": 19, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -621,7 +797,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -658,7 +834,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -706,7 +882,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -747,7 +923,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -788,7 +964,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 30, "metadata": {}, "outputs": [ { diff --git a/00_python_in_a_nutshell/05_content_functions.ipynb b/00_python_in_a_nutshell/05_content_functions.ipynb index 1b56e0e..7961934 100644 --- a/00_python_in_a_nutshell/05_content_functions.ipynb +++ b/00_python_in_a_nutshell/05_content_functions.ipynb @@ -29,7 +29,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## User-defined Functions" + "## Defining Functions" ] }, { @@ -151,7 +151,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/user/1000/ipykernel_305654/1049141082.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/tmp/user/1000/ipykernel_707190/1049141082.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'result' is not defined" ] } @@ -393,7 +393,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Extending Core Python with the Standard Library" + "## The Standard Library" ] }, { @@ -429,7 +429,7 @@ { "data": { "text/plain": [ - "0.44374384200665107" + "0.7021021034327006" ] }, "execution_count": 16, diff --git a/01_scientific_stack/00_content.ipynb b/01_scientific_stack/00_content.ipynb deleted file mode 100644 index 3498dbd..0000000 --- a/01_scientific_stack/00_content.ipynb +++ /dev/null @@ -1,674 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Chapter 1: Python's Scientific Stack" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Python itself does not come with any scientific algorithms. However, over time, many third-party libraries emerged that are useful to build machine learning applications. In this context, \"third-party\" means that the libraries are *not* part of Python's standard library.\n", - "\n", - "Among the popular ones are [numpy](https://numpy.org/) (numerical computations, linear algebra), [pandas](https://pandas.pydata.org/) (data processing), [matplotlib](https://matplotlib.org/) (visualisations), and [scikit-learn](https://scikit-learn.org/stable/index.html) (machine learning algorithms)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Extending Core Python with Third-party Packages" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before we can import these libraries, we must ensure that they installed on our computers. If you installed Python via the Anaconda Distribution that should already be the case. Otherwise, we can use Python's **package manager** `pip` to install them manually.\n", - "\n", - "`pip` is a so-called command-line interface (CLI), meaning it is a program that is run within a terminal window. JupyterLab allows us to run such a CLI tool from within a notebook by starting a code cell with a single `%` symbol. Here, this does not mean Python's modulo operator but is just an instruction to JupyterLab that the following code is *not* Python." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: numpy in ./.venv/lib/python3.8/site-packages (1.20.3)\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install numpy" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: pandas in ./.venv/lib/python3.8/site-packages (1.2.4)\n", - "Requirement already satisfied: numpy>=1.16.5 in ./.venv/lib/python3.8/site-packages (from pandas) (1.20.3)\n", - "Requirement already satisfied: python-dateutil>=2.7.3 in ./.venv/lib/python3.8/site-packages (from pandas) (2.8.1)\n", - "Requirement already satisfied: pytz>=2017.3 in ./.venv/lib/python3.8/site-packages (from pandas) (2021.1)\n", - "Requirement already satisfied: six>=1.5 in ./.venv/lib/python3.8/site-packages (from python-dateutil>=2.7.3->pandas) (1.16.0)\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install pandas" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: matplotlib in ./.venv/lib/python3.8/site-packages (3.4.2)\n", - "Requirement already satisfied: python-dateutil>=2.7 in ./.venv/lib/python3.8/site-packages (from matplotlib) (2.8.1)\n", - "Requirement already satisfied: pyparsing>=2.2.1 in ./.venv/lib/python3.8/site-packages (from matplotlib) (2.4.7)\n", - "Requirement already satisfied: pillow>=6.2.0 in ./.venv/lib/python3.8/site-packages (from matplotlib) (8.2.0)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in ./.venv/lib/python3.8/site-packages (from matplotlib) (1.3.1)\n", - "Requirement already satisfied: numpy>=1.16 in ./.venv/lib/python3.8/site-packages (from matplotlib) (1.20.3)\n", - "Requirement already satisfied: cycler>=0.10 in ./.venv/lib/python3.8/site-packages (from matplotlib) (0.10.0)\n", - "Requirement already satisfied: six in ./.venv/lib/python3.8/site-packages (from cycler>=0.10->matplotlib) (1.16.0)\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install matplotlib" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: scikit-learn in ./.venv/lib/python3.8/site-packages (0.24.2)\n", - "Requirement already satisfied: joblib>=0.11 in ./.venv/lib/python3.8/site-packages (from scikit-learn) (1.0.1)\n", - "Requirement already satisfied: threadpoolctl>=2.0.0 in ./.venv/lib/python3.8/site-packages (from scikit-learn) (2.1.0)\n", - "Requirement already satisfied: numpy>=1.13.3 in ./.venv/lib/python3.8/site-packages (from scikit-learn) (1.20.3)\n", - "Requirement already satisfied: scipy>=0.19.1 in ./.venv/lib/python3.8/site-packages (from scikit-learn) (1.6.1)\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install scikit-learn" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After we have ensured that the third-party libraries are installed locally, we can simply go ahead with the `import` statement. All the libraries are commonly imported with shorter prefixes for convenient use later on." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's see how the data type provided by these scientific libraries differ from Python's built-in ones.\n", - "\n", - "As an example, we create a `list` object similar to the one from Chapter 0." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "vector = [1, 2, 3]\n", - "\n", - "vector" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We call the `list` object by the name `vector` as that is what the data mean conceptually. As we remember from our linear algebra courses, vectors should implement scalar-multiplication. So, the following code cell should result in `[3, 6, 9]` as the answer. Surprisingly, the result is a new `list` with all the elements in `vector` repeated three times. That operation is called **concatenation** and is an example of a concept called **operator overloading**. That means that an operator, like `*` in the example, may exhibit a different behavior depending on the data type of its operands." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2, 3, 1, 2, 3, 1, 2, 3]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "3 * vector" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`numpy`, among others, provides a data type called an **n-dimensional array**. This may sound fancy at first but when used with only 1 or 2 dimensions, it basically represents vectors and matrices as we know them from linear algebra. Additionally, arrays allow for much faster computations as they are implemented in the very efficient [C language](https://en.wikipedia.org/wiki/C_%28programming_language%29) and optimized for numerical operations." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To create an array, we use the [array()](https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html#numpy-array) constructor from the imported `np` module and provide it with a `list` of values." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 2, 3])" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v1 = np.array([1, 2, 3])\n", - "\n", - "v1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The vector `v1` can now be multiplied with a scalar yielding a result meaningful in the context of linear algebra." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([3, 6, 9])" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v2 = 3 * v1\n", - "\n", - "v2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To create a matrix, we just use a `list` of (row) `list`s of values." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[1, 2, 3],\n", - " [4, 5, 6]])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m1 = np.array([\n", - " [1, 2, 3],\n", - " [4, 5, 6],\n", - "])\n", - "\n", - "m1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can use `numpy`'s `dot()` function to multiply a matrix with a vector to obtain a new vector ..." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([14, 32])" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v3 = np.dot(m1, v1)\n", - "\n", - "v3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... or simply transpose it by accessing its `.T` attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[1, 4],\n", - " [2, 5],\n", - " [3, 6]])" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m1.T" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The rules from maths still apply and it makes a difference if a vector is multiplied from the left or the right by a matrix. The following operation will fail." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "ename": "ValueError", - "evalue": "shapes (3,) and (2,3) not aligned: 3 (dim 0) != 2 (dim 0)", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mm1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m<__array_function__ internals>\u001b[0m in \u001b[0;36mdot\u001b[0;34m(*args, **kwargs)\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: shapes (3,) and (2,3) not aligned: 3 (dim 0) != 2 (dim 0)" - ] - } - ], - "source": [ - "np.dot(v1, m1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to retrieve only a **slice** (i.e., subset) of an array's data, we index into it. For example, the first row of the matrix is ..." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1, 2, 3])" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m1[0, :]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... while the second column is:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([2, 5])" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m1[:, 1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To acces the lowest element in the right column, two indices can be used." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "m1[1, 2]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`numpy` also provides various other functions and constants, such as `linspace()` to create an array of equidistant numbers, `sin()` to calculate the sinus values for all numbers in an array, or simple an approximation for `pi`. To further illustrate the concept of **vectorization**, let us calculate the sinus curve over a range of 100 values, going from negative to positive $3\\pi$." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-9.42477796, -9.23437841, -9.04397885, -8.8535793 , -8.66317974,\n", - " -8.47278019, -8.28238063, -8.09198108, -7.90158152, -7.71118197,\n", - " -7.52078241, -7.33038286, -7.1399833 , -6.94958375, -6.75918419,\n", - " -6.56878464, -6.37838508, -6.18798553, -5.99758598, -5.80718642,\n", - " -5.61678687, -5.42638731, -5.23598776, -5.0455882 , -4.85518865,\n", - " -4.66478909, -4.47438954, -4.28398998, -4.09359043, -3.90319087,\n", - " -3.71279132, -3.52239176, -3.33199221, -3.14159265, -2.9511931 ,\n", - " -2.76079354, -2.57039399, -2.37999443, -2.18959488, -1.99919533,\n", - " -1.80879577, -1.61839622, -1.42799666, -1.23759711, -1.04719755,\n", - " -0.856798 , -0.66639844, -0.47599889, -0.28559933, -0.09519978,\n", - " 0.09519978, 0.28559933, 0.47599889, 0.66639844, 0.856798 ,\n", - " 1.04719755, 1.23759711, 1.42799666, 1.61839622, 1.80879577,\n", - " 1.99919533, 2.18959488, 2.37999443, 2.57039399, 2.76079354,\n", - " 2.9511931 , 3.14159265, 3.33199221, 3.52239176, 3.71279132,\n", - " 3.90319087, 4.09359043, 4.28398998, 4.47438954, 4.66478909,\n", - " 4.85518865, 5.0455882 , 5.23598776, 5.42638731, 5.61678687,\n", - " 5.80718642, 5.99758598, 6.18798553, 6.37838508, 6.56878464,\n", - " 6.75918419, 6.94958375, 7.1399833 , 7.33038286, 7.52078241,\n", - " 7.71118197, 7.90158152, 8.09198108, 8.28238063, 8.47278019,\n", - " 8.66317974, 8.8535793 , 9.04397885, 9.23437841, 9.42477796])" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = np.linspace(-3 * np.pi, 3 * np.pi, 100)\n", - "\n", - "x" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-3.67394040e-16, -1.89251244e-01, -3.71662456e-01, -5.40640817e-01,\n", - " -6.90079011e-01, -8.14575952e-01, -9.09631995e-01, -9.71811568e-01,\n", - " -9.98867339e-01, -9.89821442e-01, -9.45000819e-01, -8.66025404e-01,\n", - " -7.55749574e-01, -6.18158986e-01, -4.58226522e-01, -2.81732557e-01,\n", - " -9.50560433e-02, 9.50560433e-02, 2.81732557e-01, 4.58226522e-01,\n", - " 6.18158986e-01, 7.55749574e-01, 8.66025404e-01, 9.45000819e-01,\n", - " 9.89821442e-01, 9.98867339e-01, 9.71811568e-01, 9.09631995e-01,\n", - " 8.14575952e-01, 6.90079011e-01, 5.40640817e-01, 3.71662456e-01,\n", - " 1.89251244e-01, -1.22464680e-16, -1.89251244e-01, -3.71662456e-01,\n", - " -5.40640817e-01, -6.90079011e-01, -8.14575952e-01, -9.09631995e-01,\n", - " -9.71811568e-01, -9.98867339e-01, -9.89821442e-01, -9.45000819e-01,\n", - " -8.66025404e-01, -7.55749574e-01, -6.18158986e-01, -4.58226522e-01,\n", - " -2.81732557e-01, -9.50560433e-02, 9.50560433e-02, 2.81732557e-01,\n", - " 4.58226522e-01, 6.18158986e-01, 7.55749574e-01, 8.66025404e-01,\n", - " 9.45000819e-01, 9.89821442e-01, 9.98867339e-01, 9.71811568e-01,\n", - " 9.09631995e-01, 8.14575952e-01, 6.90079011e-01, 5.40640817e-01,\n", - " 3.71662456e-01, 1.89251244e-01, 1.22464680e-16, -1.89251244e-01,\n", - " -3.71662456e-01, -5.40640817e-01, -6.90079011e-01, -8.14575952e-01,\n", - " -9.09631995e-01, -9.71811568e-01, -9.98867339e-01, -9.89821442e-01,\n", - " -9.45000819e-01, -8.66025404e-01, -7.55749574e-01, -6.18158986e-01,\n", - " -4.58226522e-01, -2.81732557e-01, -9.50560433e-02, 9.50560433e-02,\n", - " 2.81732557e-01, 4.58226522e-01, 6.18158986e-01, 7.55749574e-01,\n", - " 8.66025404e-01, 9.45000819e-01, 9.89821442e-01, 9.98867339e-01,\n", - " 9.71811568e-01, 9.09631995e-01, 8.14575952e-01, 6.90079011e-01,\n", - " 5.40640817e-01, 3.71662456e-01, 1.89251244e-01, 3.67394040e-16])" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y = np.sin(x)\n", - "\n", - "y" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With `matplotlib`'s [plot()](https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot) function we can visualize the sinus curve." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(x, y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us quickly generate some random data and draw a scatter plot with `numpy`'s `random` module." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x = np.random.normal(42, 3, 100)\n", - "y = np.random.gamma(7, 1, 100)\n", - "\n", - "plt.scatter(x, y)" - ] - } - ], - "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.8.12" - }, - "toc": { - "base_numbering": 1, - "nav_menu": {}, - "number_sections": false, - "sideBar": true, - "skip_h1_title": false, - "title_cell": "Table of Contents", - "title_sidebar": "Contents", - "toc_cell": false, - "toc_position": {}, - "toc_section_display": true, - "toc_window_display": false - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/01_scientific_stack/00_content_numpy.ipynb b/01_scientific_stack/00_content_numpy.ipynb new file mode 100644 index 0000000..1872760 --- /dev/null +++ b/01_scientific_stack/00_content_numpy.ipynb @@ -0,0 +1,1354 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-data-science/main?urlpath=lab/tree/01_scientific_stack/00_content_numpy.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chapter 1: Python's Scientific Stack (Part 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python itself does not come with any scientific algorithms. However, over time, many third-party libraries emerged that are useful to build machine learning applications. In this context, \"third-party\" means that the libraries are *not* part of Python's standard library.\n", + "\n", + "Among the popular ones are [numpy ](https://numpy.org/) (numerical computations, linear algebra), [pandas ](https://pandas.pydata.org/) (data processing), [matplotlib ](https://matplotlib.org/) (visualisations), and [scikit-learn ](https://scikit-learn.org/stable/index.html) (machine learning algorithms)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extending Python with Third-party Packages" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we can import these libraries, we must ensure that they installed on our computers. If you installed Python via the Anaconda Distribution that should already be the case. Otherwise, we can use Python's **package manager** `pip` to install them manually.\n", + "\n", + "`pip` is a so-called command-line interface (CLI), meaning it is a program that is run within a terminal window. JupyterLab allows us to run such a CLI tool from within a notebook by starting a code cell with a single `%` symbol. Here, this does not mean Python's modulo operator but is just an instruction to JupyterLab that the following code is *not* Python.\n", + "\n", + "So, let's proceed by installing [numpy ](https://numpy.org/) and [matplotlib ](https://matplotlib.org/)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: numpy in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (1.21.1)\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install numpy" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: matplotlib in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (3.4.3)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from matplotlib) (2.8.2)\n", + "Requirement already satisfied: cycler>=0.10 in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from matplotlib) (0.10.0)\n", + "Requirement already satisfied: pyparsing>=2.2.1 in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from matplotlib) (2.4.7)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from matplotlib) (1.3.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from matplotlib) (8.3.2)\n", + "Requirement already satisfied: numpy>=1.16 in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from matplotlib) (1.21.1)\n", + "Requirement already satisfied: six in /home/webartifex/repos/intro-to-data-science/.venv/lib/python3.8/site-packages (from cycler>=0.10->matplotlib) (1.16.0)\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install matplotlib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After we have ensured that the third-party libraries are installed locally, we can simply go ahead with the `import` statement. All the libraries are commonly imported with shorter prefixes for convenient use later on." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see how the data type provided by these scientific libraries differ from Python's built-in ones." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Vectors and Matrices with Numpy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As an example, let's start by creating a `list` object." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vector = [1, 2, 3, 4, 5]\n", + "\n", + "vector" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We call the `list` object by the name `vector` as that is what the data is supposed to mean conceptually. As we remember from our linear algebra courses, vectors should implement scalar-multiplication. So, the following code cell should result in `[3, 6, 9, 12, 15]` as the answer. Surprisingly, the result is a new `list` with all the elements in `vector` repeated three times. That operation is called **concatenation** and is an example of a concept called **operator overloading**. That means that an operator, like `*` in the example, may exhibit a different behavior depending on the data type of its operands." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "3 * vector" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[numpy ](https://numpy.org/), among others, provides a data type called an **n-dimensional array**. This may sound fancy at first but when used with only 1 or 2 dimensions, it basically represents vectors and matrices as we know them from linear algebra. Additionally, arrays allow for much faster computations as they are implemented in the very efficient [C language ](https://en.wikipedia.org/wiki/C_%28programming_language%29) and optimized for numerical operations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To create an array, we use the [np.array() ](https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html#numpy-array) constructor and provide it a `list` of values." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3, 4, 5])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1 = np.array([1, 2, 3, 4, 5])\n", + "\n", + "v1" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(v1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The vector `v1` can now be multiplied with a scalar yielding a result meaningful in the context of linear algebra." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 3, 6, 9, 12, 15])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v2 = 3 * v1\n", + "\n", + "v2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To model a matrix, we use a `list` of (row) `list`s of values. Note how the output below the cell contains *two* levels of brackets `[` and `]`." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10]])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1 = np.array([\n", + " [1, 2, 3, 4, 5],\n", + " [6, 7, 8, 9, 10],\n", + "])\n", + "\n", + "m1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can use the [np.dot() ](https://numpy.org/doc/stable/reference/generated/numpy.dot.html#numpy.dot) function to multiply a matrix with a vector to obtain a new vector ..." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 55, 130])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v3 = np.dot(m1, v1)\n", + "\n", + "v3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "... or simply transpose it by accessing its [.T ](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.T.html#numpy.ndarray.T) attribute." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1, 6],\n", + " [ 2, 7],\n", + " [ 3, 8],\n", + " [ 4, 9],\n", + " [ 5, 10]])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1.T" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The rules from maths still apply and it makes a difference if a vector is multiplied from the left or the right by a matrix. The following operation will fail." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "shapes (5,) and (2,5) not aligned: 5 (dim 0) != 2 (dim 0)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/user/1000/ipykernel_1264563/568665770.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mm1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m<__array_function__ internals>\u001b[0m in \u001b[0;36mdot\u001b[0;34m(*args, **kwargs)\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: shapes (5,) and (2,5) not aligned: 5 (dim 0) != 2 (dim 0)" + ] + } + ], + "source": [ + "np.dot(v1, m1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Indexing & Slicing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to retrieve only a subset of an array's data, we index or slice into it. This is similar to how we index or slice into `list` objects, in particular, if we deal with one-dimensional arrays like `v1`, `v2`, or `v3`." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3, 4, 5])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Indexing may be done with either positive (`0`-based) indexes from the left or negative (`1`-based) indexes from the right.\n", + "\n", + "Here, we obtain the first and the last element in `v1`." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Slicing uses the same `:` notation as with `list`s taking *start*, *stop*, and *step* values." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([2, 3, 4])" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[1:-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([3, 4, 5])" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[2:]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3, 4])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[:-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([2, 4])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[1:-1:2]" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 3, 5])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1[::2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Indexing and slicing become slightly more complicated when working with higher dimensional arrays like `m1`. In principle, we must provide either an index or a slice for *each* dimension." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10]])" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, to slice out the first row of the matrix, we write `[0, :]`. The `0` implies taking elements in *only* the *first* row and the `:` means taking elements across *all* columns." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3, 4, 5])" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[0, :]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For sure, we could also *not* leave out the *start* and *stop* values along the second dimension and obtain the same result. But that would not only be unneccessary but also communicate a different meaning, namely to \"take elements from the first through the fifth columns\" instead of \"take elements from all columns.\"" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3, 4, 5])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[0, 0:5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Whenever we take *all* elements in *later* dimensions (i.e., those more to the right), we may also drop the index or slice instead and keep only the *earlier* ones. However, the previous style is a bit more explicit in that we are working with a two-dimensional array." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3, 4, 5])" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As another example, let's slice out elements across *all* rows but in only the *second* column. Colloquially, we can say that we \"slice out the second column\" from the matrix." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([2, 7])" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[:, 1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we wanted to slice out a smaller matrix from a larger one, we slice along both dimensions. Above, we have only sliced along one dimension while indexing into the other.\n", + "\n", + "For example, to obtain a 2x2 square matrix consisting of the two left-most columns in `m1`, we can write the following." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1, 2],\n", + " [6, 7]])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[:2, :2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, to slice out a 2x2 matrix consisting of the two right-most columns, we write the following." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 4, 5],\n", + " [ 9, 10]])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[-2:, -2:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To access individual elements as scalars, we combine two indexes along both dimensions.\n", + "\n", + "For example, to access the element in the lower-left corner, we write the following." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[1, 0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dimensionality vs. Shapes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both, the vectors `v1`, `v2`, and `v3`, and the matrix `m1` have the *same* **data type** from a technical point of view, namely `np.ndarray`." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(v1)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(m1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So, how can we tell that they have different dimensions without looking at how they are displayed below a code cell?\n", + "\n", + "The `np.ndarray` type comes with a couple of **properties** that we can access via the dot notation. Examples are `.ndim` and `.shape`.\n", + "\n", + "While `.ndim` simply tells us how many dimensions an array has, ..." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1.ndim" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1.ndim" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "... `.shape` reveals the structure of the elements. The one-element tuple `(5,)` below says that there is one dimension along which there are five elements ..." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(5,)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v1.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "... whereas the two-element tuple `(2, 5)` indicates that the array's elements are placed along two dimensions spanning a grid of two elements in one and five elements into the other dimension. We know such notations already from our linear algebra courses where we would call `m1` a 2x5 matrix." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2, 5)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is a relationship behind the dimensionality of an array we are slicing and indexing and what we get back as a result: Whenever we index into an array along some dimension, the result will have one dimension less than the original.\n", + "\n", + "For example, if we start with a two-dimensional array like `m1` and slice along both dimensions, the result will also have two dimensions, even if it holds only one element." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1, 2, 3, 4, 5],\n", + " [ 6, 7, 8, 9, 10]])" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1]])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[:1, :1] # Note the double brackets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If, on the contrary, we slice only along one of the two dimensions and index into the other, the result is a one-dimensional array. So, both of the below slices have the *same* properties and we cannot tell if one of them was (part of) a row or column in `m1`." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([6, 7])" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[1, :2]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 5, 10])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[:, -1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, indexing along both dimensions gives us back a scalar value." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m1[0, 0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Array Constructors & Functions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[numpy ](https://numpy.org/) provides various **constructors** (i.e., functions) to create all kinds of arrays.\n", + "\n", + "For example, [np.linspace() ](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html#numpy.linspace) creates an array of equidistant numbers, often used to model the values on a function's x-axis. [np.pi ](https://numpy.org/doc/stable/reference/constants.html#numpy.pi) is an alias for Python's built-in `math.pi`. The cell below creates `100` coordinate points arranged between $-3\\pi$ and $+3\\pi$." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-9.42477796, -9.23437841, -9.04397885, -8.8535793 , -8.66317974,\n", + " -8.47278019, -8.28238063, -8.09198108, -7.90158152, -7.71118197,\n", + " -7.52078241, -7.33038286, -7.1399833 , -6.94958375, -6.75918419,\n", + " -6.56878464, -6.37838508, -6.18798553, -5.99758598, -5.80718642,\n", + " -5.61678687, -5.42638731, -5.23598776, -5.0455882 , -4.85518865,\n", + " -4.66478909, -4.47438954, -4.28398998, -4.09359043, -3.90319087,\n", + " -3.71279132, -3.52239176, -3.33199221, -3.14159265, -2.9511931 ,\n", + " -2.76079354, -2.57039399, -2.37999443, -2.18959488, -1.99919533,\n", + " -1.80879577, -1.61839622, -1.42799666, -1.23759711, -1.04719755,\n", + " -0.856798 , -0.66639844, -0.47599889, -0.28559933, -0.09519978,\n", + " 0.09519978, 0.28559933, 0.47599889, 0.66639844, 0.856798 ,\n", + " 1.04719755, 1.23759711, 1.42799666, 1.61839622, 1.80879577,\n", + " 1.99919533, 2.18959488, 2.37999443, 2.57039399, 2.76079354,\n", + " 2.9511931 , 3.14159265, 3.33199221, 3.52239176, 3.71279132,\n", + " 3.90319087, 4.09359043, 4.28398998, 4.47438954, 4.66478909,\n", + " 4.85518865, 5.0455882 , 5.23598776, 5.42638731, 5.61678687,\n", + " 5.80718642, 5.99758598, 6.18798553, 6.37838508, 6.56878464,\n", + " 6.75918419, 6.94958375, 7.1399833 , 7.33038286, 7.52078241,\n", + " 7.71118197, 7.90158152, 8.09198108, 8.28238063, 8.47278019,\n", + " 8.66317974, 8.8535793 , 9.04397885, 9.23437841, 9.42477796])" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = np.linspace(-3 * np.pi, 3 * np.pi, 100)\n", + "\n", + "x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Besides constructors, [numpy ](https://numpy.org/) provides all kinds of **vectorized** functions. The concept of **vectorization** means that a function is executed once for *each* element in an array. Vectorized functions are one major benefit of using [numpy ](https://numpy.org/): Not only are they optimized heavily on the C level (i.e., \"behind the scenes\") but also allow us to avoid writing explicit `for`-loops that are for some technical reasons considered \"slow\" in Python.\n", + "\n", + "For example, [np.sin() ](https://numpy.org/doc/stable/reference/generated/numpy.sin.html#numpy.sin) calculates the sine for each element in the `x` array. The resulting `y` array has thus the same `.shape` as `x`." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-3.67394040e-16, -1.89251244e-01, -3.71662456e-01, -5.40640817e-01,\n", + " -6.90079011e-01, -8.14575952e-01, -9.09631995e-01, -9.71811568e-01,\n", + " -9.98867339e-01, -9.89821442e-01, -9.45000819e-01, -8.66025404e-01,\n", + " -7.55749574e-01, -6.18158986e-01, -4.58226522e-01, -2.81732557e-01,\n", + " -9.50560433e-02, 9.50560433e-02, 2.81732557e-01, 4.58226522e-01,\n", + " 6.18158986e-01, 7.55749574e-01, 8.66025404e-01, 9.45000819e-01,\n", + " 9.89821442e-01, 9.98867339e-01, 9.71811568e-01, 9.09631995e-01,\n", + " 8.14575952e-01, 6.90079011e-01, 5.40640817e-01, 3.71662456e-01,\n", + " 1.89251244e-01, -1.22464680e-16, -1.89251244e-01, -3.71662456e-01,\n", + " -5.40640817e-01, -6.90079011e-01, -8.14575952e-01, -9.09631995e-01,\n", + " -9.71811568e-01, -9.98867339e-01, -9.89821442e-01, -9.45000819e-01,\n", + " -8.66025404e-01, -7.55749574e-01, -6.18158986e-01, -4.58226522e-01,\n", + " -2.81732557e-01, -9.50560433e-02, 9.50560433e-02, 2.81732557e-01,\n", + " 4.58226522e-01, 6.18158986e-01, 7.55749574e-01, 8.66025404e-01,\n", + " 9.45000819e-01, 9.89821442e-01, 9.98867339e-01, 9.71811568e-01,\n", + " 9.09631995e-01, 8.14575952e-01, 6.90079011e-01, 5.40640817e-01,\n", + " 3.71662456e-01, 1.89251244e-01, 1.22464680e-16, -1.89251244e-01,\n", + " -3.71662456e-01, -5.40640817e-01, -6.90079011e-01, -8.14575952e-01,\n", + " -9.09631995e-01, -9.71811568e-01, -9.98867339e-01, -9.89821442e-01,\n", + " -9.45000819e-01, -8.66025404e-01, -7.55749574e-01, -6.18158986e-01,\n", + " -4.58226522e-01, -2.81732557e-01, -9.50560433e-02, 9.50560433e-02,\n", + " 2.81732557e-01, 4.58226522e-01, 6.18158986e-01, 7.55749574e-01,\n", + " 8.66025404e-01, 9.45000819e-01, 9.89821442e-01, 9.98867339e-01,\n", + " 9.71811568e-01, 9.09631995e-01, 8.14575952e-01, 6.90079011e-01,\n", + " 5.40640817e-01, 3.71662456e-01, 1.89251244e-01, 3.67394040e-16])" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y = np.sin(x)\n", + "\n", + "y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's use [matplotlib ](https://matplotlib.org/)'s [plt.plot() ](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plot) function to visualize the sine curve between $-3\\pi$ and $+3\\pi$." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(x, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we use only `10` equidistant points for `x`, the resulting curve does not look like a curve. There is a trade-off behind this: To make nice plots, we need a rather high granularity of data points. That, however, causes more computations in the background making the plotting slower. With toy data like the one here this is not an issue. For real life data that may be different." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x = np.linspace(-3 * np.pi, 3 * np.pi, 10)\n", + "y = np.sin(x)\n", + "\n", + "plt.plot(x, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[numpy ](https://numpy.org/) provides further constructors. Most notably are the ones in the [np.random ](https://numpy.org/doc/stable/reference/random/index.html#module-numpy.random) module that mirrors the [random ](https://docs.python.org/3/library/random.html) module in the [standard library ](https://docs.python.org/3/library/index.html): For example, [np.random.normal() ](https://numpy.org/doc/stable/reference/random/generated/numpy.random.normal.html#numpy.random.normal) and [np.random.gamma() ](https://numpy.org/doc/stable/reference/random/generated/numpy.random.gamma.html#numpy.random.gamma) return arrays whose elements follow the normal and gamma probability distributions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us quickly generate some random data points and draw a scatter plot with [matplotlib ](https://matplotlib.org/)'s [plt.scatter() ](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html#matplotlib.pyplot.scatter) function." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x = np.random.normal(42, 3, 100)\n", + "y = np.random.gamma(7, 1, 100)\n", + "\n", + "plt.scatter(x, y)" + ] + } + ], + "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.8.12" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/static/link/to_np.png b/static/link/to_np.png new file mode 100644 index 0000000000000000000000000000000000000000..b2911dba8996ea9a3dd08033b90d688b2998fdb1 GIT binary patch literal 1306 zcmV+#1?BpQP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv|NsC0|NjYC_uK#g00(qQO+^Rg3IqrTI40lFh5!Hr9!W$&R5;6xRC`QYbrk;H z+uru}!CKl<1XiA-E0%3+v@7dOP!SLuMBI!-mJvc6WFaNYZ7u>MZcEJ6ZOKT6s}az# z01l%8MO~&WN?ds}7%(iI6iQnP^l@8gd;9qL$JEe73EzL`B;R+wd^zU;xE=Um00!YN za2~Ef68d3qJ0uir314OKIJ__}U0!!iwGxwErl^r4=FglQGCeQ^rCW26XA?HJNMkS# zmRN%8pOfLiVYmS++Tk=XgMn0IJfTRHMU=DJ%P4y^(J6EtwHJ*QC>Y_ieY8I)FCep< zb*P&QeKS$*xzdp|-EOX*7_=n2K9WT9*I1=*)=8cUHLnN6$AxlQ6$L@EyDw^6SEGmS zn{Ln2;{E5Q$#FZV}JVd^I^b{2~(-cC&hEaYVYeK9Fl&@Vx66g-C0^ zG4yQM)Q9hS4A)W+bcn^dtjXNFYfOGFI(>(@t8kXIsP4>7p{A8 zx#+OS6Y*shJ=VZe@)nslu*m7CRlcjqd4SCI&p*^G+3isp-k1MySG9I}qA9`5p6v5j~Mp82(DR=NCXTf@{N^HIyC zjX6@r?7--hd1d*|tDL^1T5b-rAk_6k@EABSCv^@vg1M` zwI2@X?yR<}YGs_*2T6bn82<#qsG?V+*_fX)h8FMjB*n2$N>0V;Sw>yX(s}o7cn#Wt zo{QjDv7*$8h}~>qU)jP3*2d8q^Dg3qVU+0hob<{ALr{ukqf|s3vLUHw65Z^8>fW(w zQPa*d!k_W3yh24Lzk%h$%PAXR9^3?O+lTI7efeLgCXGhr;Joo1QR&qO+JX_HQ#%%L z>xr4vyr{xG`NGmLMMxmDQtDIWM_H)^>;M3OT%h1m*|(@8*;YBhYwCASblNBVvS0?( z`qi)!3gd&^WPBu{fYZm&=FcWo3u0(B6fOD+QUUbf#{VArW_TRrli=g=HLc6Z;Fk&N zvGqS|+y+lZ+K4cnZ4jm~&(cWnHjsknw)I2)11_)u0^m2W0BnE{H~<3&K@{L@P5KKO zfFK=H$}U0x001R)MObuXVRU6WV{&C-bY%cCFfuVMF)%GKG*mD+IxsgnGdC+RFgh?W zSrvqe0000bbVXQnWMOn=I&E)cX=Zr#!I65#lIx{ybFfckWFepeo QHUIzs07*qoM6N<$f);C4(*OVf literal 0 HcmV?d00001 diff --git a/static/link/to_pd.png b/static/link/to_pd.png new file mode 100644 index 0000000000000000000000000000000000000000..85d56c63d6d9f3fe0c5e021285459eb0e2ab9f30 GIT binary patch literal 862 zcmeAS@N?(olHy`uVBq!ia0vp^{214Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>CFK7VhX3aoTGO@oSwjTDCIiJI9IOMZY=aa7LReE` zSW|`AL5>szs%Hx>Va<8N-1&jIOAzP)kT}TMKz1r?#(Ut{2vEB4u5?*5gnVk>N|Qj*nq!~Q^B z$&ailFRiC1Pkd(JZ~V?oNYeG$;V4#}Bd{>_sry#E=wL#;+S$?;_phD1cktrLo28GXixc%Go|SGSbF3wkFtB*ElK7nJ;qW#Jo9^xSlaH)D%jE zedfL+19YltiEBhjN@7W>RdP`(kYX@0Ff!CNG|)9L2{Ev+GBmU@Fwr(Jure^vdSnLl lJCcUn{FKbJN^}hdR;K0<4QER~asV|jc)I$ztaD0e0sy9c^#%X{ literal 0 HcmV?d00001 diff --git a/static/link/to_plt.png b/static/link/to_plt.png new file mode 100644 index 0000000000000000000000000000000000000000..a3b443c23a0f21c805b021b776e1ebf31f5e5eb2 GIT binary patch literal 1148 zcmZ`$drVtp6u*RRARE-_HWEUXC1%)-OiPC_apF)AkcU7KT|ibI9q}mqFfuJvA zAgJzJ2-*UnItqf$b0EmdhoGbm2#T!vX)^yL1O?%F*@bB!Av!u*Zm`H?vXYXL?d@%i zMx$1%OG`_mqM}d~6|b)!X2%ZSyDvr+N>pOCPIh`)I+YN|4&NMk3PRfK*O9fVOxox9E zuNI-BofE$`OwLZKHO4@|@ALWe2IB@cOD`q-wSLII_N;aBHPLWQThpam{ZlZiHk-{j zj)MV#8o+Gga(J%g$6xx#CPl+@ec1265(=?D5OBHZMX_;uUZo>+xAi@Wm3w&SIZ86a zc)U8D77)Uncstpya~Y`n-Q=Zo>s&w37U&O@@p`-}Qq`yLV_b~wcCDk9OU@1ultm;G zQ6$Bi}wahI?lmk01)WASc? z)}}iPS?mstQ-LAyQY(8%x9QhPVGNNDu@q)MiD~Upc_AX%plQrZ$R)^9CxXEe4TD>h zumpxXrxc9CpeAS&CKj)1HXjDO?oCpOVkoxipd2R3s91+LG?-Oq-;l^*%#Gn*tyC_N zC@e7PH?*=*iQGEQZez1}Q){eu4>sQf{DR7}(o=T^sx1q^2@z)Iq=gV+J3{w7|9YUY z0fgwx)Re+dc?F+eX&{V|Pwso_z+S=GNl@(K%z^55dg zB`8wFuaY#&5t%fR6VFYEleNgpIIYJghDS%n?~L93tVYPKsJZa*`A_{WFahK9utFU*&)O4~3$nz5oCK literal 0 HcmV?d00001 diff --git a/static/link/to_skl.png b/static/link/to_skl.png new file mode 100644 index 0000000000000000000000000000000000000000..9c780cd00a817a8ab1a43a17b82d7093dec9d40f GIT binary patch literal 837 zcmeAS@N?(olHy`uVBq!ia0vp^{214Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Ib;{6Oe z;~A$<&WioiY4m@G3s8i3WIW>x1hGti57z}3G@NmE&y3U`Gc14zC<_z^ilon2`gfN3 z;~wKwdvTxxfPz6YwtSvu?xrmOwo$B&xw)cZ6ZcqBmjb@x}3znOgsL~xO-xDTZ z=PT0{DsMF7%*qV4Maimj5|pRKDEMfd(=rdAqyhDe(t_LXN$})7O>#DHjU|pK-$ZP3}OU8J;eV zAsp9}6BM`%HWe2X6&f2kRrc8IsrkdyA^gp^5KTzrh5mZnNb zraXNjDl*mS@F8WT#Zy8hBtsT2zIw$pDe3VeVIkA4TO>;sEuLKRby9H9NYpc_?7Tq8gQu&X%Q~loCICI0Nnrp0 literal 0 HcmV?d00001