in cosa differisce la moltiplicazione per le classi NumPy Matrix vs Array?


130

I documenti numpy raccomandano di usare array anziché matrix per lavorare con le matrici. Tuttavia, a differenza di ottava (che stavo usando fino a poco tempo fa), * non esegue la moltiplicazione della matrice, è necessario utilizzare la funzione matrixmultipy (). Penso che questo renda il codice molto illeggibile.

Qualcuno condivide le mie opinioni e ha trovato una soluzione?


8
Stai chiedendo opinioni e non una domanda. C'è qualcosa di più specifico che possiamo aiutarti o forse guidarti nel renderlo più leggibile?
wheaties

2
In realtà i documenti raccomandano di usare la matrice se si fa un'algebra lineare e non si desidera utilizzare multiply () quindi qual è il problema?
Matti Pastell,

1
Non ho esaminato i documenti in dettaglio. Solo curioso, quali vantaggi offrono gli array rispetto alla classe matrix? Ho scoperto che le matrici non fanno distinzione tra righe e colonne. È perché le matrici dovrebbero essere pensate come tensori piuttosto che come matrici? Come ha sottolineato Joe, il fatto che la classe di matrici sia 2-dim è abbastanza limitante. Qual è il pensiero dietro questo tipo di design, come in, perché non avere una singola classe di matrice come matlab / ottava?
elexhobby,

Immagino che il problema principale sia che python non ha una .*sintassi vs '*' per la moltiplicazione degli elementi rispetto alla matrice. Se così fosse, sarebbe tutto più semplice anche se sono sorpreso che scelgano *di significare moltiplicare gli elementi e non la matrice.
Charlie Parker,

Risposte:


127

Il motivo principale per evitare di usare la matrixclasse è che a) è intrinsecamente bidimensionale e b) c'è un sovraccarico aggiuntivo rispetto a un array "normale" intorpidito. Se tutto ciò che stai facendo è l'algebra lineare, allora sentiti libero di usare la classe matrix ... Personalmente trovo più problemi di quanti ne valga la pena.

Per le matrici (precedenti a Python 3.5), utilizzare dotinvece di matrixmultiply.

Per esempio

import numpy as np
x = np.arange(9).reshape((3,3))
y = np.arange(3)

print np.dot(x,y)

O nelle versioni più recenti di numpy, usa semplicemente x.dot(y)

Personalmente, lo trovo molto più leggibile *dell'operatore che implica la moltiplicazione della matrice ...

Per gli array in Python 3.5, utilizzare x @ y.


10
È illeggibile quando si dispone di una pila di moltiplicazioni, ad esempio x ' A' * A x.
elexhobby,

14
@elexhobby - x.T.dot(A.T).dot(A).dot(x)non è illeggibile, comunque per ognuno il suo. Se stai principalmente facendo la moltiplicazione di matrici, allora usa numpy.matrixassolutamente!
Joe Kington,

7
A proposito, perché la moltiplicazione di matrici si chiama "punto"? In che senso è un prodotto punto?
amcnabb,

8
@amcnabb - La moltiplicazione della matrice viene talvolta definita come un "prodotto punto" nei libri di testo (in quei libri, il prodotto punto che stai pensando è chiamato "prodotto scalare" o "prodotto punto scalare"). Il prodotto del punto scalare è solo una moltiplicazione matriciale di due vettori, dopotutto, quindi usare "punto" per significare la moltiplicazione matriciale in generale non è molto allungato. Quella particolare notazione sembra (?) Più comune nei testi di ingegneria e scienze che in matematica, almeno nella mia esperienza. La sua prevalenza nel numpy è principalmente perché numpy.matrixmultiplyè difficile da scrivere.
Joe Kington,

7
@amcnabb il punto è che il punto si generalizza alla dimensionalità arbitraria senza ambiguità. È questo che rende numpy.dotequivalente alla moltiplicazione della matrice. Se non ti piace davvero la notazione, usa la matrixclasse.
Henry Gomersall,

80

le cose chiave da sapere per le operazioni sulle matrici NumPy rispetto alle operazioni sulle matrici NumPy sono:

  • La matrice NumPy è una sottoclasse dell'array NumPy

  • Le operazioni di array NumPy sono elementari (una volta che la trasmissione è stata tenuta in considerazione)

  • Le operazioni con matrice NumPy seguono le normali regole dell'algebra lineare

alcuni frammenti di codice per illustrare:

>>> 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]])

ma questa operazione fallisce se queste due matrici NumPy vengono convertite in array:

>>> 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) 

sebbene l'uso della sintassi NP.dot funzioni con le matrici ; questa operazione funziona come una moltiplicazione di matrici:

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

hai mai bisogno di una matrice NumPy? vale a dire, un array NumPy sarà sufficiente per il calcolo dell'algebra lineare (a condizione che tu conosca la sintassi corretta, cioè NP.dot)?

la regola sembra essere che se gli argomenti (array) hanno forme (mxn) compatibili con una data operazione di algebra lineare, allora stai bene, altrimenti NumPy genera.

l'unica eccezione che ho riscontrato (probabilmente ce ne sono altri) è il calcolo dell'inverso della matrice .

di seguito sono riportati frammenti in cui ho chiamato un'operazione di algebra lineare pura (in effetti, dal modulo di algebra lineare di Numpy) e passata in un array NumPy

determinante di un array:

>>> 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

autovettori / coppie di autovalori :

>>> 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   ]]))

norma matriciale :

>>>> LA.norm(m)
22.0227

fattorizzazione qr :

>>> 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.]]))

rango matrice :

>>> 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

condizione matrice :

>>> a1 = NP.random.randint(1, 10, 12).reshape(4, 3)
>>> LA.cond(a1)
5.7093446189400954

l'inversione richiede una matrice NumPyperò:

>>> 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'

ma lo pseudoinverso di Moore-Penrose sembra funzionare bene

>>> 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]])

3
mInv = NP.linalg.inv (m) calcola l'inverso di un array
db1234

Un punto importante da notare qui è * è la moltiplicazione degli elementi, il punto è la moltiplicazione della matrice vera. Si prega di consultare stackoverflow.com/a/18255635/1780570
Minh Triet

Nota IMP: le matrici intorpidite devono essere evitate a favore degli array. Nota dalla documentazione -> "Non è più consigliabile utilizzare questa classe, anche per l'algebra lineare. Invece, utilizzare array regolari. La classe potrebbe essere rimossa in futuro." Vedi anche stackoverflow.com/a/61156350/6043669
HopeKing


15

Esiste una situazione in cui l'operatore punto fornirà risposte diverse quando si tratta di matrici come nel caso delle matrici. Ad esempio, supponiamo che:

>>> a=numpy.array([1, 2, 3])
>>> b=numpy.array([1, 2, 3])

Consente di convertirli in matrici:

>>> am=numpy.mat(a)
>>> bm=numpy.mat(b)

Ora possiamo vedere un output diverso per i due casi:

>>> print numpy.dot(a.T, b)
14
>>> print am.T*bm
[[1.  2.  3.]
 [2.  4.  6.]
 [3.  6.  9.]]

Per essere precisi, * è la moltiplicazione degli elementi, il punto è la moltiplicazione della matrice vera. Si prega di consultare stackoverflow.com/a/18255635/1780570
Minh Triet

Questo perché come array numpy, aT == a, la trasposizione non fa nulla.
patapouf_ai,

Se scrivi a = np.array ([[1], [2], [3]]), allora numpy.dot (at, b) dovrebbe darti lo stesso. La differenza tra matix e array non è nel punto ma nella trasposizione.
patapouf_ai,

O in realtà, se scrivi a = numpy.array ([[1,2,3]]) aT trasporterà davvero e tutto funzionerà come nelle matrici.
patapouf_ai,

8

Riferimento da http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html

..., l'uso della classe numpy.matrix è scoraggiato , poiché non aggiunge nulla che non può essere realizzato con oggetti 2D numpy.ndarray e può creare confusione su quale classe viene utilizzata. Per esempio,

>>> 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])

Le operazioni di scipy.linalg possono essere applicate allo stesso modo agli oggetti numpy.matrix o 2D numpy.ndarray .


7

Questo trucco potrebbe essere quello che stai cercando. È una specie di semplice sovraccarico dell'operatore.

È quindi possibile utilizzare qualcosa come la classe Infix suggerita come questa:

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

5

Una citazione pertinente di PEP 465 - Un operatore infix dedicato per la moltiplicazione di matrici , come menzionato da @ petr-viktorin, chiarisce il problema a cui stava arrivando l'OP:

[...] numpy offre due diversi tipi con __mul__metodi diversi . Per gli numpy.ndarrayoggetti, *esegue la moltiplicazione elementwise e la moltiplicazione matriciale deve utilizzare una funzione call ( numpy.dot). Per gli numpy.matrixoggetti, *esegue la moltiplicazione matriciale e la moltiplicazione elementwise richiede la sintassi della funzione. Scrivere codice usando numpy.ndarrayfunziona benissimo. Anche scrivere codice usando numpy.matrixfunziona bene. Ma i problemi iniziano non appena proviamo a integrare questi due pezzi di codice insieme. Il codice che si aspetta un ndarraye ottiene un matrix, o viceversa, potrebbe bloccarsi o restituire risultati errati

L'introduzione @dell'operatore infix dovrebbe aiutare a unificare e semplificare il codice matrice Python.


1

La funzione matmul (dal numpy 1.10.1) funziona bene per entrambi i tipi e restituisce il risultato come una classe di matrice numpy:

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))

Produzione:

(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'>)

Dal momento che python 3.5 come accennato in precedenza è anche possibile utilizzare un nuovo operatore di moltiplicazione matrice @come

C = A @ B

e ottieni lo stesso risultato di cui sopra.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.