{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "jupyter": { "source_hidden": true }, "tags": [ "remove-cell" ], "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%html\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "# Practical introduction to Python and Numpy\n", "exercisenotebook\n", "\n", "This part of the exercises aims to introduce you to a bit more of the Python and Numpy syntax and give you some simple\n", "guidelines for working effectively with arrays (which is what images are).\n", "\n", "Tasks you have to perform are marked as **Task (x)**.\n", "\n", "*Note: Run each cell as you read along. If a cell is incomplete, it is part of some exercise as described in the text.*" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Using Python to implement basic linear algebra functions\n", "We start by defining vectors $v_a$, $v_b$ as Python lists:\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "va = [2, 2]\n", "vb = [3, 4]" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "The euclidean length of a vector is defined\n", "\n", "$$||v|| = \\sqrt{\\sum_{i=1}^N v_i^2}.$$ {#eq:euclidean_norm}\n", "\n", "### Task A)\n", "1. Implement this as a Python function in the code below.\n", "2. Test the result on vectors $v_a$ and $v_b$ and verify by hand.\n", "\n", "*@eq.euclidean_norm\n", "\n", "**Hints:** \n", "* For-loops in python work like for-each loops in Java, i.e. they loop through the elements of an iterator and takes the\n", "current iterator value as the iteration variable.\n", "* Python has a `range(x)` function which returns an iterator of integers from $0,\\dots, x$.\n", "* The size of a list can be found using the `len(l)` function.\n", "* Exponentiation in python works using the `**` operator. For square root, use `x**(1/2)`.\n", "* Remember to use Python's built in `help()` function for additional documentation. In Jupyter\n", "Lab, you can also open a documentation popover by pressing placing the text cursor on the desired symbol and pressing\n", "**Shift + Tab**." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a 2.8284271247461903\n", "b 5.0\n" ] } ], "source": [ "def norm(v):\n", " # PLACEHOLDER <<\n", " # ...\n", " # >>\n", " # SOLUTION <<\n", " s = 0\n", " for i in range(len(v)):\n", " s += v[i]**2\n", " return s**(1/2)\n", " # >>\n", "\n", "print('a', norm(va))\n", "print('b', norm(vb))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Using loops for list iteration requires quite a lot of boilerplate code. Luckily, Python's *list comprehensions* are\n", "created exactly for making list iteration more expressive and easier to understand.\n", "\n", "A list comprehension has the following form\n", "```python\n", "[f(e) for e in list]\n", "```\n", "where $f$ is an arbitrary function applied to each element $e$. For people familiar with functional programming, this\n", "is equivalent to the `map` function. *Note: List comprehensions can also include guard rules. You can read more about\n", "list comprehensions [here](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions).*\n", "\n", "Python also provides a wealth of utility functions for performing common list operations. One such function is\n", "```python\n", "sum(l)\n", "```\n", "which sums all elements in the list argument.\n", "\n", "### Task B)\n", "1. Implement the euclidean length function below by using a list comprehension and sum function.\n", " - First exponentiate each element in the list comprehension, resulting in a new list of exponentiated values.\n", " - Then use the sum function to add all elements together and finally remember the square root.\n", "2. Test the result as before." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a 2.8284271247461903\n", "b 5.0\n" ] } ], "source": [ "def norm2(v):\n", " # PLACEHOLDER <<\n", " # ...\n", " # >>\n", " # SOLUTION <<\n", " return sum([e**2 for e in v])**(1/2)\n", " # >>\n", "\n", "print('a', norm2(va))\n", "print('b', norm2(vb))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Your next task is to produce a dot product given two vectors. For reference, the dot product for vectors is defined as:\n", "\n", "$$\n", "dot(a, b) = a\\bullet b = \\sum_{i=1}^N a_ib_i.\n", "$$\n", "\n", "### Task C)\n", "1. Finish the function \"dot\" below by implementing the equation for dot product using either for-loops or list\n", "comprehensions.\n", " - *Note: If you want to use list comprehensions you need the function `zip` which interleaves two iterators. It is\n", " equivalent to most functional language zip functions. Documentation can be found\n", " [here](https://docs.python.org/3/library/functions.html#zip)*\n", "2. Test the implementation on $v_a$ and $v_b$. Verify by hand!" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "14" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def dot(a, b):\n", " # PLACEHOLDER <<\n", " # ...\n", " # >>\n", " # SOLUTION <<\n", " t = 0\n", " for i in range(len(a)):\n", " t += a[i] * b[i]\n", " return t\n", " # >>\n", "\n", "def dot2(a, b):\n", " return sum([a*b for a, b in zip(va, vb)])\n", "\n", "dot(va, vb)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Finally, we need to implement matrix multiplication. For an $N\\times D$ matrix $A$ and a $D\\times K$ matrix $B$, the\n", "matrix multiplication (or matrix product) is a new $N\\times K$ matrix $R$. Elements $R_{ij}$ of $R$ can be calculated\n", "using the following formula\n", "\n", "$$\n", "R_{ij} = \\sum_{d=1}^D A_{id}B_{dj}.\n", "$$\n", "\n", "In other words, it is the dot product of the $i$'th row vector of $A$ and the $j$'th column vector of $B$.\n", "\n", "### Task D)\n", "1. We provided a possible implementation of matrix multiplication. Make sure that you understand what's going on,\n", "especially concerning the actual result calculation (for loops).\n", "2. Create sample matrices $m_a$ and $m_b$ by filling out the code stubs below. The sizes aren't important as long as\n", "they are valid for multiplication. *Hint: Use nested lists to create each row.*.\n", "3. Calculate the result by hand. Verify that it matches the function output." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "# PLACEHOLDER <<\n", "# ma = ...\n", "# >>\n", "# SOLUTION <<\n", "ma = [\n", " [1, 2, 3],\n", " [4, 5, 6],\n", " [7, 8, 9]\n", "]\n", "# >>\n", "\n", "# PLACEHOLDER <<\n", "# mb = ...\n", "# >>\n", "# SOLUTION <<\n", "mb = [\n", " [5, 4, 9],\n", " [2, 1, 7],\n", " [8, 0, 1]\n", "]\n", "# >>" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "[[33, 6, 26], [78, 21, 77], [123, 36, 128]]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def matmul(a, b):\n", " # Check for valid matrix sizes\n", " if len(a[0]) != len(b):\n", " raise ValueError(f'Matrices of size ({len(a), len(a[0])}) and ({len(b), len(b[0])}) are not compatible')\n", " \n", " # D = inner_size\n", " inner_size = len(b) \n", " \n", " # The NxK output matrix, initialised to 0s\n", " out = [[0 for _ in range(inner_size)] for _ in range(inner_size)]\n", " \n", " for row_a in range(len(a)):\n", " for col_b in range(len(b[0])):\n", " \n", " # Application of the formula\n", " out[row_a][col_b] = 0\n", " for i in range(inner_size):\n", " \n", " out[row_a][col_b] += a[row_a][i] * b[i][col_b]\n", " return out\n", " \n", "matmul(ma, mb)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Introducing Numpy\n", "\n", "Numpy makes it way easier to work with multidimensional arrays and provides a significant performance increase as well.\n", "We start by showing how Numpy is used to do simple array operations.\n", "\n", "The following code imports the `numpy` package and creates a $3\\times 3$ matrix:\n", "\n", "*Note the import statement renaming `numpy` to `np`. This is commonly done in Python to avoid namespace confusion.*" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "import numpy as np\n", "\n", "vec = np.array([\n", " [1, 2, 3],\n", " [3, 4, 9],\n", " [5, 7, 3]\n", "])" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "To check the size of an array use `a.shape`. This works on all numpy arrays, e.g. `(vec*2).shape` works as well (we will\n", " return to array operations later in this exercise).\n", "\n", "Print the shape of `vec` below and verify that it corresponds to the expected shape." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(3, 3)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vec.shape" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Slicing in Python enables the selection of more than one array element. Instead of specifying a single number, e.g. `0`\n", "a range can be specified using the notation `:`, e.g. `0:2`. Check the code below for a few examples:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "single [1 2 3]\n", "vector [2 4]\n", "matrix\n", " [[1 2]\n", " [3 4]\n", " [5 7]]\n" ] } ], "source": [ "single = vec[0]\n", "print('single', single)\n", "\n", "vector = vec[:2, 1] # 0's can be ommitted.\n", "print('vector', vector)\n", "\n", "matrix = vec[:, :2]\n", "print('matrix\\n', matrix)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "It is also possible to use negative indices. These are equivalent to counting from the end of the array, i.e. `-`\n", "$\\equiv$ `len(a)-`. A few examples:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "single 3\n", "arange [[1 2]]\n" ] } ], "source": [ "single = vec[-1, -1]\n", "print('single', single)\n", "\n", "arange = vec[0:-2, 0:-1]\n", "print('arange', arange)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "### Task E)\n", "1. Create variable `ur` as a 2x2 matrix of the upper right corner of `vec` using slicing.\n", "2. Create variable `row` as the 2nd row of `vec`\n", "3. Create variable `col` as the 1st column of `vec`" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "upper right [[2 3]\n", " [4 9]]\n", "row [3 4 9]\n", "column [1 3 5]\n" ] } ], "source": [ "# PLACEHOLDER <<\n", "# ur = ...\n", "# row = ...\n", "# col = ...\n", "# >>\n", "# SOLUTION <<\n", "ur = vec[:2, 1:]\n", "row = vec[1] # or vec[2, :]\n", "col = vec[:, 0]\n", "# >>\n", "\n", "print('upper right', ur)\n", "print('row', row)\n", "print('column', col)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Using Numpy for array operations\n", "While these implementations seem fine for our sample inputs, they quickly become unbearingly slow when increasing the\n", "size of the operands. For example, the matrix multiplication runs in time $O(NKD)$ which is $O(N^3)$ if $N=K=D$.\n", "\n", "Let's try an example. The code below uses numpy to generate $100\\times 100$ matrices of random numbers:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "ta = np.random.randint(100, size=(100, 100))\n", "tb = np.random.randint(100, size=(100, 100))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Jupyter Lab provides special command `%timeit ` which runs a performance test on the supplied statement. This\n", "way, we can test how fast our matrix multiplication code is:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "569 ms ± 28.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] } ], "source": [ "%timeit matmul(ta, tb)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Not very fast huh? Now let's try using numpy's built in matrix multiplication function `np.dot` instead." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "515 µs ± 10.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" ] } ], "source": [ "%timeit np.dot(ta, tb)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "That is approximately 1500 times faster than the native version (on the test computer, anyway)!!. What about other list\n", "operations? Lets try the sum function:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "47.5 µs ± 2.28 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" ] } ], "source": [ "%timeit sum(ta)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12.9 µs ± 1.93 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n" ] } ], "source": [ "%timeit np.sum(ta)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Also a clear improvement. Because of its speed, Numpy should always be used instead of native Python wherever possible." ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Adapting Python code to Numpy\n", "\n", "Although simple multiplications and sums are easier to perform using Numpy functions than native Python, the other is\n", "true in a lot of situations where more specific processing is needed.\n", "\n", "Let's start by adapting our `norm` function to numpy. Numpy supports many elementwise operations, all implemented as\n", "overloads of the traditional operators. To lift all elements of a numpy array to the $n$'th power, simply use the `**`\n", "operator.\n", "\n", "### Task F)\n", "1. Implement norm_np without using loops or list comprehensions. Numpy has a sum function `np.sum` you can use.\n", "2. Test it on the provided vector" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "def norm_np(v):\n", " # PLACEHOLDER <<\n", " # ...\n", " # >>\n", " # SOLUTION <<\n", " return ((v**2).sum())**(1/2)\n", " # >>" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "7.3484692283495345" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vec = np.array([2, 3, 4, 5])\n", "norm_np(vec)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Again, we compare the Python and Numpy implementations using an array of random numbers:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "vr = np.random.randint(100, size=10000)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "16.8 µs ± 2.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", "5.09 ms ± 693 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", "3.46 ms ± 580 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], "source": [ "%timeit norm_np(vr)\n", "%timeit norm(vr)\n", "%timeit norm2(vr)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Once again a huge difference between Numpy and Python (with the Python loop and list-comprehension versions being\n", "approximately equal)." ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "## Useful Numpy tricks\n", "We end this exercise by introducing a few essential Numpy tricks that will make coding with Numpy much easier\n", "(and faster).\n", "\n", "### Comparison operators\n", "Just as the elementwise arithmetic operators, Numpy implements elementwise comparison operators. For example, if we\n", "wanted to find elements of `vr` larger than $98$ we can use the following code:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "array([False, False, False, ..., False, False, False])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vr > 98" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "In itself this isn't super useful. Luckely, Numpy supports a special indexing mode using an array of booleans to\n", "indicate which elements to keep.\n", "\n", "To get the actual values we simply insert the comparison code into the index operator for the array:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "array([99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n", " 99, 99, 99])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vr[vr > 98]" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Finally, we can combine boolean arrays by using the logical operators `&` and `|`" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 1, 99, 0, 0, 0, 1, 99, 1, 1, 1, 1, 0, 0, 99, 0,\n", " 1, 1, 1, 99, 99, 0, 1, 1, 99, 0, 99, 99, 1, 1, 99, 1, 99,\n", " 0, 0, 1, 1, 1, 99, 0, 99, 99, 99, 99, 1, 1, 1, 1, 0, 1,\n", " 99, 99, 0, 99, 1, 99, 1, 99, 99, 1, 0, 99, 0, 0, 99, 99, 0,\n", " 99, 1, 99, 99, 1, 0, 0, 0, 99, 99, 1, 1, 1, 1, 99, 0, 0,\n", " 0, 1, 0, 1, 99, 0, 1, 1, 0, 1, 99, 1, 99, 1, 1, 99, 99,\n", " 99, 0, 99, 99, 1, 1, 0, 99, 99, 99, 99, 99, 1, 99, 0, 1, 1,\n", " 99, 0, 99, 99, 1, 99, 1, 99, 1, 0, 99, 1, 0, 1, 0, 1, 0,\n", " 1, 0, 1, 1, 1, 99, 1, 1, 99, 99, 99, 0, 99, 0, 1, 0, 1,\n", " 99, 0, 99, 99, 0, 1, 0, 99, 1, 0, 0, 1, 1, 1, 0, 99, 1,\n", " 99, 0, 99, 99, 0, 1, 0, 99, 99, 1, 1, 99, 1, 0, 0, 1, 99,\n", " 1, 1, 1, 0, 0, 1, 99, 0, 99, 0, 1, 99, 0, 99, 1, 99, 99,\n", " 99, 0, 1, 1, 99, 0, 99, 0, 0, 99, 99, 99, 1, 1, 99, 1, 0,\n", " 99, 99, 0, 0, 0, 99, 0, 1, 99, 99, 99, 99, 1, 0, 99, 99, 1,\n", " 99, 0, 0, 1, 1, 1, 1, 99, 0, 1, 0, 99, 99, 99, 99, 99, 1,\n", " 99, 99, 1, 99, 99, 99, 99, 99, 1, 99, 0, 1, 0, 99, 99, 99, 99,\n", " 99, 99, 0, 1, 0, 99, 1, 0, 1, 99, 99, 99, 99, 99, 99, 1, 0,\n", " 99, 0, 1, 0, 0, 99, 99, 1, 99, 0, 1, 99])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vr[(vr < 2) | (vr > 98)]" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "These tricks also work for assignment:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "array([ 0, 5, 3, 17, 35, 0, 0, 0, 0, 44])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vr[vr > 50] = 0\n", "vr[:10]" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "### Operate along dimensions\n", "You will often create operations on arrays that contain multiple instances grouped together. For example, in machine\n", "learning, you often concatenate input vectors into matrices. In these instances you may want to perform operations along\n", "only one or some of the array axes.\n", "\n", "As an example, let's try to calculate the average of $N$ random vectors. We define an $N\\times K$ matrix of random\n", "values:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "N, K = 20, 10\n", "r = np.random.uniform(size=(N, K))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "Numpy provides a function `np.mean` for calculating averages. Using the `axis` argument, we specify that the average\n", "should be calculated over the rows:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "array([0.48741618, 0.53653589, 0.6221141 , 0.44965224, 0.53989127,\n", " 0.38464317, 0.54081028, 0.54825065, 0.44834191, 0.41510535])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(r, axis=0)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "The `axis` argument is supported by most of Numpy's functions, including `sum` and `sqrt`." ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.5" } }, "nbformat": 4, "nbformat_minor": 4 }