L’utilisation de NumPy est un moyen pratique d’effectuer des opérations matricielles en Python.
Bien que la liste intégrée de Python puisse représenter un tableau bidimensionnel (une liste de listes), l’utilisation de NumPy simplifie les tâches telles que la multiplication de matrices, les matrices inverses, les déterminants, les valeurs propres, etc.
- Créer un tableau NumPy ( 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 ) représentant une matrice : 𝐧𝐩.𝐚𝐫𝐫𝐚𝐲()
- Accéder et modifier les éléments d’un tableau NumPy ( 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 )
- Calculs par éléments sur des tableaux : opérateurs arithmétiques
- Matrix multiplication: @, 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥(), 𝐧𝐩.𝐝𝐨𝐭()
- Inner product of vectors: 𝐧𝐩.𝐢𝐧𝐧𝐞𝐫()
- Inverse matrix: 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐢𝐧𝐯()
- Determinant: 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐝𝐞𝐭()
- Eigenvalues and eigenvectors: 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐞𝐢𝐠()
NumPy peut être installé à l’aide de la commande 𝐩𝐢𝐩 .
$ pip install numpy
NumPy fournit la classe 𝐧𝐩.𝐧𝐝𝐚𝐫𝐫𝐚𝐲 pour les tableaux multidimensionnels à usage général et la classe 𝐧𝐩.𝐦𝐚𝐭𝐫𝐢𝐱 spécialisée pour les matrices (tableaux bidimensionnels). Cependant, les opérations matricielles sont également possibles avec 𝐧𝐩.𝐧𝐝𝐚𝐫𝐫𝐚𝐲 , et à partir de la version 1.26 de NumPy, il n’est plus recommandé d’utiliser 𝐧𝐩.𝐦𝐚𝐭𝐫𝐢𝐱 .
Il n’est plus recommandé d’utiliser cette classe, même pour l’algèbre linéaire. Utilisez plutôt des tableaux classiques. La classe pourrait être supprimée à l’avenir. matrice numpy — Manuel NumPy v1.26
Cet article se concentre sur les opérations matricielles utilisant 𝐧𝐩.𝐧𝐝𝐚𝐫𝐫𝐚𝐲 .
La version de NumPy utilisée dans cet article est la suivante. Notez que les fonctionnalités peuvent varier selon les versions.
import numpy as np print(np.__version__) # 1.26.2
Créer un tableau NumPy ( 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 ) représentant une matrice : 𝐧𝐩.𝐚𝐫𝐫𝐚𝐲()
Un tableau NumPy ( 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 ) peut être créé en utilisant 𝐧𝐩.𝐚𝐫𝐫𝐚𝐲() .
La spécification d’une liste bidimensionnelle (une liste de listes) comme premier argument crée un tableau bidimensionnel.
a = np.array([[0, 1, 2], [3, 4, 5]]) print(a) # [[0 1 2] # [3 4 5]] print(type(a)) # <class 'numpy.ndarray'>
Vous pouvez également créer des 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 à l’aide de fonctions telles que 𝐧𝐩.𝐚𝐫𝐚𝐧𝐠𝐞() et modifier la forme à l’aide de la méthode 𝐫𝐞𝐬𝐡𝐚𝐩𝐞() .
- numpy.arange(), linspace() : générer un ndarray avec des valeurs identiques espacées
- NumPy : Comment utiliser reshape() et la signification de -1
print(np.arange(6).reshape(2, 3)) # [[0 1 2] # [3 4 5]]
De plus, il existe des fonctions telles que 𝐧𝐩.𝐳𝐞𝐫𝐨𝐬() , 𝐧𝐩.𝐨𝐧𝐞𝐬() et 𝐧𝐩.𝐟𝐮𝐥𝐥() pour initialiser des tableaux de n’importe quelle forme avec la même valeur. Il est également possible de lire des fichiers CSV sous forme de tableaux.
- NumPy : Créer un ndarray avec tous les éléments initialisés avec la même valeur
- NumPy : lecture et écriture de fichiers CSV (np.loadtxt, np.genfromtxt, np.savetxt)
Accéder et modifier les éléments d’un tableau NumPy ( 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 )
Dans un 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 bidimensionnel , les éléments sont accessibles à l’aide de [𝐫𝐨𝐰_𝐧𝐮𝐦𝐛𝐞𝐫, 𝐜𝐨𝐥𝐮𝐦𝐧_𝐧𝐮𝐦𝐛𝐞𝐫] , où les indices de ligne et de colonne commencent à 0 . Cela permet à la fois la récupération et la modification des valeurs.
a = np.array([[0, 1, 2], [3, 4, 5]]) print(a) # [[0 1 2] # [3 4 5]] print(a[0, 1]) # 1 a[0, 1] = 100 print(a) # [[ 0 100 2] # [ 3 4 5]]
À l’aide de tranches, vous pouvez sélectionner des plages et obtenir des sous-tableaux.
print(a[:, 1:]) # [[100 2] # [ 4 5]]
Calculs par éléments sur des tableaux : opérateurs arithmétiques
L’application d’opérateurs arithmétiques tels que + (addition), – (soustraction), * (multiplication), / (division) et ** (exponentiation) à un nombre effectue des calculs élément par élément.
a1 = np.arange(6).reshape(2, 3) print(a1) # [[0 1 2] # [3 4 5]] a2 = np.arange(6, 18, 2).reshape(2, 3) print(a2) # [[ 6 8 10] # [12 14 16]] print(a1 + a2) # [[ 6 9 12] # [15 18 21]] print(a1 - a2) # [[ -6 -7 -8] # [ -9 -10 -11]] print(a1 * a2) # [[ 0 8 20] # [36 56 80]] print(a1 / a2) # [[0. 0.125 0.2 ] # [0.25 0.28571429 0.3125 ]] print(a1**a2) # [[ 0 1 1024] # [ 531441 268435456 152587890625]]
Des calculs avec des valeurs scalaires sont également possibles.
print(a1 * 100) # [[ 0 100 200] # [300 400 500]]
Même lorsque l’on travaille avec des tableaux de formes différentes, un mécanisme appelé diffusion ajuste automatiquement ces formes, autant que possible, pour permettre les calculs.
print(a1 * [10, 100, 1000]) # [[ 0 100 2000] # [ 30 400 5000]]
Pour les puissances négatives, une erreur se produit si le type de données du tableau d’origine ( 𝐝𝐭𝐲𝐩𝐞 ) est un entier ( 𝐢𝐧𝐭 ). La conversion en nombre à virgule flottante ( 𝐟𝐥𝐨𝐚𝐭 ) résout ce problème.
# print(a2 ** -1) # ValueError: Integers to negative integer powers are not allowed. print(a2.astype(float) ** -1) # [[0.16666667 0.125 0.1 ] # [0.08333333 0.07142857 0.0625 ]]
Pour chaque opérateur arithmétique, des fonctions correspondantes telles que 𝐧𝐩.𝐦𝐮𝐥𝐭𝐢𝐩𝐥𝐲() sont également disponibles.
print(np.multiply(a1, a2)) # [[ 0 8 20] # [36 56 80]]
Multiplication matricielle :
Pour calculer la multiplication d’une matrice, utilisez l’opérateur @ , 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥() ou 𝐧𝐩.𝐝𝐨𝐭() . 𝐝𝐨𝐭() est également disponible comme méthode de 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 .
- numpy.matmul — Manuel de NumPy v1.26
- numpy.dot — Manuel de NumPy v1.26
- numpy.ndarray.dot — Manuel de NumPy v1.26
L’opérateur @ est disponible à partir de Python 3.5 et NumPy 1.10, et 𝐚 @ 𝐛 est équivalent à 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥(𝐚, 𝐛) .
a1 = np.arange(4).reshape((2, 2)) print(a1) # [[0 1] # [2 3]] a2 = np.arange(6).reshape((2, 3)) print(a2) # [[0 1 2] # [3 4 5]] print(a1 @ a2) # [[ 3 4 5] # [ 9 14 19]] print(np.matmul(a1, a2)) # [[ 3 4 5] # [ 9 14 19]] print(np.dot(a1, a2)) # [[ 3 4 5] # [ 9 14 19]] print(a1.dot(a2)) # [[ 3 4 5] # [ 9 14 19]]
Bien que 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥() et 𝐧𝐩.𝐝𝐨𝐭() se comportent différemment pour les tableaux à plus de trois dimensions, cet article ne couvrea pas ces différences. Pour plus de détails, reportez-vous à la documentation officielle.
Notez que 𝐧𝐩.𝐝𝐨𝐭() est généralement utilisé pour les produits scalaires. Pour la multiplication de matrices (traitement de tableaux bidimensionnels), il est préférable d’utiliser 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥() ou l’opérateur @ .
Si 𝐚 et 𝐛 sont tous deux des tableaux 2D, il s’agit d’une multiplication matricielle, mais l’utilisation de 𝐦𝐚𝐭𝐦𝐮𝐥 ou 𝐚 @ 𝐛 est préférable. numpy.dot — Manuel de NumPy v1.26
Lors du traitement des tableaux 1D et 2D
Bien qu’une matrice avec une seule ligne ou une seule colonne soit parfois appelée respectivement vecteur de ligne ou vecteur de colonne, il n’y a pas de distinction entre les lignes et les colonnes dans un tableau unidimensionnel . Pour représenter une seule ligne ou une seule colonne, utilisez un tableau bidimensionnel.
a_row = np.arange(3).reshape(1, 3) print(a_row) # [[0 1 2]] print(a_row.shape) # (1, 3) a_col = np.arange(3).reshape(3, 1) print(a_col) # [[0] # [1] # [2]] print(a_col.shape) # (3, 1)
Le produit de deux tableaux bidimensionnels est calculé comme le produit matriciel habituel et le résultat est un tableau bidimensionnel.
a_2d = np.arange(9).reshape(3, 3) print(a_2d) # [[0 1 2] # [3 4 5] # [6 7 8]] print(a_row @ a_2d) # [[15 18 21]] print(a_2d @ a_col) # [[ 5] # [14] # [23]]
Lors du calcul du produit d’un tableau unidimensionnel et d’un tableau bidimensionnel à l’aide de l’opérateur @ , 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥() ou 𝐧𝐩.𝐝𝐨𝐭() , le traitement des tableaux diffère. Le tableau unidimensionnel du premier argument (opérande de gauche) est traité comme un vecteur de ligne, et le tableau unidimensionnel du deuxième argument (opérande de droite) est traité comme un vecteur de colonne, ce qui donne un tableau unidimensionnel.
a_1d = np.array([0, 1, 2]) print(a_1d @ a_2d) # [15 18 21] print(np.dot(a_1d, a_2d)) # [15 18 21] print(a_2d @ a_1d) # [ 5 14 23] print(np.dot(a_2d, a_1d)) # [ 5 14 23]
Comme cela sera mentionné dans la section suivante, lorsqu’il s’agit de tableaux unidimensionnels, le produit scalaire (produit interne) est renvoyé.
Produit scalaire de vecteurs : 𝐧𝐩.𝐢𝐧𝐧𝐞𝐫()
Bien que légèrement éloigné du sujet des matrices (tableaux bidimensionnels), 𝐧𝐩.𝐢𝐧𝐧𝐞𝐫() est utilisé pour calculer le produit scalaire de vecteurs (tableaux unidimensionnels) et renvoyer un scalaire.
a1 = np.array([0, 1, 2]) a2 = np.array([3, 4, 5]) print(np.inner(a1, a2)) # 14
L’opérateur @ , 𝐧𝐩.𝐦𝐚𝐭𝐦𝐮𝐥() et 𝐧𝐩.𝐝𝐨𝐭() renvoient également le produit interne lorsque les deux arguments sont des tableaux unidimensionnels.
print(a1 @ a2) # 14 print(np.dot(a1, a2)) # 14
Matrice inverse : 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐢𝐧𝐯()
Pour calculer la matrice inverse, utilisez 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐢𝐧𝐯() . Le produit de la matrice d’origine et de sa matrice inverse donne la matrice identité.
a = np.array([[2, 5], [1, 3]]) print(a) # [[2 5] # [1 3]] print(np.linalg.inv(a)) # [[ 3. -5.] # [-1. 2.]] print(a @ np.linalg.inv(a)) # [[1. 0.] # [0. 1.]]
Matrice pseudo-inverse : 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐩𝐢𝐧𝐯()
Pour les matrices singulières, qui sont des matrices sans inverse, l’utilisation de 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐢𝐧𝐯() entraînera une erreur.
a_singular = np.array([[0, 0], [1, 3]]) print(a_singular) # [[0 0] # [1 3]] # print(np.linalg.inv(a_singular)) # LinAlgError: Singular matrix
Vous pouvez calculer la matrice pseudo-inverse de Moore-Penrose en utilisant 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐩𝐢𝐧𝐯() .
print(np.linalg.pinv(a_singular)) # [[0. 0.1] # [0. 0.3]]
Bien que le produit matriciel d’une matrice singulière et de son pseudo-inverse ne donne pas la matrice identité, l’application de l’opération pseudo-inverse à la matrice pseudo-inverse donne la matrice d’origine. Reportez-vous à la page Wikipédia ci-dessus pour plus de détails.
print(a_singular @ np.linalg.pinv(a_singular)) # [[0. 0.] # [0. 1.]] print(np.linalg.pinv(np.linalg.pinv(a_singular))) # [[0. 0.] # [1. 3.]]
Notez que pour les matrices régulières (non singulières), 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐢𝐧𝐯() et 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐩𝐢𝐧𝐯() renvoie la matrice inverse.
a = np.array([[2, 5], [1, 3]]) print(a) # [[2 5] # [1 3]] print(np.linalg.inv(a)) # [[ 3. -5.] # [-1. 2.]] print(np.linalg.pinv(a)) # [[ 3. -5.] # [-1. 2.]]
Déterminant : 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐝𝐞𝐭()
Pour calculer le déterminant, utilisez 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐝𝐞𝐭() .
a = np.array([[0, 1], [2, 3]]) print(a) # [[0 1] # [2 3]] print(np.linalg.det(a)) # -2.0
Valeurs propres et vecteurs propres : 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐞𝐢𝐠()
Pour calculer les valeurs propres et les vecteurs propres, utilisez 𝐧𝐩.𝐥𝐢𝐧𝐚𝐥𝐠.𝐞𝐢𝐠() .
Pour une matrice carrée d’ordre n, cette fonction renvoie un tableau unidimensionnel contenant n valeurs propres et un tableau bidimensionnel où chaque colonne correspond à un vecteur propre associé à chaque valeur propre.
La i-ième valeur propre ( [𝐢] ) correspond au i-ième vecteur propre de la colonne ( [:, 𝐢] ). Les vecteurs propres sont normalisés à une longueur de 1 .
a = np.array([[8, 1], [4, 5]]) print(a) # [[8 1] # [4 5]] eigenvalues, eigenvectors = np.linalg.eig(a) print(eigenvalues) # [9. 4.] print(eigenvectors) # [[ 0.70710678 -0.24253563] # [ 0.70710678 0.9701425 ]] print(a @ eigenvectors[:, 0] == eigenvalues[0] * eigenvectors[:, 0]) # [ True True] print(a @ eigenvectors[:, 1] == eigenvalues[1] * eigenvectors[:, 1]) # [ True True]
Pour trouver la plus grande valeur propre, utilisez 𝐧𝐩.𝐚𝐫𝐠𝐦𝐚𝐱() , qui renvoie l’index de la valeur maximale.
print(eigenvalues[np.argmax(eigenvalues)]) # 9.0 print(eigenvectors[:, np.argmax(eigenvalues)]) # [0.70710678 0.70710678]
En définissant une fonction personnalisée, vous pouvez obtenir une liste de tuples associant chaque valeur propre à son vecteur propre correspondant. Pour plus de clarté, les vecteurs propres sont divisés par la plus petite valeur absolue non nulle de chaque colonne. La sortie de la fonction est formatée à l’aide de chaînes f ( 𝐟’ … ‘ ).
def get_eigenpairs(a): values, vectors = np.linalg.eig(a) pairs = [] for i, val in enumerate(values): vec = vectors[:, i] / min(x for x in np.abs(vectors[:, i]) if x != 0) pairs.append((val, vec)) return pairs for val, vec in get_eigenpairs(a): print(f'value: {val}, vector: {vec}') # value: 9.0, vector: [1. 1.] # value: 4.0, vector: [-1. 4.]
Pour une matrice 3 𝐱 3 :
a_3d = np.array([[1, 1, 2], [0, 2, -1], [0, 0, 3]]) print(a_3d) # [[ 1 1 2] # [ 0 2 -1] # [ 0 0 3]] for val, vec in get_eigenpairs(a_3d): print(f'value: {val}, vector: {vec}') # value: 1.0, vector: [1. 0. 0.] # value: 2.0, vector: [1. 1. 0.] # value: 3.0, vector: [ 1. -2. 2.]
Les nombres complexes peuvent également être traités.
a = np.array([[3, 2], [-2, 3]]) print(a) # [[ 3 2] # [-2 3]] for val, vec in get_eigenpairs(a): print(f'value: {val:.1}, vector: {vec}') # value: (3+2j), vector: [0.-1.j 1.+0.j] # value: (3-2j), vector: [0.+1.j 1.-0.j]
Pour plus d’informations sur la gestion des nombres complexes en Python, consultez l’article suivant.
