Informatique : Leçon 9. Le module numpy
Dans la leçon 8, on construit des matrices en les regardant comme des listes de listes, ce qui a demandé de définir toutes les opérations matricielles. Or, le module \(\texttt{numpy}\) est destiné notamment au calcul matriciel et fait le travail. On s'en servira aussi en traitement de l'image.
Une subtilité (ou un point fort) du module : les tableaux peuvent être multidimensionnels. Les matrices sont donc un cas particulier de tableaux multidimensionels.
Importation des modules
import numpy as np # importation prudente
Rappel : avec import vous importez le module. Avec as vous lui donnez un nom de préfixe pour vous rappeler les fonctions provenant du module. Autrement dit : chaque commande utilisée du module numpy est préfixée par np, ce qui permet d'identifier son origine.
Premiers pas avec numpy
La plupart des commandes suivantes sont dans votre aide-mémoire. Les matrices sont des objets de type array . Si on tape simplement :
A = [[1,0,1],[4,2,-8]]
type(A)
list
alors on obtient, comme au TP précédent, une liste de listes. En revanche, si vous déclarez votre liste comme un tableau numpy (en anglais : array) vous obtenez :
A = np.array( [[1,0,1],[4,2,-8]]) # Le préfixe np provient de l'importation print A # prudente du module
[[ 1 0 1] [ 4 2 -8]]
type(A)
numpy.ndarray
Autrement dit, dans le module numpy, c'est la commande np.array qui permet de définir des matrices. L'objet ainsi construitn'est lus un objet de type liste, mais un objet de type tableau multidimensionnel : nd-array. C'est ce genre d'objet qui va être considéré comme une matrice à partir de maintenant.
Taille d'une matrice
Vous la récupérez avec la commande shape (c'est ce qu'on appelle une méthode au sens de la programmation orientée objet. Ce n'est pas vraiment une fonction, ni l'objet (ah ah!) de ce TP. Les méthodes se suffixent aux objets auxquelles elles appliquent, ou sur lesquelles elles opèrent) :
A.shape # C'est pourquoi on n'écrit pas shape(A) : shape est une méthode, pas une fonction
(2, 3)
Le résultat est un tuple. Ici, ce tuple contient 2 items : cela signifie que le tableau est 2-dimensionnel. Enfin, les valeurs des items nous disent que \(\mathtt{A}\) est de taille \(2 \times 3\).
Accès aux coefficients
Les doubles indices sont d'usage. Restriction habituelle de Python : les indices commencent, on s'en doute, à \(0\) :
print A
[[ 1 0 1] [ 4 2 -8]]
Par exemple, pour récupérer \(a_{2,3}=-8\)
A[1,2] # inutile d'utiliser A[1][2]
-8
Extraction d'une ligne ou d'une colonne
De façon plus générale on peut extraire des sous-matrices par tranches :
print A
[[ 1 0 1] [ 4 2 -8]]
Par exemple, si je veux \(\ell_1 =\begin{pmatrix} 1&0&1 \end{pmatrix}\), la première ligne de \(A\) :
A[0,:] # les deux points ":" servent de "joker" si vous voulez. # C'est l'opérateur de spécification par tranche (de slicing).
array([1, 0, 1])
**Attention. ** Vous observez qu'il n'existe plus qu'une paire de crochets : les lignes sont des tableaux 1-dimensionnels, et donc, pas des matrices au sens de tableaux 2-dimensionnels :
ligne = A[0,:] print ligne
[1 0 1]
ligne.shape # La réponse ne sera pas (1,3) # on devrait récupérer un tuple à # un seul item
(3,)
On a un tuple ne contenant qu'un seul élément : on a donc un tableau \(\mathtt{1D}\) (1-dimensionnel) de longueur \(\mathtt{3}\).
Si je veux récupérer \(c_2=\begin{pmatrix} 0\\2\end{pmatrix}\), la deuxième colonne de \(\mathtt{A}\) :
A
array([[ 1, 0, 1], [ 4, 2, -8]])
A[:,1] print A[:,1]
[0 2]
Ma colonne n'est pas formatée en colonne : c'est encore un tableau \(\mathtt{1D}\). Dans la suite on remédie à ce problème (si on considère que cela est un problème) grâce à une méthode permettant de redimensionner un tableau.
Redimensionner un tableau numpy
Si vous souhaitez vraiment récupérer une colonne non pas pas comme un tableau \(\mathtt{1D}\), mais une "vraie" colonne au sens des matrices, c'est-à-dire, pour l'exemple précédent, un tableau de format \((2,1)\), vous avez la méthode \(\mathtt{reshape}\) pour cela :
colonne = A[:,1] # j'extrais la deuxième colonne de A colonne = colonne.reshape(2,1) # avec reshape(2,1) j'en fais une matrice 2 X 1 print colonne
[[0] [2]]
** Exercice. ** La commande \(\mathtt{range}\) a son analogue en tableau \(\mathtt{numpy}\) : \(\mathtt{arange}\) (pour array-range). Par exemple :
np.arange(1,10) # tableau 1D des entiers de 1 à 9.
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
Construire la matrice suivante : $ B =
$.
Solution.
B = np.arange(1,10).reshape(3,3) print B
[[1 2 3] [4 5 6] [7 8 9]]
Autres opérations
Reportez-vous à l'aide-mémoire : les opérations les plus utiles y sont consignées. Voici quelques matrices typiques :
Matrices remarquables
Matrice unité ou identité
identite = np.eye(4) # Matrice I4 : identité d'ordre 4 print identite,"\n" # rappel : "\n" est le saut de ligne print 3*identite # une matrice scalaire
[[ 1. 0. 0. 0.] [ 0. 1. 0. 0.] [ 0. 0. 1. 0.] [ 0. 0. 0. 1.]] [[ 3. 0. 0. 0.] [ 0. 3. 0. 0.] [ 0. 0. 3. 0.] [ 0. 0. 0. 3.]]
Une remarque sur le produit matriciel
En Python, vous pouvez faire deux types de produit :
-
Le produit matriciel que vous connaissez avec les restrictions de format que cela implique. La commande est :
\begin{equation*} \texttt{np.dot(A,B)}\quad \text{, et ce n'est pas }\quad \texttt{A*B} \end{equation*} -
Il y a un autre produit qui existe (mais qui ne correspond à rien en maths) : le produit élément par élément (broadcasting). Pour deux matrices \(A\) et \(B\) de même format :
donne la matrice de même format que \(A\) et \(B\) de coefficient général \(a_{i,j} \times b_{i,j}\). Opération très utile pour le calcul en "parallèle" (évite le recours à une boucle).
Exercice
- Calculer \(A^2\) où \(A\) est la matrice Attila d'ordre 3.
- Construire en utilisant la matrice \(B\) précédente la matrice \(C\) suivante :
$ C =
$
# Réponse à 1. : #---------------- A = np.ones([3,3]) np.dot(A,A) #Produit matriciel de A avec A
array([[ 3., 3., 3.], [ 3., 3., 3.], [ 3., 3., 3.]])
# Réponse à 2. : #--------------- B = np.arange(1,10).reshape(3,3) print 'B =' print B # la matrice B de tout à l'heure M = np.array([2**k for k in B]) # construction en compréhension print 'M = ' print M C = B*M # la matrice est le produit print 'C = ' # élément par élement de B et M print C
B = [[1 2 3] [4 5 6] [7 8 9]] M = [[ 2 4 8] [ 16 32 64] [128 256 512]] C = [[ 2 8 24] [ 64 160 384] [ 896 2048 4608]]