Numpy et Matplotlib: deux librairies Python pour le calcul numérique
31 janvier 2016
Python possède des librairies dédiées au calcul numérique. Nous proposons de découvrir Numpy et Matplotlib.
1 Un nouvelle classe d’objets : les tableaux «numpy»
• Introduction
Pour représenter des listes de nombres ou des matrices, nous avons utilisé jusqu’à présent les «listes»
Python, par exemplet = [5, 2, 4, 1]. Nous pouvons ajouter des nombres à ces listes avec la méthode append (par exemple, après avoir exécutét.append(8), la listetvaut alors[5, 2, 4, 1, 8]. De plus, les listes Python peuvent contenir des éléments de types différents, par exemple[4, 3.1, ’cou’]contient un entier, un flottant et une chaîne de caractères. Cette souplesse permise par Python est appréciable dans bien des situations, mais elle ne permet pas des calculs numériques efficaces.
La librairienumpy(provient de «numeric» et «Python») propose des tableaux de typendarrayque nous appelerons tableaux «numpy» adaptés au calcul numérique.
Il faut au prélable importer la librairie numpy, l’usage étant de la rebaptisernp.
>>> import numpy as np
On crée un tableau «numpy» avec la fonctionnp.array(en anglais «array» signifie tableau).
>>> t = np.array([5, 2, 4, 1])
>>> print(type(t))
<class ’numpy.ndarray’>
Le type renvoyé estndarrayqui signifie «n-dimensional array», c’est-à-dire «tableau àndimensions». Ici tne possède qu’une dimension. Une matrice sera un tableau à deux dimensions. Par exemple
In : A = np.array([[1 , 2, 3], [4, 5, 6]]) # crée une matrice à deux lignes et trois colonnes In: print(A)
Out :
array([[1, 2, 3], [4, 5, 6]])
In : A.ndim # donne la dimension du tableau A Out: 2
Remarque : une image numérique RGB sera codée par une «matrice de pixels» dont le coefficient d’indice (i, j) est un triplet de nombres (r, g, b) définissant l’intensité en rouge, vert et bleue du pixel en position (i, j) . Cela pourra être représenté par un tableau numpy à 3 dimensions.
• Accès aux éléments : comme avec les listes. Par exemple, t[0]vaut 5 etA[0][1]vaut 2.
Le slicing fonctionne aussi. Par exemple, t[ : 2]renvoie [5,2]les deux premiers éléments det.
Signalons que des syntaxes particulières sont permises : par exemple A[0,1] correspond à A[0][1] et l’instructiont[ 1, : ]renverra toute la ligne deAd’indice 1 donc[4, 5, 6].
• On obtient le format du tableau avec la méthodeshapequi renvoie un tuple :
In : t.shape
Out: (4,) # 4 lignes (donc un vecteur colonne) In : A.shape
Out: (2, 3) # 2 lignes et 3 colonnes
Remarque : si l’on ne connaît pas shape, on peut s’en sortir avec la fonctionlen In : len(t)
Out: 4
In : len(A) # nombre de lignes Out: 2
In : len(A[0]) # nombre de colonnes Out: 3
• Objet mutable : on modifie les éléments comme pour les listes.
In : t[0] = 9 In : t
Out: array([9, 2, 4, 1])
• Attention aux copies. Comme tout objet mutable en Python, l’affectation t2 = tne va pas réaliser une copie de t.
t
Out: array([5, 3, 4, 1]) In : t2 = t
In : t2[0] = 7 In : t
Out: array([7, 3, 4, 1] # contamination de t)
Les variablestett2sont deux étiquettes d’un même objet (on dit qu’elles pointent vers le même objet).
On utilisera copy.deepcopypour faire des copies «profondes» de tableau.
• Première différence fondamentale avec les listes : les éléments d’un tableau «numpy» ont nécessairement le même type.
Par exemple, l’instruction for x in t:
print(type(x))
affiche quatre fois<class ’numpy.int32’>. Les éléments detsont des entiers relatifs codés sur 32 bits.
Si l’on affecte un flottant à ce tableau, il sera converti en «entier 32 bits».
In : t[0] = 5.3 In : t
Out: array([5, 2, 4, 1])
On peut choisir le type des données avec l’argument dtype. Par exemple, np.array([2,1,3], dtype
= ’uint8’) est un tableau dont les éléments sont des entiers naturels codés sur 8 bits (uint signifie
«unsigned integer»).
Attention aux dépassements de capacité dans ce cas : In : A = np.array([254 , 255, 3], dtype = ’uint8’)
In : A+1 # C on ajoute 1 à tous les coefficients du tableau Out: array([255, 0, 4], dtype=uint8)
Le plus grand entier naturel représenté sur 8 bits est bien 28−1 = 257.
Out: B= array([126, 127, 1], dtype=int8) In: B+1
Out: array([ 127, -128, 2], dtype=int8)
Le plus grand entier relatif représenté sur 8 bits est bien 27−1 = 127.
• Deuxième différence fondamentale avec les listes : les tableaux numpy ont une longueur fixée. En particu- lier, on ne peut pas ajouter d’éléments.
In : t.append(5)
---
AttributeError Traceback (most recent call last)
<ipython-input-67-9262fbb92a36> in <module>() ----> 1 t.append(5)
AttributeError: ’numpy.ndarray’ object has no attribute ’append’
• Quelques fonctions utiles
Les fonctions np.arangeet np.linspace:
In : np.arange(1,11) # les entiers de 1 à 10
Out: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
In :np.linspace(0,1,5) # 5 valeurs uniformément distribuées entre 0 et 1 Out: array([ 0. , 0.25, 0.5 , 0.75, 1. ])
La fonction np.zeros pour créeer des tableaux de zéros.
In : np.zeros((3,2)) Out :
array([[ 0., 0.], [ 0., 0.], [ 0., 0.]])
• Les tableaux numpy sont adaptés à la «vectorisation des calculs» (comportement par défaut dans les logiciels de calcul numériques comme Scilab).
Les opérations arithmétiques se font coefficients par coefficients.
In : t
Out: array([5, 3, 4, 1]) In : t+1
Out: array([6, 4, 5, 2])
In : t + t # ce n’est pas de la concaténation Out: array([10, 6, 8, 2])
In : t * t # ce n’est pas le produit matriciel Out: array([25, 9, 16, 1])
On parle aussi de «mapage» :
In : np.sin(t) # applique sinus à tous les coefficients de t Out: array([-0.95892427, 0.14112001, -0.7568025 , 0.84147098]) In : np.sum(t) # somme des éléments de t
Out: 13
Remarque : la vectorisation des calculs évite l’utilisation de boucles et permet un gain de rapidité consi- dérable.
1.0 0.5 0.0 0.5 1.0 1.5 2.0 1.0
1.5 2.0 2.5 3.0 3.5 4.0
1.0 0.5 0.0 0.5 1.0 1.5 2.0
mes abscisses 1.0
1.5 2.0 2.5 3.0 3.5 4.0
mes ordonnées
courbe d'équation y=f(x)
Figure 1 – Ma première ligne brisée
2 Découverte de la librairie matplotlib.pyplot
On pourra au besoin consulter ce tutoriel en français :http://matplotlib.free.fr. Le principe est simple : on crée une liste d’abcisses, une liste d’ordonnées et on demande de tracer les points de coordonnées correspon- dantes. Par défaut, les points tracés sont reliés par des segments de droite, ce qui donne une courbe. On peut demander aussi à ce que les points ne soients pas reliés, on obtient un nuage de points.
Par exemple, en exécutant le script suivant, on obtient un premier graphique.
import matplotlib.pyplot as plt
X = [-1, 0, 1, 2] # la liste des abscisses Y = [3, 2, 4, 1] # la liste des ordonnées plt.plot(X, Y) # pour créer le graphique plt.show() # pour afficher le graphique
Si l’on insère les commandes suivantes, on complète le premier graphique.
plt.grid() # pour créer une grille plt.xlabel("mes abscisses")
plt.ylabel("mes ordonnées")
plt.title("courbe d’équation $y =f(x)$")
Pour tracer une courbe, il suffira donc de placer un «grand» nombre de points.
Nous vous proposons de découvrir d’autres fonctionnalités en TD, citons par exemple :
• remplacer la ligne plt.plot(X, Y)parplt.plot(X, Y,’g-’). Dans le troisième argument de la fonction plot, lebsignifie blue et donc code la couleur et le tiret-représente le style de la courbe. On peut utiliser les différents styles ce courbes suivants :[’-’, ’–’, ’-.’, ’:’]
• Pour créer unnuage de points: remplacer la ligne plt.plot(X, Y)parplt.plot(X, Y,’r.’). Dans le troisième argument de la fonction plot, lersignifie red et donc code la couleur et le point.représente le marqueur de points.
On peut utiliser les différents marqueurs de points suivants :marqueurs = [’o’, ’+’, ’.’, ’x’, ’*’]
Pour terminer, illustrons ce texte par le tracé du cercle trigonométrique. Pour cela, on trace «beaucoup» de points de coordonnées (cost,sint) avectdécrivant [0,2π].
Apprécions l’utilisation de la «vectorialisation» :
1.0 0.5 0.0 0.5 1.0 1.0
0.5 0.0 0.5 1.0
Figure2 – Mon premier cercle
T = np.linspace(0,2*np.pi,200) # mes 200 abscisses entre 0 et 2pi Xdisk = np.cos(T) # vectorisation, on applique cos au tableau numpy Ydisk = np.sin(T)
plt.plot(Xdisk,Ydisk, ’b’) plt.show()