{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\"Alle Teilnehmer:innen biologischer Profilmodule werden zur Studienleistung angemeldet.\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Numpy introduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# numpy basics and creating arrays\n", "\n", "Numpy is a widely used library for handling arrays of data, especially numerical data. It would not be an exageration to say it is fundamental to the Python data science ecosystem.\n", "\n", "The most important part of numpy is the numpy `array` type. A numpy `array` is conceptually similar to a Python `list` or `tuple` but each element has the same data type and the array has a fixed size.\n", "\n", "Typically `numpy` is imported as `np`, a conventional shorthand that saves a bit of typing." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can create an array from any sequence type, such as lists and tuples:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([1,2,3,4])\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can crate an array of `n` elements (from `0` to `n-1`) with the `arange` function." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(10)\n", "x" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 5, 6, 7, 8, 9])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(4,10)\n", "x" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(0,10,1)\n", "x" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 6, 8])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(4,10,2)\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can create an array of `n` equally spaced elements from `start` to `stop` with `np.linspace`. For example, here `start` is `100`, `stop` is `120` and `n` is 11." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([100., 102., 104., 106., 108., 110., 112., 114., 116., 118., 120.])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linspace(100, 120, 11)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also create arrays of zero or one with a given shape:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0., 0., 0.])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.zeros((3,))" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0.]])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.zeros((3,5)) # shape parameter - (number of rows, number of columns) in this case" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 1., 1.],\n", " [1., 1., 1.],\n", " [1., 1., 1.],\n", " [1., 1., 1.],\n", " [1., 1., 1.]])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.ones((5,3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## array shape\n", "\n", "In addition to 1 dimensional numpy arrays which are very similar to lists or tuples, numpy arrays may also be 2 or more dimensions. The `shape` attribute of a numpy array may be used to get or set its number of dimensions and size." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(12)\n", "x" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(12,)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.shape" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11]])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(12)\n", "x.shape = (3,4)\n", "x" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3, 4)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.shape" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "cannot reshape array of size 12 into shape (3,2)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[20], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m x\u001b[38;5;241m.\u001b[39mshape \u001b[38;5;241m=\u001b[39m (\u001b[38;5;241m3\u001b[39m,\u001b[38;5;241m2\u001b[39m)\n", "\u001b[0;31mValueError\u001b[0m: cannot reshape array of size 12 into shape (3,2)" ] } ], "source": [ "x.shape = (3,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `ndim` attribute is the dimensionality of the array (and, thus, equal to length of the array's `shape` attribute):" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.ndim" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[[ 0, 1],\n", " [ 2, 3]],\n", "\n", " [[ 4, 5],\n", " [ 6, 7]],\n", "\n", " [[ 8, 9],\n", " [10, 11]]])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(12)\n", "x.shape = (3,2,2)\n", "x" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.ndim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## array operations\n", "\n", "Numpy arrays support mathematical operations with other numpy arrays and with single numbers (\"scalars\").\n", "\n", "With scalars, the scalar is first converted to an array with the same shape as the numpy array and then an element-wise operation is performed.\n", "\n", "With other arrays of the same size, an element-wise operation is performed." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(10)\n", "x" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = 2 * np.arange(10)\n", "y" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z = x + y\n", "z" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x + 3" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x + 3.0" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 0.2, 0.4, 0.6, 0.8, 1. , 1.2, 1.4, 1.6, 1.8])" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x/5" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.2" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1/5" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 4, 8, 12, 16, 20, 24, 28, 32, 36])" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "4*x" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.array([ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27])/3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## array dtype\n", "\n", "Just like lists or tuples, every element in a numpy array has a data type. As mentioned above, however, every element in a numpy array has the same data type, and thus we can refer to the \"datatype of the array\". This can be set when the array is created with the `dtype` keyword argument and read from the `dtype` attribute:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(10)\n", "x" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dtype('int64')" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.dtype" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(10, dtype=np.float64)\n", "x" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dtype('float64')" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.dtype" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## array indexing and slicing\n", "\n", "Numpy arrays can be indexed and sliced just like other Python sequence types such as lists, tuples, and strings.\n", "\n", "Just like with python lists, the indices or slices can be read and written. In other words, numpy arrays are *mutable*." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(10)\n", "x" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[4]" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3])" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:4]" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 5, 6, 7, 8, 9])" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[4:]" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3])" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tmp = slice(4)\n", "x[tmp]" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 5, 6])" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tmp = slice(4, 7)\n", "x[tmp]" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 5, 6])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[4:7]" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2, 4, 6])" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tmp = slice(2, 7, 2)\n", "x[tmp]" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2, 4, 6, 8])" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tmp = slice(2, None, 2)\n", "x[tmp]" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([2, 4, 6, 8])" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[2::2]" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 7])" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[4::3]" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([4, 5, 6])" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[4:7]" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "slice indices must be integers or None or have an __index__ method", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[64], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m x[\u001b[38;5;241m2\u001b[39m::\u001b[38;5;241m2.2\u001b[39m]\n", "\u001b[0;31mTypeError\u001b[0m: slice indices must be integers or None or have an __index__ method" ] } ], "source": [ "x[2::2.2]" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 2.2, 4.4, 6.6, 8.8])" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.arange(0, 10, 2.2)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 2, 4, 6, 8])" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[::2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because numpy arrays can have 2 or more, dimensions, we can also index and slice them in higher dimensions. For two dimensional arrays, the first index is always the row index and the second index is always the column index." ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11]])" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(12)\n", "x.shape = (3,4)\n", "x" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11]])" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[1:, :]" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 1, 2, 3],\n", " [ 5, 6, 7],\n", " [ 9, 10, 11]])" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:, 1:]" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 6, 7],\n", " [10, 11]])" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[1:, 2:]" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[4, 5, 6, 7]])" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[1:2:]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11]])" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 99, 99],\n", " [ 8, 9, 99, 99]])" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[1:, 2:] = 99\n", "x" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dtype('int64')" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.dtype" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 99, 99],\n", " [ 8, 9, 99, 99]])" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[1:, 2:] = 99.5\n", "x" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 99, 99],\n", " [ 8, 9, 99, 99]])" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[1:, 2:] = 99.9\n", "x" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[99, 99, 99, 99],\n", " [99, 99, 99, 99],\n", " [99, 99, 99, 99]])" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:, :] = 99.9\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References to arrays\n", "\n", "Remember that variable assignment in Python does not create a new object but only creates a variable which points to an existing object. This is very important with numpy." ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n", " 17, 18, 19])" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(20)\n", "x" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Here we create a variable which references the first 10 elements of `x`.\n", "y = x[:10]\n", "y" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [], "source": [ "x[4] = 9999" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 9999, 5, 6, 7, 8, 9, 10,\n", " 11, 12, 13, 14, 15, 16, 17, 18, 19])" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 9999, 5, 6, 7, 8, 9])" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([123, 123, 123, 123, 123, 123, 123, 123, 123, 123])" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Now we assign all the elements of `y` to have the value of 123.\n", "# We do this by creating a slice into the array `y` and assigning to it.\n", "y[:] = 123\n", "y" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 10, 11, 12,\n", " 13, 14, 15, 16, 17, 18, 19])" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# How does this affect the original array `x`?\n", "x" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [], "source": [ "y[-1] = 999" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([123, 123, 123, 123, 123, 123, 123, 123, 123, 999, 10, 11, 12,\n", " 13, 14, 15, 16, 17, 18, 19])" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [], "source": [ "y[::2] = -1" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ -1, 123, -1, 123, -1, 123, -1, 123, -1, 999, 10, 11, 12,\n", " 13, 14, 15, 16, 17, 18, 19])" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [], "source": [ "x[:3] = -100" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-100, -100, -100, 123, -1, 123, -1, 123, -1, 999, 10,\n", " 11, 12, 13, 14, 15, 16, 17, 18, 19])" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-100, -100, -100, 123, -1, 123, -1, 123, -1, 999])" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [], "source": [ "z = y.copy()" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-100, -100, -100, 123, -1, 123, -1, 123, -1, 999])" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-100, -100, -100, 123, -1, 123, -1, 123, -1, 999])" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [], "source": [ "y[:2] = -9999" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-9999, -9999, -100, 123, -1, 123, -1, 123, -1,\n", " 999])" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-100, -100, -100, 123, -1, 123, -1, 123, -1, 999])" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [], "source": [ "z = y[:]" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-9999, -9999, -100, 123, -1, 123, -1, 123, -1,\n", " 999])" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-9999, -9999, -100, 123, -1, 123, -1, 123, -1,\n", " 999])" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [], "source": [ "y[:2] = 444444" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([444444, 444444, -100, 123, -1, 123, -1, 123,\n", " -1, 999])" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([444444, 444444, -100, 123, -1, 123, -1, 123,\n", " -1, 999])" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z = np.arange(12)\n", "z" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [], "source": [ "zref = z[::3]\n", "zref[:] = 999" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([999, 1, 2, 999, 4, 5, 999, 7, 8, 999, 10, 11])" ] }, "execution_count": 106, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [], "source": [ "zrefref = zref[::2]\n", "zrefref[:] = -1000" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-1000, 1, 2, 999, 4, 5, -1000, 7, 8,\n", " 999, 10, 11])" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Array *slices* - a key difference between a numpy array and a Python list\n", "\n", "With a numpy array, a slice is created by `[:]` (e.g. `my_array[:]`). With a plain Python list, `[:]` will return a copy of the list.\n", "\n", "For both numpy arrays and Python lists, the `.copy()` method will make a copy, so this is preferred if you want to be sure you are making a copy." ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [], "source": [ "# First with a list\n", "a = [1,2,3]" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [], "source": [ "b = a[:]" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [], "source": [ "a[0] = 100" ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3]" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[100, 2, 3]" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a" ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [], "source": [ "# Now with a numpy array\n", "a = np.array([1,2,3])" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [], "source": [ "b = a[:]" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [], "source": [ "a[0] = 100" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([100, 2, 3])" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([100, 2, 3])" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Efficient data processing with numpy\n", "\n", "Because operations on numpy arrays happen for all elements with a single Python expression, these can operations can be performed very fast and efficiently by the computer. For example, if `x` is a numpy array with 10,000 elements, we can avoid a Python for loop with 10,000 iterations by performing our work with numpy.\n", "\n", "Below we use the Jupyter \"magic command `%timeit`\" to measure how long a single expression takes, in this case performing an element-wise multiplication." ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [], "source": [ "x = np.arange(10000, dtype=np.float64)" ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.0000000e+00, 1.0000000e+00, 4.0000000e+00, ..., 9.9940009e+07,\n", " 9.9960004e+07, 9.9980001e+07])" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x*x" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.6 μs ± 15.2 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\n" ] } ], "source": [ "%timeit x*x" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10000" ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = x*x\n", "len(y)" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [], "source": [ "assert y[2] == 4\n", "assert y[3] == 9" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's do the same as above with a Python `list`. We need to crease a list_mul function." ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [], "source": [ "def list_mul(a,b):\n", " \"\"\"element-wise product of `a` and `b`\"\"\"\n", " n = len(a)\n", " assert n==len(b) \n", " c = []\n", " for i in range(n):\n", " c.append(a[i] * b[i])\n", " return c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now convert `x` to a list from a numpy array." ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [], "source": [ "x = list(x)" ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(x)" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[:10]" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "483 μs ± 24.9 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" ] } ], "source": [ "%timeit list_mul(x,x)" ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [], "source": [ "y = list_mul(x,x)" ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [], "source": [ "assert y[3] == 9" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Elementwise numpy operations\n", "\n", "Above you have already seen element-wise multiplication, which multiplies every element of two inputs. Similarly, other operations operate element wise on a single input array." ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1., 2., 3.])" ] }, "execution_count": 132, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sqrt( np.array([1, 4, 9]))" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 0.21666156, 0.43332312, 0.64998469, 0.86664625,\n", " 1.08330781, 1.29996937, 1.51663094, 1.7332925 , 1.94995406,\n", " 2.16661562, 2.38327719, 2.59993875, 2.81660031, 3.03326187,\n", " 3.24992343, 3.466585 , 3.68324656, 3.89990812, 4.11656968,\n", " 4.33323125, 4.54989281, 4.76655437, 4.98321593, 5.1998775 ,\n", " 5.41653906, 5.63320062, 5.84986218, 6.06652374, 6.28318531])" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linspace( 0, 2*np.pi, 30) " ] }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1. , 0.97662056, 0.90757542, 0.79609307, 0.64738628,\n", " 0.46840844, 0.26752834, 0.05413891, -0.161782 , -0.37013816,\n", " -0.56118707, -0.72599549, -0.85685718, -0.94765317, -0.99413796,\n", " -0.99413796, -0.94765317, -0.85685718, -0.72599549, -0.56118707,\n", " -0.37013816, -0.161782 , 0.05413891, 0.26752834, 0.46840844,\n", " 0.64738628, 0.79609307, 0.90757542, 0.97662056, 1. ])" ] }, "execution_count": 134, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.cos( np.linspace( 0, 2*np.pi, 30) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More numpy operations\n", "\n", "In addition to elementwise operations such as `np.cos(x)` or `x * y` where `x` and `y` are same-shaped arrays, numpy can also perform operations on entire arrays.\n", "\n", "Take for example the `mean()` function." ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(10)\n", "x" ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4.5" ] }, "execution_count": 136, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also do the mean on a 2D array, either for the entire array or row-wise or column-wise:" ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3, 4, 5],\n", " [ 6, 7, 8, 9, 10, 11],\n", " [12, 13, 14, 15, 16, 17],\n", " [18, 19, 20, 21, 22, 23],\n", " [24, 25, 26, 27, 28, 29]])" ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.arange(30)\n", "x.shape = (5,6)\n", "x" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "14.5" ] }, "execution_count": 138, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(x)" ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([12., 13., 14., 15., 16., 17.])" ] }, "execution_count": 139, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# take the mean across the rows, (i.e. mean of each column), which is axis 0.\n", "np.mean(x,axis=0)" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 2.5, 8.5, 14.5, 20.5, 26.5])" ] }, "execution_count": 140, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# take the mean across the columns, which is axis 1.\n", "np.mean(x,axis=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to `mean()`, numpy provides `std()`, `sum()`, and more. " ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8.65544144839919" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.std(x)" ] }, { "cell_type": "code", "execution_count": 142, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "435" ] }, "execution_count": 142, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.sum(x)" ] }, { "cell_type": "code", "execution_count": 143, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "29" ] }, "execution_count": 143, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.max(x)" ] }, { "cell_type": "code", "execution_count": 144, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "14.5" ] }, "execution_count": 144, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.mean()" ] }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "14.5" ] }, "execution_count": 145, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## argmin and argmax\n", "\n", "Important in many scientific computing applications are `argmin` and `argmax` functions. These return the index of the smallest or largest value, respectively." ] }, { "cell_type": "code", "execution_count": 146, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 10, -10, 4, 3, 2, 100, 2, 2, -1])" ] }, "execution_count": 146, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([0, 10, -10, 4, 3, 2, 100, 2, 2, -1])\n", "x" ] }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 147, "metadata": {}, "output_type": "execute_result" } ], "source": [ "min_idx = np.argmin(x)\n", "min_idx" ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-10" ] }, "execution_count": 148, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[min_idx]" ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-10" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.min(x)" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 10, -10, 4, 3, 2, 100, 2, 2, -1])" ] }, "execution_count": 150, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": 151, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 151, "metadata": {}, "output_type": "execute_result" } ], "source": [ "max_idx = np.argmax(x)\n", "max_idx" ] }, { "cell_type": "code", "execution_count": 152, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "100" ] }, "execution_count": 152, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x[max_idx]" ] }, { "cell_type": "code", "execution_count": 153, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 100, 0, 4, 3, 2, 100, 2, 2, -1])" ] }, "execution_count": 153, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([0, 100, 0, 4, 3, 2, 100, 2, 2, -1])\n", "x" ] }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 154, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.argmax(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Because of its speed, numpy makes it possible to use Python for scientific computing.\n", "\n", "You can read more about numpy at its [User Guide](https://numpy.org/doc/1.26/user/index.html) and its [Reference Guide](https://numpy.org/doc/1.26/reference/index.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Live coding example: calculate distance between 2D points." ] }, { "cell_type": "code", "execution_count": 155, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "a = (10, 20)\n", "b = (13, 24)\n", "\n", "plt.plot([a[0]], [a[1]], 'o', label='a')\n", "plt.plot([b[0]], [b[1]], 'o', label='b')\n", "plt.plot([5, 15, 15, 5, 5], [15, 15, 25, 25, 15], 'k-')\n", "plt.legend();" ] }, { "cell_type": "code", "execution_count": 157, "metadata": {}, "outputs": [], "source": [ "def compute_distance(a,b):\n", " dx = a[0] - b[0]\n", " dy = a[1] - b[1]\n", " return np.sqrt(dx*dx + dy*dy)" ] }, { "cell_type": "code", "execution_count": 158, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 158, "metadata": {}, "output_type": "execute_result" } ], "source": [ "compute_distance(a,b)" ] }, { "cell_type": "code", "execution_count": 159, "metadata": {}, "outputs": [], "source": [ "assert compute_distance(a,b)==5.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See also https://twitter.com/MIT_CSAIL/status/1459932891765297153?s=20\n", "\n", "![FEA8OpTWYAAxNjx.png](FEA8OpTWYAAxNjx.png)" ] } ], "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.11.10" } }, "nbformat": 4, "nbformat_minor": 4 }