comment la multiplication diffèrent pour NumPy Matrice vs Tableau des classes?

le numpy docs recommande l'utilisation de tableau au lieu de matrice pour travailler avec des matrices. Cependant, contrairement à octave (que j'utilisais jusqu'à récemment), * n'effectue pas de multiplication matricielle, vous devez utiliser la fonction matrixmultipy (). Je pense que cela rend le code très illisible.

quelqu'un partage mon point de vue, et a trouvé une solution?

122
demandé sur doug 2010-10-08 16:50:47

7 réponses

la principale raison pour éviter d'utiliser la classe matrix est que a) il est intrinsèquement bidimensionnel, et b) Il ya des frais généraux supplémentaires par rapport à un Tableau" normal". Si tout ce que vous faites est l'algèbre linéaire, alors par tous les moyens, n'hésitez pas à utiliser la classe matrix... Personnellement, je trouve que c'est plus difficile que ce que ça vaut.

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 versions plus récentes de numpy, il suffit d'utiliser x.dot(y)

personnellement, je le trouve beaucoup plus lisible que l'opérateur * impliquant une multiplication matricielle...

pour les tableaux en Python 3.5, utilisez x @ y .

121
répondu Joe Kington 2015-01-25 13:57:33

les points clés à connaître pour les opérations sur NumPy "1519140920 des" tableaux par rapport à des opérations sur NumPy "1519140920 des" matrices sont:

  • num Py matrix is a subclass of num Py array

  • NumPy array opérations élément-sage (une fois que la radiodiffusion est comptabilisé)

  • NumPy matrice les opérations de suivre 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 utilisant le NP.point 1519150920" la syntaxe fonctionne avec les tableaux ; cette opération fonctionne comme la multiplication matricielle:

>> NP.dot(a1, a2t)
array([[127,  84,  85,  89],
       [218, 139, 142, 173],
       [226, 157, 136, 103],
       [352, 197, 214, 393]])

avez-vous besoin d'une matrice? ie, un tableau NumPy suffira-t-il pour le calcul de l'algèbre linéaire (à condition que vous connaissiez la syntaxe correcte, ie, NP.dot)?

la règle semble être que si les arguments (tableaux) ont des formes (m x n) compatibles avec l'opération d'algèbre linéaire donnée, alors vous êtes ok, sinon, Numpy lance.

la seule exception que j'ai rencontrée (il y en a probablement d'autres) est calculating matrix inverse .

ci-dessous sont des extraits dans lesquels j'ai appelé une opération d'algèbre linéaire pure (en fait, à partir de module D'algèbre linéaire de Numpy) et passé dans un NumPy array

déterminant d'un réseau:

>>> 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 un NumPy matrix bien que:

>>> 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 Moore-Penrose pseudoinverse semble fonctionner très bien

>>> 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]])
76
répondu doug 2017-05-20 13:40:18

en 3.5, Python finalement a obtenu un opérateur de multiplication de matrice . La syntaxe est a @ b .

16
répondu Petr Viktorin 2016-01-29 17:04:24

il y a une situation où l'opérateur dot donnera des réponses différentes lorsqu'il s'agit de tableaux comme lorsqu'il s'agit 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.]]
15
répondu Jadiel de Armas 2014-09-18 22:46:24

référence de http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html

... l'utilisation de la numpy.matrice classe est découragé , car il n'ajoute rien qui ne peut être accompli avec 2D numpy.ndarray et peut conduire à une confusion dont la classe est 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])

scipy.les opérations linalg peuvent être appliquées également à numpy.la matrice ou "2D 151960920" numpy.ndarray des objets.

8
répondu Yong Yang 2014-01-07 05:01:07

Ce truc pourrait être ce que vous cherchez. C'est une sorte de simple opérateur de surcharge.

vous pouvez alors utiliser quelque chose comme la classe Infix suggérée 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
6
répondu Bitwise 2013-08-19 13:51:19

une citation pertinente de PEP 465-un opérateur infix dédié pour la multiplication matricielle , comme mentionné par @petr-viktorin, clarifie le problème que l'OP obtenait à:

[...] numpy fournit deux types différents avec des méthodes __mul__ différentes. Pour les objets numpy.ndarray , * effectue la multiplication élémentaire, et la multiplication matricielle doit utiliser un appel de fonction ( numpy.dot ). Au lieu de numpy.matrix objets, * effectue la multiplication matricielle, et la multiplication élémentaire nécessite la syntaxe de la fonction. Ecrire le code en utilisant numpy.ndarray fonctionne très bien. Ecrire le code en utilisant numpy.matrix fonctionne aussi très bien. mais les problèmes commencent dès que nous essayons d'intégrer ces deux morceaux de code ensemble. Le Code qui s'attend à un ndarray et obtient un matrix , ou vice-versa, peut s'écraser ou retourner des résultats incorrects

l'introduction de l'opérateur infix @ devrait aider à unifier et simplifier le code matriciel python.

4
répondu cod3monk3y 2015-01-11 20:27:06