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 0000000..b2911db Binary files /dev/null and b/static/link/to_np.png differ diff --git a/static/link/to_pd.png b/static/link/to_pd.png new file mode 100644 index 0000000..85d56c6 Binary files /dev/null and b/static/link/to_pd.png differ diff --git a/static/link/to_plt.png b/static/link/to_plt.png new file mode 100644 index 0000000..a3b443c Binary files /dev/null and b/static/link/to_plt.png differ diff --git a/static/link/to_skl.png b/static/link/to_skl.png new file mode 100644 index 0000000..9c780cd Binary files /dev/null and b/static/link/to_skl.png differ