Les numpy docs recommandent d'utiliser un tableau plutôt qu'une matrice pour travailler avec des matrices. Cependant, contrairement à octave (que j'utilisais jusqu'à récemment), * n'effectue pas la multiplication de matrice, vous devez utiliser la fonction matrixmultipy (). Je pense que cela rend le code très illisible.
Quelqu'un partage-t-il mes points de vue et a-t-il trouvé une solution?
La principale raison d'éviter d'utiliser la classe matrix
est que a) il est intrinsèquement bidimensionnel et b) qu'il existe une surcharge supplémentaire par rapport à un tableau numpy "normal". Si vous ne faites que de l'algèbre linéaire, n'hésitez pas à utiliser la classe matricielle ... Personnellement, je trouve que c'est plus compliqué que cela n'en vaut la peine.
Pour les tableaux (avant Python 3.5), utilisez dot
au lieu de matrixmultiply
.
Par exemple.
import numpy as np
x = np.arange(9).reshape((3,3))
y = np.arange(3)
print np.dot(x,y)
Ou, dans les nouvelles versions de numpy, utilisez simplement x.dot(y)
Personnellement, je le trouve beaucoup plus lisible que l'opérateur *
impliquant une multiplication de matrice ...
Pour les tableaux dans Python 3.5, utilisez x @ y
.
les éléments clés à connaître pour les opérations sur les tableaux NumPy et les opérations sur les matrices NumPy sont:
La matrice NumPy est une sous-classe du tableau NumPy
Les opérations NumPy array sont élément par élément (une fois la diffusion comptabilisée)
Les opérations de la matrice NumPy suivent les règles ordinaires de l'algèbre linéaire
quelques extraits de code pour illustrer:
>>> from numpy import linalg as LA
>>> import numpy as NP
>>> a1 = NP.matrix("4 3 5; 6 7 8; 1 3 13; 7 21 9")
>>> a1
matrix([[ 4, 3, 5],
[ 6, 7, 8],
[ 1, 3, 13],
[ 7, 21, 9]])
>>> a2 = NP.matrix("7 8 15; 5 3 11; 7 4 9; 6 15 4")
>>> a2
matrix([[ 7, 8, 15],
[ 5, 3, 11],
[ 7, 4, 9],
[ 6, 15, 4]])
>>> a1.shape
(4, 3)
>>> a2.shape
(4, 3)
>>> a2t = a2.T
>>> a2t.shape
(3, 4)
>>> a1 * a2t # same as NP.dot(a1, a2t)
matrix([[127, 84, 85, 89],
[218, 139, 142, 173],
[226, 157, 136, 103],
[352, 197, 214, 393]])
mais cette opération échoue si ces deux matrices NumPy sont converties en tableaux:
>>> a1 = NP.array(a1)
>>> a2t = NP.array(a2t)
>>> a1 * a2t
Traceback (most recent call last):
File "<pyshell#277>", line 1, in <module>
a1 * a2t
ValueError: operands could not be broadcast together with shapes (4,3) (3,4)
bien que l’utilisation de la syntaxe NP.dot fonctionne avec les tableaux ; cette opération fonctionne comme une multiplication matricielle:
>> NP.dot(a1, a2t)
array([[127, 84, 85, 89],
[218, 139, 142, 173],
[226, 157, 136, 103],
[352, 197, 214, 393]])
alors avez-vous déjà besoin d'une matrice NumPy? En d'autres termes, un tableau NumPy suffira-t-il pour le calcul d'algèbre linéaire (à condition que vous connaissiez la syntaxe correcte, c'est-à-dire NP.dot)?
la règle semble être que si les arguments (tableaux) ont des formes (m x n) compatibles avec une opération d'algèbre linéaire donnée, alors vous êtes ok, sinon, NumPy jette.
la seule exception que j'ai rencontrée (il y en a probablement d'autres) est en calculant l'inverse de la matrice .
ci-dessous sont des extraits dans lesquels j'ai appelé une opération d'algèbre linéaire pure (en fait, du module Algèbre linéaire de Numpy) et passée dans un tableau NumPy
déterminant d'un tableau:
>>> m = NP.random.randint(0, 10, 16).reshape(4, 4)
>>> m
array([[6, 2, 5, 2],
[8, 5, 1, 6],
[5, 9, 7, 5],
[0, 5, 6, 7]])
>>> type(m)
<type 'numpy.ndarray'>
>>> md = LA.det(m)
>>> md
1772.9999999999995
vecteurs propres/valeur propre paires:
>>> LA.eig(m)
(array([ 19.703+0.j , 0.097+4.198j, 0.097-4.198j, 5.103+0.j ]),
array([[-0.374+0.j , -0.091+0.278j, -0.091-0.278j, -0.574+0.j ],
[-0.446+0.j , 0.671+0.j , 0.671+0.j , -0.084+0.j ],
[-0.654+0.j , -0.239-0.476j, -0.239+0.476j, -0.181+0.j ],
[-0.484+0.j , -0.387+0.178j, -0.387-0.178j, 0.794+0.j ]]))
matrice norme :
>>>> LA.norm(m)
22.0227
qr factorisation :
>>> LA.qr(a1)
(array([[ 0.5, 0.5, 0.5],
[ 0.5, 0.5, -0.5],
[ 0.5, -0.5, 0.5],
[ 0.5, -0.5, -0.5]]),
array([[ 6., 6., 6.],
[ 0., 0., 0.],
[ 0., 0., 0.]]))
matrice rang :
>>> m = NP.random.Rand(40).reshape(8, 5)
>>> m
array([[ 0.545, 0.459, 0.601, 0.34 , 0.778],
[ 0.799, 0.047, 0.699, 0.907, 0.381],
[ 0.004, 0.136, 0.819, 0.647, 0.892],
[ 0.062, 0.389, 0.183, 0.289, 0.809],
[ 0.539, 0.213, 0.805, 0.61 , 0.677],
[ 0.269, 0.071, 0.377, 0.25 , 0.692],
[ 0.274, 0.206, 0.655, 0.062, 0.229],
[ 0.397, 0.115, 0.083, 0.19 , 0.701]])
>>> LA.matrix_rank(m)
5
matrice condition :
>>> a1 = NP.random.randint(1, 10, 12).reshape(4, 3)
>>> LA.cond(a1)
5.7093446189400954
inversion nécessite une matrice NumPy si:
>>> a1 = NP.matrix(a1)
>>> type(a1)
<class 'numpy.matrixlib.defmatrix.matrix'>
>>> a1.I
matrix([[ 0.028, 0.028, 0.028, 0.028],
[ 0.028, 0.028, 0.028, 0.028],
[ 0.028, 0.028, 0.028, 0.028]])
>>> a1 = NP.array(a1)
>>> a1.I
Traceback (most recent call last):
File "<pyshell#230>", line 1, in <module>
a1.I
AttributeError: 'numpy.ndarray' object has no attribute 'I'
mais le pseudoinverse de Moore-Penrose semble bien fonctionner
>>> LA.pinv(m)
matrix([[ 0.314, 0.407, -1.008, -0.553, 0.131, 0.373, 0.217, 0.785],
[ 1.393, 0.084, -0.605, 1.777, -0.054, -1.658, 0.069, -1.203],
[-0.042, -0.355, 0.494, -0.729, 0.292, 0.252, 1.079, -0.432],
[-0.18 , 1.068, 0.396, 0.895, -0.003, -0.896, -1.115, -0.666],
[-0.224, -0.479, 0.303, -0.079, -0.066, 0.872, -0.175, 0.901]])
>>> m = NP.array(m)
>>> LA.pinv(m)
array([[ 0.314, 0.407, -1.008, -0.553, 0.131, 0.373, 0.217, 0.785],
[ 1.393, 0.084, -0.605, 1.777, -0.054, -1.658, 0.069, -1.203],
[-0.042, -0.355, 0.494, -0.729, 0.292, 0.252, 1.079, -0.432],
[-0.18 , 1.068, 0.396, 0.895, -0.003, -0.896, -1.115, -0.666],
[-0.224, -0.479, 0.303, -0.079, -0.066, 0.872, -0.175, 0.901]])
Dans la version 3.5, Python _ enfin a obtenu un opérateur de multiplication de matrice . La syntaxe est a @ b
.
Il existe une situation où l'opérateur de points donnera des réponses différentes lorsqu'il s'agit de tableaux ou de matrices. Par exemple, supposons ce qui suit:
>>> a=numpy.array([1, 2, 3])
>>> b=numpy.array([1, 2, 3])
Permet de les convertir en matrices:
>>> am=numpy.mat(a)
>>> bm=numpy.mat(b)
Maintenant, nous pouvons voir une sortie différente pour les deux cas:
>>> print numpy.dot(a.T, b)
14
>>> print am.T*bm
[[1. 2. 3.]
[2. 4. 6.]
[3. 6. 9.]]
Référence de http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html
..., l'utilisation de la classe numpy.matrix est déconseillée , puisqu’il n’ajoute rien qui ne puisse être accompli avec des objets 2D numpy.ndarray , et peut entraîner une confusion de la classe utilisée. Par exemple,
>>> import numpy as np
>>> from scipy import linalg
>>> A = np.array([[1,2],[3,4]])
>>> A
array([[1, 2],
[3, 4]])
>>> linalg.inv(A)
array([[-2. , 1. ],
[ 1.5, -0.5]])
>>> b = np.array([[5,6]]) #2D array
>>> b
array([[5, 6]])
>>> b.T
array([[5],
[6]])
>>> A*b #not matrix multiplication!
array([[ 5, 12],
[15, 24]])
>>> A.dot(b.T) #matrix multiplication
array([[17],
[39]])
>>> b = np.array([5,6]) #1D array
>>> b
array([5, 6])
>>> b.T #not matrix transpose!
array([5, 6])
>>> A.dot(b) #does not matter for multiplication
array([17, 39])
Les opérations scipy.linalg peuvent être appliquées indifféremment à numpy.matrix ou à Objets 2D numpy.ndarray .
Cette astuce pourrait être ce que vous cherchez. C'est une sorte de surcharge d'opérateur simple.
Vous pouvez ensuite utiliser quelque chose comme la classe suggérée Infix comme ceci:
a = np.random.Rand(3,4)
b = np.random.Rand(4,3)
x = Infix(lambda x,y: np.dot(x,y))
c = a |x| b
Une citation pertinente de PEP 465 - opérateur infixe dédié à la multiplication matricielle , mentionnée par @ petr-viktorin, clarifie le problème auquel se heurtait l'OP:
[...] numpy fournit deux types différents avec différentes méthodes
__mul__
. Pour les objetsnumpy.ndarray
,*
effectue une multiplication élément par élément et la multiplication de matrice doit utiliser un appel de fonction (numpy.dot
). Pour les objetsnumpy.matrix
,*
effectue la multiplication de matrice et la multiplication élément par élément requiert la syntaxe de la fonction. Écrire du code en utilisantnumpy.ndarray
fonctionne bien. Écrire du code en utilisantnumpy.matrix
fonctionne aussi très bien. Mais les ennuis commencent dès que nous essayons d'intégrer ces deux morceaux de code. Le code qui attend unendarray
et obtient unematrix
, ou vice versa, peut planter ou renvoyer des résultats incorrects
L'introduction de l'opérateur @
infix devrait aider à unifier et à simplifier le code de la matrice python.
La fonction matmul (depuis numpy 1.10.1) fonctionne très bien pour les deux types et renvoie le résultat sous forme de classe numpy matrix:
_import numpy as np
A = np.mat('1 2 3; 4 5 6; 7 8 9; 10 11 12')
B = np.array(np.mat('1 1 1 1; 1 1 1 1; 1 1 1 1'))
print (A, type(A))
print (B, type(B))
C = np.matmul(A, B)
print (C, type(C))
_
Sortie:
_(matrix([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]]), <class 'numpy.matrixlib.defmatrix.matrix'>)
(array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]), <type 'numpy.ndarray'>)
(matrix([[ 6, 6, 6, 6],
[15, 15, 15, 15],
[24, 24, 24, 24],
[33, 33, 33, 33]]), <class 'numpy.matrixlib.defmatrix.matrix'>)
_
Puisque python 3.5 as mentionné plus tôt , vous pouvez également utiliser un nouvel opérateur de multiplication de matrice @
comme
_C = A @ B
_
et obtenez le même résultat que ci-dessus.