diff options
Diffstat (limited to 'PVCM/cama/fr/ma1 np01 Numpy Introduction.ipynb')
| -rw-r--r-- | PVCM/cama/fr/ma1 np01 Numpy Introduction.ipynb | 933 |
1 files changed, 933 insertions, 0 deletions
diff --git a/PVCM/cama/fr/ma1 np01 Numpy Introduction.ipynb b/PVCM/cama/fr/ma1 np01 Numpy Introduction.ipynb new file mode 100644 index 0000000..bd593c2 --- /dev/null +++ b/PVCM/cama/fr/ma1 np01 Numpy Introduction.ipynb @@ -0,0 +1,933 @@ +{ + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "## NumPy - An N-dimensional Array manipulations library\n", + "\n", + "[NumPy](https://docs.scipy.org/doc/numpy/user/index.html) est une première boîte à outils pour le développement de programmes scientifiques. Cette\n", + "bibliothèque offre en particulier des tableaux multidimensionnels simples à manipuler et **performants** (ce qui n'est pas le cas des listes de Python).\n", + "\n", + "Il est à noter que l'on retrouve la syntaxe de Numpy pour la manipulation des tableaux dans d'autres langages comme R ou Julia et que les bibliothèques d'IA comme PyTorch, TensorFlow ou JAX utilisent aussi cette syntaxe." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np # np is the convention" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "À la différence des listes, __les tableaux ont toutes leurs valeurs du même type__.\n", + "\n", + "## Création d'un tableau" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[1 2 3]\n", + " [4 5 7]]\n", + "shape: (2, 3)\n", + "type: <class 'numpy.int64'>\n" + ] + } + ], + "source": [ + "a = np.array([[1,2,3], [4,5,7]]) # 2D array built from a list\n", + "print(a)\n", + "print(\"shape: \",a.shape)\n", + "print(\"type: \",type(a[0,0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "### dtype : le choix du type des éléments\n", + "\n", + "Lorsqu'on fait du calcul scientifique il est important de choisir le type des tableaux afin d'optimiser la mémoire, les erreurs, la vitesse.\n", + "\n", + "NumPy propose les types suivants :\n", + "\n", + "<table border=\"1\" class=\"docutils\">\n", + "<colgroup>\n", + "<col width=\"15%\" />\n", + "<col width=\"85%\" />\n", + "</colgroup>\n", + "<thead valign=\"bottom\">\n", + "<tr class=\"row-odd\"><th class=\"head\">Data type</th>\n", + "<th class=\"head\">Description</th>\n", + "</tr>\n", + "</thead>\n", + "<tbody valign=\"top\">\n", + "<tr class=\"row-even\"><td>bool</td>\n", + "<td>Boolean (True or False) stored as a byte</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>int</td>\n", + "<td>Platform integer (normally either <tt class=\"docutils literal\"><span class=\"pre\">int32</span></tt> or <tt class=\"docutils literal\"><span class=\"pre\">int64</span></tt>)</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>int8</td>\n", + "<td>Byte (-128 to 127)</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>int16</td>\n", + "<td>Integer (-32768 to 32767)</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>int32</td>\n", + "<td>Integer (-2147483648 to 2147483647)</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>int64</td>\n", + "<td>Integer (-9223372036854775808 to 9223372036854775807)</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>uint8</td>\n", + "<td>Unsigned integer (0 to 255)</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>uint16</td>\n", + "<td>Unsigned integer (0 to 65535)</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>uint32</td>\n", + "<td>Unsigned integer (0 to 4294967295)</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>uint64</td>\n", + "<td>Unsigned integer (0 to 18446744073709551615)</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>float</td>\n", + "<td>Shorthand for <tt class=\"docutils literal\"><span class=\"pre\">float64</span></tt>.</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>float16</td>\n", + "<td>Half precision float: sign bit, 5 bits exponent,\n", + "10 bits mantissa</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>float32</td>\n", + "<td>Single precision float: sign bit, 8 bits exponent,\n", + "23 bits mantissa</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>float64</td>\n", + "<td>Double precision float: sign bit, 11 bits exponent,\n", + "52 bits mantissa</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>complex</td>\n", + "<td>Shorthand for <tt class=\"docutils literal\"><span class=\"pre\">complex128</span></tt>.</td>\n", + "</tr>\n", + "<tr class=\"row-odd\"><td>complex64</td>\n", + "<td>Complex number, represented by two 32-bit floats (real\n", + "and imaginary components)</td>\n", + "</tr>\n", + "<tr class=\"row-even\"><td>complex128</td>\n", + "<td>Complex number, represented by two 64-bit floats (real\n", + "and imaginary components)</td>\n", + "</tr>\n", + "</tbody>\n", + "</table>" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x = [0 1 2 3] uint8\n", + "x = [254 1 2 3] uint8\n", + "y = [254. 1. 2. 3.] float32\n" + ] + } + ], + "source": [ + "x = np.arange(4, dtype= np.uint8) # arange is the numpy version of range to produce an array\n", + "print(\"x =\", x, x.dtype)\n", + "\n", + "x[0] = -2 # 0 - 2 = max -1 for unsigned int\n", + "print(\"x =\", x, x.dtype)\n", + "\n", + "y = x.astype('float32') # conversion\n", + "print(\"y =\", y, y.dtype)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "On peut connaitre la taille mémoire (en octets) qu'occupe un élément du tableau et l'occupation de tout le tableau :" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "4\n" + ] + }, + { + "data": { + "text/plain": [ + "16" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(x[0].itemsize)\n", + "print(y[0].itemsize)\n", + "y.nbytes" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "### Méthodes prédéfinies\n", + "\n", + "On a déjà vu la méthode `arange` pour créer un tableau, il en existe aussi pour\n", + "créer un tableau vide ou de la dimension de son choix avec que des 0 ou que des 1 ou ce qu'on veut.\n", + "En fait il existe tellement de méthodes qu'on en présente qu'une petite partie ici, pour les autres voir la\n", + "[liste des méthodes de création prédéfinies](https://docs.scipy.org/doc/numpy/reference/routines.array-creation.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Empty float:\n", + " [[2.42350504e-316 0.00000000e+000]\n", + " [4.94065646e-324 nan]]\n", + "Float zeros:\n", + " [[0. 0.]\n", + " [0. 0.]]\n", + "Complex ones:\n", + " [[1.+0.j 1.+0.j 1.+0.j]\n", + " [1.+0.j 1.+0.j 1.+0.j]]\n", + "Full of 3.2:\n", + " [[3.2 3.2]\n", + " [3.2 3.2]]\n", + "La matrice suivante est affichée partiellement car trop grande : \n", + "[[1. 0. 0. ... 0. 0. 0.]\n", + " [0. 1. 0. ... 0. 0. 0.]\n", + " [0. 0. 1. ... 0. 0. 0.]\n", + " ...\n", + " [0. 0. 0. ... 1. 0. 0.]\n", + " [0. 0. 0. ... 0. 1. 0.]\n", + " [0. 0. 0. ... 0. 0. 1.]]\n" + ] + } + ], + "source": [ + "a = np.empty((2,2), dtype=float) # empty do not set any value, it is faster\n", + "print(\"Empty float:\\n\", a)\n", + "\n", + "print(\"Float zeros:\\n\", np.zeros((2,2), dtype=float)) # matrix filled with 0\n", + "\n", + "print(\"Complex ones:\\n\", np.ones((2,3), dtype=complex)) # matrix filled with 1\n", + "\n", + "print(\"Full of 3.2:\\n\", np.full((2,2), 3.2))\n", + "\n", + "print(\"La matrice suivante est affichée partiellement car trop grande : \")\n", + "print(np.identity(1000)) # identity matrix" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "### Avec des valeurs aléatoires\n", + "\n", + "La sous-bibliothèque [`np.random`](https://docs.scipy.org/doc/numpy/reference/routines.random.html) offre des méthodes pour générer des tableaux de valeurs aléatoires." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Random integers < 10:\n", + " [[7 5 7 2]\n", + " [6 7 0 8]\n", + " [6 3 8 3]]\n", + "Random reals between 0 and 1 :\n", + " [[0.45228105 0.39674551 0.02142443 0.14342572]\n", + " [0.95223097 0.85798264 0.85777533 0.28784271]\n", + " [0.5142878 0.36823048 0.87704756 0.44096786]]\n" + ] + } + ], + "source": [ + "print(\"Random integers < 10:\\n\", np.random.randint(10, size=(3,4))) # can also choose a min\n", + "\n", + "print(\"Random reals between 0 and 1 :\\n\", np.random.random(size=(3,4)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "On peut choisir la loi de distribution (loi uniforme par défaut)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1.44216124, 2.5586318 , 4.28770816],\n", + " [2.16814785, 1.82332334, 4.53031302]])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loc = 3\n", + "scale = 1.5\n", + "np.random.normal(loc, scale, size=(2,3)) # Gauss distribution" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "### En redéfinissant sa forme\n", + "\n", + "Un cas classique pour faire des tests est de créer un petit tableau multidimensionnelle avec des valeurs différentes.\n", + "Pour cela le plus simple est de mettre 0,1,2,...,N dans les cases de notre tableau de forme (3,4) par exemple. \n", + "Cela se fait avec `arange` qu'on a déjà vu pour générer les valeurs et `reshape` pour avoir la forme voulue :" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0, 1, 2, 3],\n", + " [ 4, 5, 6, 7],\n", + " [ 8, 9, 10, 11]])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = np.arange(3*4).reshape((3,4))\n", + "arr" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr[1, 0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "Attention, la numérotation des cases d'un tableau est effectuée avec des boucles imbriquées aussi c'est toujours la dernière dimension qui varie le plus vite. En 3D cela veut dire que passer d'un élément au suivant fait varier le dernier indice (suivant z). Cela ne correspond pas à la manière humaine de remplir un cube (on a tendance à faire des empilements de tableaux 2D). À l'usage cela ne pose pas de problème, c'est\n", + "seulement bizarre lorsqu'on affiche des tests pour voir.\n", + "\n", + "```\n", + " humain Numpy\n", + " ┌─┬─┐ ┌─┬─┐ \n", + "┌─┬─┐│5│ ┌─┬─┐│3│\n", + "│0│1│┼─┤ │0│2│┼─┤\n", + "├─┼─┤│7│ ├─┼─┤│7│\n", + "│2│3│┴─┘ │4│6│┴─┘\n", + "└─┴─┘ └─┴─┘ \n", + "``` " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[0, 1],\n", + " [2, 3]],\n", + "\n", + " [[4, 5],\n", + " [6, 7]]])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = np.arange(8).reshape(2,2,2) # a[0,1,0] is 2 and a[0,1,1] is 3\n", + "A" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "L'inverse de reshape est `flatten()` qui transforme un tableau à plusieurs dimensions en un tableau à 1 dimension. On peut aussi utiliser `flat` pour avoir une vue 1D sur le tableau sans le transformer." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "(2, 2, 2)\n" + ] + } + ], + "source": [ + "print(A.flat[5])\n", + "print(A.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "### Mélanger les valeurs\n", + "\n", + "Si on veut travailler avec les valeurs d'un tableau prises dans un ordre aléatoire alors on peut mélanger\n", + "le tableau avec `np.random.permutation()`. Attention la permutation s'effectue sur les éléments du premier niveau du tableau, `A[:]`, à savoir des tableaux\n", + "si le tableau est à plusieurs dimensions (un tableau de tableaux)." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 4, 5, 6, 7],\n", + " [ 8, 9, 10, 11],\n", + " [ 0, 1, 2, 3]])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = np.arange(12).reshape(3,4)\n", + "np.random.permutation(data) # permutes lines only" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "Si on veut mélanger toutes les valeurs il faut applatir le tableau et lui redonner sa forme :" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[10, 3, 11, 8],\n", + " [ 4, 1, 2, 7],\n", + " [ 0, 9, 6, 5]])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = np.random.permutation(data.flatten()).reshape(data.shape) # it works because flatten returns a copy\n", + "data" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "### Avec une fonction de son choix\n", + "\n", + "On peut aussi créer un tableau avec une fonction qui donne la valeur du tableau pour chaque indice (i,j) :" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0, -1, -2, -3],\n", + " [ 2, 1, 0, -1],\n", + " [ 4, 3, 2, 1]])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def f(i,j):\n", + " return 2*i - j\n", + "\n", + "np.fromfunction(f, shape=(3,4), dtype=int)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "## Opérations de base\n", + "\n", + "Numpy permet d'appliquer les [opérations mathématiques](https://numpy.org/doc/stable/reference/routines.math.html) usuelles à tous les éléments des tableaux :" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A + 1:\n", + " [[2 3]\n", + " [4 5]] \n", + "\n", + "2 A + Id:\n", + " [[3. 4.]\n", + " [6. 9.]] \n", + "\n", + "A * A (element-wise product):\n", + " [[ 1 4]\n", + " [ 9 16]] \n", + "\n", + "A @ A (matrix or dot product):\n", + " [[ 7 10]\n", + " [15 22]]\n" + ] + } + ], + "source": [ + "A = np.array([[1,2], [3,4]])\n", + "\n", + "print(\"A + 1:\\n\", A + 1, '\\n')\n", + "print(\"2 A + Id:\\n\", 2 * A + np.identity(2), '\\n')\n", + "print(u\"A * A (element-wise product):\\n\", A * A, '\\n') # or np.square(A)\n", + "print(u\"A @ A (matrix or dot product):\\n\", A @ A) # or A.dot(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "On peut transposer un tableau avec `.T`. Cela ne fait rien avec un tableau en 1D, pour faire la différence entre vecteur horizontal et un vecteur vertical, il faut l'écrire en 2D :" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[1 3 5]] \n", + "\n", + " [[1]\n", + " [3]\n", + " [5]] \n", + "\n", + "Guess what v + v.T means:\n", + " [[ 2 4 6]\n", + " [ 4 6 8]\n", + " [ 6 8 10]]\n" + ] + } + ], + "source": [ + "v = np.array([[1,3,5]])\n", + "print(v, '\\n\\n', v.T, '\\n')\n", + "print(\"Guess what v + v.T means:\\n\", v + v.T)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "On dispose aussi des fonctions trigonométriques, hyperboliques, exposant, logarithme..." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.841, 0.909],\n", + " [ 0.141, -0.757]])" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.set_printoptions(precision=3) # set printing precision for reals\n", + "np.sin(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "Enfin Numpy offre un ensemble de méthodes pour faire des calculs sur les élements du tableau : \n", + "\n", + "* `sum()` pour additionner tous les élements \n", + "* `mean()` pour avoir la moyenne des éléments et `average()` pour avoir la moyenne pondérée, \n", + "* `prod()` pour multiplier tous les élements, \n", + "* `min()` et `max()` pour avoir la valeur minimale et la valeur maximale,\n", + "* `argmin()` et `argmax()` pour avoir les indices des valeurs minimales et maximales du tableau\n", + "* `cumsum()` et `cumprod()` pour les additions et multiplication cumulatives, \n", + "* `diff()` pour avoir l'écart avec l'élément suivant (utile pour calculer une dérivée).\n", + "\n", + "Chaque méthode `A.sum()` existe aussi en fonction `np.sum(A)`." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A.argmax()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 1, 1])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.diff(A.flatten())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "## Parcourir un tableau\n", + "\n", + "La façon naturelle pour parcourir tous les éléments d'un tableau à plusieurs dimensions est de faire une boucle pour chaque dimension :" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0 1\n", + " 2 3\n", + " 4 5\n" + ] + } + ], + "source": [ + "a = np.arange(6).reshape(3,2)\n", + "for ligne in a:\n", + " for element in ligne:\n", + " print(\" \", element, end=\"\") # end=\"\" avoid the return after each print\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "On a vu dans la manipulation de la forme d'un tableau qu'on peut l'applatir, mais plutôt que d'utiliser `flatten()` qui fabrique un tableau en 1 dimension, on préfère utiliser `flat` qui donne [itérateur](https://fr.wikipedia.org/wiki/It%C3%A9rateur) pour parcourir tous les éléments du tableau." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "for v in a.flat:\n", + " print(v)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "Il est aussi possible de faire une boucle sur les indices mais c'est nettement moins performant." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "for i in range(len(a)):\n", + " for j in range(len(a[i])):\n", + " print(a[i,j])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "lang": "fr" + }, + "source": [ + "## Travailler en vectoriel\n", + "\n", + "Faire des boucles correspond souvent à la facon de penser de ceux qui programment depuis longtemps mais ce n'est pas efficace en Python. Il est préférable \n", + "de travailler directement sur le tableau. Ainsi plutôt que de faire la boucle\n", + "\n", + "```\n", + "for i in range(len(x)):\n", + " z[i] = x[i] + y[i]\n", + "```\n", + "\n", + "on fera\n", + "\n", + "```\n", + "z = x + y\n", + "```\n", + " \n", + "Non seulement c'est plus lisible mais c'est aussi plus rapide." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "45.5 ms ± 494 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "35.3 ms ± 139 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "36.9 µs ± 156 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" + ] + } + ], + "source": [ + "def double_loop(a):\n", + " for i in range(a.shape[0]):\n", + " for j in range(a.shape[1]):\n", + " a[i,j] = np.sqrt(a[i,j]) # change in-place\n", + "\n", + "def iterate(a):\n", + " for x in a.flat:\n", + " x = np.sqrt(x) # modification not saved in a, x is a local var\n", + "\n", + "b = np.random.random(size=(200,200))\n", + "a = b.copy() # we need a copy to be sure to use the same data each time\n", + "%timeit double_loop(a)\n", + "\n", + "a = b.copy() \n", + "%timeit iterate(a)\n", + "\n", + "a = b.copy()\n", + "%timeit np.sqrt(a) # vectorial operation, 1000 times faster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ] +}
\ No newline at end of file |
