# Notes pour Cama Je m'excuse par avance pour les fautes d'orthographe, pour ce qui est du contenu numpy, je me relis le plus possible mais le risques de fautes est toujours présent, dans le doute, consultez la man page ## Tips sympa ### Accéder à une man page en exam :D Dans un terminal python: ```py >>> import numpy as np >>> import numpy.linalg as lin # format généralement utilisé sur moodle >>> help(np. 'appuyer sur tab pour voir les propositions') >>> # Par exemple : >>> help(np.arange) # affiche la man page de la fonction arange >>> help(lin) # affiche la man page du module linalg >>> help(np.float32) # information sur la classe en question ``` Cette man page est votre amie, chérissez la. Il aussi notable que beaucoup de fonctions sont directement applicables sur les objets numpy, Par exemple: ```py # A est un array numpy A.sum() # est strictement équivalent à np.sum(A) ``` CEPENDANT, certaines méthodes sont propres à certaines structures. Donc, si vous ne trouvez pas la méthode cherchée avec l'aide de 'help(np. ...)' Essayez de regarder la man page de la structure de donnée avec laquelle vous travaillez (par exemple 'help(np.ndarray)') ## Récap des cours ### ma1 np01: Intro Numpy #### Les dtypes: * bool * int, int8/16/32/64 * uint, uint8/16/32/64 * float, float8/16/32/64 * complex, complex64/128 Dans le doute, vous pouvez utiliser la fonction 'type()' de python #### Les tableaux/matrices/tensor: ##### Les basics : ```py pyton_list = [...] a = np.array(python_list) # création avec une list python a = np.arange(4, dtype=np.uint8) # array([0,1,2,3]) de type uint8 a.dtype # uint8 b = a.astype('float32') # crée une copie de a où les éléments sont convertis en float32 b.nbytes # = 16 car 4 éléments de 4 bytes b[0].itemsize # = 4 car un float fait 4 bytes b.reshape(2,2) # un tableau 2x2 de floats (voir man page pour plus de precisions) b.flatten() # transforme b en un tableau 1d c = np.empty((2,2), dtype=float) # (2,2) correspond aux dimensions du tableau sortant # de plus empty signifie que les valeurs ne sont pas initialisées => plus rapide # Alternatives à empty et arrange: c = np.zeros((2,2), dtype=float) # remplis avec des 0 c = np.ones((2,2), dtype=complex) # remplis avec des 1 c = np.full((2,2), 3.2) # remplis avec des 3.2 c = np.random.random(size=(3,4)) # créer une matrice (tableau 2d) 3x4 avec des valeurs aléatoires # Regardez help(np.random. 'tab') pour voir les différentes fonctions et choisir # la loi aléatoire qui nous est utile np.random.permutation() # mélange le tableau # cas où l'on veut permuter tous les éléments du tableau indépendamment de la dimention np.random.permutation(c.flatten()).reshape(c.shape) id = np.identity(10) # matrice identité 10x10 np.fromfunction(f, shape=(3,4), dtype=int) # créer un tableau à partir d'une fonction # ici le tableau est de dimension 2, f devra prendre 2 paramètre (par ex, def f(i,j): ...) ``` ##### Les essentiels: ```py # Gestion de la forme a = np.arange(8) b = a.reshape(2,2,2) # check l'organisation du tableau sur le notebook b.flat[index] # TRES PRATIQUE, permet d'indexer comme ci b était 1d # .flat revient à faire un flatten puis reshape avec la shape d'origine b.shape # = (2,2,2) # Opération des bases sur tableaux: A = np.array([[1,2], [3,4]]) A+1 # fait +1 sur tous les éléments A*3 # fait *3 sur tous les éléments ... A*A # <=> np.square(A), produit d'Hadamard A @ A # <=> A.dot(A), produit matricielle A+A # <=> addition matricielle A.T # <=> A.transpose() # Les opérations mathématiques de bases: np.round(A) # arrondie np.sqrt(A) # racine carrée np.sin(A) # applique la fonction sinus sur tous les éléments de A # possède des fonctions trigonométrique, hyperboliques, exposant, log ... ``` ##### Les essentiels 2 (jsp pas comment nommer des titres): ```py A = np.arange(10) # = [0,1,2, ..., 9] np.sum(A) # somme sur les élém de A np.prod(A) # produit sur les élém de A np.mean(A) # moyenne de A np.average(A) # moyenne pondérée de A np.min(A) # valeur min de A np.max(A) # valeur max de A np.argmin(A) # indice de la valeur min de A np.argmax(A) # indice de la valeur min de A np.maximum(arr1, arr2) # pour avoir le tableau des maximums entre 2 tableaux ou entre un tableau et une valeur, np.minimum(arr1, arr2) # pour avoir le tableau des maximums entre 2 tableaux ou entre un tableau et une valeur, np.cumsum(A) # si A = [e_0, e_1, ..., e_n] alors cumsum = [e_0, e0+e1, e_0+e_1+e2, ..., somme de e_0 à e_n] np.cumprod(A) # comme cumsum mais on travaille avec des produits np.diff(A) # pour avoir l'écart avec l'élément suivant (utile pour calculer une dérivée). ``` ### ma1 np02: Filtres Bon, les listes en python (/array numpy car fonctionne de la même manière), niveau indexage, on peut faire un peu n'importe quoi Je vais présenter les fonctionnalités de bases mais n'hésitez pas à voir ca de votre côté avec vos propres exemples #### Les bases: Ce qu'on peut mettre entre les '[]' d'une liste/array: * un entier i; si positif correspond au ième indice, si négatif on commence par la fin du tableau (tab[-1] = tab[len(tab) - 1] aka le dernier elem) * une liste d'indice [i, j, k]; tab[[i,j,k]] renvoie un tableau avec les éléments aux indices i, j et k * une séquence 'debut:fin:saut'; debut inclut, fin exclut (comme pour les boucles for), permet par exemple de récupérer tous les indices impaires en faisant tab[1::2] * un tableau de booléen de même taille que le tableau souhaité; si tab = [1,2,3], faire tab[[True, True, False]] donnera [1,2]. !! ATTENTION !! cette notation ne fonctionne pas avec les listes python (pas de soucis concernant les arrays numpy) ```py # les exemples données sont ceux du notebook a = np.arange(12).reshape(3,4) print(a, '\n') # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] print(a[1, :], '\n') # 2nd line # [4 5 6 7] print(a[0:2, 0:2], '\n') # top left sub-matrix # [[ 0 1] # [4 5] print(a[::2, -1], '\n') # even lines, last column # [3 11] print(a[:, [0,-1]]) # first and last column # [[ 0 3] # [ 4 7] # [ 8 11]] # ATTENTION a[i][j] # et a[i,j] # Peuvent sembler similaires, et dans le cas des entiers c'est généralement le # cas, (du moins je n'ai pas trouvé de contre exemple) # Cependant, lorsque l'on travaille avec d'autres outils que les indices brutes # (par exemple les ':') les notations ne sont plus équivalentes; a[:, j] != a[:][j] # je vous conseille de travailler avec la notation [,] # c'est généralement la plus pratique mais prenez ce que vous comprenez le mieux ``` #### Les filtres logiques Ces filtres vont créer des tableaux de booléens, comme dit ci-dessus, ces tableaux sont utiles pour numpy mais ils ne sont pas utilisables sur les listes python ```py a = np.array([i for i in range(5)] # a = array([0,1,2,3,4]) filtre = (a%2==0) # les parenthèses sont préférables mais pas obligatoires # filtre = array([True, False, True, False, True]) a[filtre] # = array([0,2,4]) # filtre étant un tableau, on peut déterminer certaines info sur a: filtre.sum() # cmb d'élément de a vérifie la condition de filtre filtre.any() # vérifie si au moins une valeur est à true filtre.all() # vérifie si toutes les valeurs sont à true filtre.prod() == 0 # vérifie si un cas est faux filtre.sum() == 0 # vérifie si tous les cas sont faux # On peut biensur faire des opérations sur les éléments de a qui respectent les conditions d'un filtre, par exemple: a[filtre ^ True] += 1 # ajoute 1 à tous les nombres impaires # l'opérateur ^ est l'opérateur Xor # filtre ^ True => transforme les True en False et vice versa # on peut aussi utiliser les opérateurs booléens | et & (or, and) # => nécessite des '()' entre chaque segment, i.e: filtre = a>2 & a%2==0 # non valide filtre = (a>2) & (a%2==0) # valide ``` #### La fonction where Permet de réaliser un ternaire sur chaque élément d'un tableau ```py np.where(a > 5, a, 0) # a if a > 5 else 0 # On peut donc utiliser des filtres comme premier param ``` ### ma1 np03: Manipulation Cette partie est très bien expliquée sur le notebook, de plus cette partie comporte bcp de fonctions, la man page est très bien détaillée avec des exemples pertinents. Tout ca pour vous dire que j'ai la flemme de faire des exemples pour chacune des fonctions Je vais me contenter de faire un listing des fonctions qui supportent les axes pour passer plus de temps sur les nouvelles fonctions #### Les axes: Un tableau a des axes qui correspondent aux axes d'un repère dans l'espace. L'ordre des axes est celui de l'inclusion des crochets. En 2D un tableau de tableau est un tableau de lignes avec chaque ligne qui est un tableau 1D de valeurs. L'ordre est donc lignes puis colonnes (contrairement à l'axes (𝑥,𝑦) dans l'espace). En 3D l'ordre est ligne, colonne, profondeur si on désire avoir une image, sinon c'est 0, 1 et 2. De très nombreuses opérations sur les tableaux se font suivant un des axes du tableau aussi il est important de comprendre ce que sont les axes. (oui c'est un copié collé du cours j'en ai rien à foutre) #### Les fonctions 'classiques' qui supportent les axes: * arithmétiques : sum, prod, cumsum, cumprod * statistiques : min, max, argmin, argmax, mean (moyenne), average (moyenne pondérée), std (écart type), var, median, percentile, quantile * autres : gradiant, diff, fft (ps: dans le court il est noté 'gradiant' mais je crois que c'est 'gradient', car help(np.gradiant) n'existe simplement pas) #### Les fonctions de manipulations (enfin): Les nouveautés: ```py # Application de fonctions array_ = np.arange(2*4*3).reshape((2,4,3)) np.apply_along_axis(function_name, axis=-1, arr=array_) # applique function_name sur le dernier axe de array_, le dernier axe va donc disparaitre array_.max(axis=(1,2)) # on peut spécifier plusieurs axes np.apply_over_axes(...) # s'applique sur plusieurs axes # Réorganisation d'un tableau np.moveaxis(array_,2,0) # permet de déplacer un axe (wow) array_.shape # égale à (3,2,4) array_.swapaxes(1,2) # je crois que vous avez compris (sinon help(np.swapaxes)) array_.transpose((2,0,1)) # met l'axe 2 en place 0, 0 en place 1 et 1 en place 2 # transpose réorganise les axes comme on veut, on peut faire un peu ce qu'on veut avec np.flip(array_, n) # où n est un entier positif, cette ligne est équivalente à: # a[:,:,..,::-1,:,..,:] avec ::-1 en nième position => permet d'inverser les valeurs # d'un tableau suivant un axe np.roll(array_, 2, axis=1) # fait glisser les éléments de 2 indices le long de l'axe 1 array_.T # transposée de array_ #Concaténation: a = np.zeros((2,3)) b = np.ones((2,3)) np.concatenate((a,b), axis=0) # deplus, vous pouvez directement utiliser les fonctions vstack/row_stack ou hstack/column_stack # ou dstack (travail en profonduer) pour travailler sur des axes spécifiques # Empilage # A la différence de la concaténation, l'empilage ajoute une dimension. Empiler est utile # pour stocker un paquet de tableaux 2D, des images par exemple, dans un tableau 3D np.stack((a,b)) # stack() possède un paramèter axis au besoin #Découpage: e,f = np.split(c, 2, 1) # split en 2 le long de l'axe 1 # split est la fonction inverse de la concaténation, comme concatenate, split possède les # variantes : hsplit, vsplit et dsplit (découpe suivant les axes 0, 1 et 2) ``` ### ma1 np05 (rip np04): Notation d'Einstein Pour être 100% honnête je ne maitrise que très peu cette notation qui relève très clairement de la magie noire. Voici une très bonne vidéo qui récapitule cette notation en 5min: https://www.youtube.com/watch?v=ULY6pncbRY8 Une autre vidéo, avec un peu plus d'exemple est qui est tout aussi bien: https://www.youtube.com/watch?v=pkVwUVEHmfI&t=785s La man page de help est aussi très complète. La manière de faire la plus simple reste d'écrire un pseudo code avec des boucles for, puis de re-écrire avec la notation Einstein. #### Formule essentiels + exemple Rappel: Voici la formule pour calculer C[i,j], avec C = A @ B où A est de dimension i*k et B de dimension k*j: $$C_{ij} = \sum_1^k A_{ik} \times B_{kj}$$ | Signature de einsum | Équivalent NumPy | Description | |---------------------|-----------------|-------------| | `('i->', v)` | `sum(v)` | Somme des valeurs du vecteur v | | `('i,i->i', u, v)` | `u * v` | Multiplication des vecteurs u et v élément par élément | | `('i,i', u, v)` | `inner(u, v)` | Produit scalaire de u et v | | `('i,j', u, v)` | `outer(u, v)` | Produit dyadique de u et v | | `('ij', A)` | `A` | Renvoie la matrice A | | `('ji', A)` | `A.T` | Transposée de A | | `('ii->i', A)` | `diag(A)` | Diagonale de A | | `('ii', A)` | `trace(A)` | Somme de la diagonale de A | | `('ij->', A)` | `sum(A)` | Somme des valeurs de A | | `('ij->j', A)` | `sum(A, axis=0)` | Somme des colonnes de A | | `('ij->i', A)` | `sum(A, axis=1)` | Somme des lignes de A | | `('ij,ij->ij', A, B)` | `A * B` | Multiplication des matrices A et B élément par élément | | `('ij,ji->ij', A, B)` | `A * B.T` | Multiplication des matrices A et B transposée élément par élément | | `('ij,jk', A, B)` | `dot(A, B)` | Produit scalaire de A et B | | `('ij,jk->ij', A, B)` | `inner(A, B)` | Produit intérieur de A et B | | `('ij,jk->ijk', A, B)` | `A[:, None] * B` | Chaque ligne de A multipliée par B | | `('ij,kl->ijkl', A, B)` | `A[:, :, None, None] * B` | Chaque valeur de A multipliée par B | ### ma1 np06 : Linalg On attaque la partie chiante; faire des maths. Il n'y a pas énormément de fonctions dans le module linalg à connaitre mais au vu des exercies d'entrainement vous devez connaitre le sens mathématiques des objets avec lequels vous travaillez. #### Petits rappels: ```py A = np.array([[1,2],[3,4]]) B = np.array([[1,2],[3,4]]) A @ B # produit matriciel <=> A.dot(B) A * B # produit d'Hadamard ``` #### De l'algèbre linéaire youpi ! ```py b = np.array([17,37]) x = lin.solve(A,b) # résoud un système d'équation linéaire (matricielle ou scalaire) # x = [3. , 7.] A @ x # = [17. 37.] = b lin.inv(A) # matrice inverse # x = lin.inv(A).dot(b) A.T # ca ne change pas c'est toujours la transposée # Extractions: np.diag(A) # renvoie la diagonale de la matrice np.tril(A) # matrice triangulaire inférieur (l pour lower) np.triu(A) # matrice triangulaire supérieur np.tri(3) # créer une matrice 3*3 triangulaire avec des 0 et des 1 Q,R = lin.qr(A) # alors là ... jsp lin.eig(A) # donne valeurs propres et vecteurs propres de A lin.det(A) # determinant de A lin.norm(A) # norme 2 lin.norm(A, 1) # norme 1 lin.cond(A, 2) # conditionnement, encore une fois jsp ce que c'est... pour le 2, je sais encore moins ``` Voilà voilà, si vous pensez qu'il manque qlq chose n'hésitez pas à me le faire remonter. Je ne me répéterais jamais assez mais il y a surement des fautes (surtout niveau orthographe), pensez bien à toujours regarder la man page si vous avez le moindre doute, sinon demandez moi directement :)