web-dev-qa-db-de.com

Wie unterscheidet sich die Multiplikation für NumPy Matrix- und Array-Klassen?

In den Numpy-Dokumenten wird empfohlen, Array anstelle von Matrix für die Arbeit mit Matrizen zu verwenden. Im Gegensatz zur Oktave (die ich bis vor kurzem verwendet habe) führt * keine Matrixmultiplikation durch, Sie müssen jedoch die Funktion matrixmultipy () verwenden. Ich denke, dies macht den Code sehr unlesbar.

Teilt jemand meine Ansichten und hat eine Lösung gefunden?

130
elexhobby

Der Hauptgrund, die Verwendung der matrix -Klasse zu vermeiden, besteht darin, dass a) sie von Natur aus zweidimensional ist und b) im Vergleich zu einem "normalen" Numpy-Array ein zusätzlicher Aufwand entsteht. Wenn alles, was Sie tun, lineare Algebra ist, können Sie auf jeden Fall die Matrixklasse verwenden ... Ich persönlich finde es jedoch schwieriger, als es sich lohnt.

Verwenden Sie für Arrays (vor Python 3.5)) dot anstelle von matrixmultiply.

Z.B.

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

print np.dot(x,y)

Oder verwenden Sie in neueren Versionen von numpy einfach x.dot(y)

Persönlich finde ich es viel lesbarer als der Operator *, Der eine Matrixmultiplikation impliziert ...

Verwenden Sie für Arrays in Python 3.5 x @ y.

126
Joe Kington

die wichtigsten Informationen für Operationen mit NumPy Arrays im Vergleich zu Operationen mit NumPy Matrizen sind:

  • Die NumPy-Matrix ist eine Unterklasse des NumPy-Arrays

  • NumPy -Array -Operationen sind elementweise (sobald Broadcasting berücksichtigt wurde)

  • NumPy Matrix Operationen folgen den üblichen Regeln der linearen Algebra

einige Codefragmente zur Veranschaulichung:

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

diese Operation schlägt jedoch fehl, wenn diese beiden NumPy-Matrizen in Arrays konvertiert werden:

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

die Verwendung der Syntax NP.dot funktioniert jedoch mit Arrays ; Diese Operation funktioniert wie eine Matrixmultiplikation:

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

benötigen Sie also jemals eine NumPy-Matrix? Ist ein NumPy-Array für die Berechnung der linearen Algebra ausreichend (vorausgesetzt, Sie kennen die korrekte Syntax, dh NP.dot)?

die Regel scheint zu sein, dass wenn die Argumente (Arrays) Formen (m x n) haben, die mit der gegebenen linearen Algebra-Operation kompatibel sind, Sie in Ordnung sind, andernfalls wirft NumPy.

die einzige Ausnahme, auf die ich gestoßen bin (es gibt wahrscheinlich andere), ist die Berechnung der inversen Matrix .

im Folgenden sind Ausschnitte aufgeführt, in denen ich eine reine lineare Algebra-Operation aufgerufen habe (tatsächlich aus Numpys linearem Algebra-Modul) und in einem NumPy-Array übergeben habe

Determinante eines Arrays:

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

Eigenvektoren/Eigenwert Paare:

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

matrix Norm :

>>>> LA.norm(m)
22.0227

qr Faktorisierung :

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

matrix 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

matrix Bedingung :

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

Inversion erfordert eine NumPy Matrix obwohl:

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

aber das Moore-Penrose-Pseudoinverse scheint gut zu funktionieren

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

In 3.5 ist Python finally hat einen Matrixmultiplikationsoperator . Die Syntax ist a @ b.

20
Petr Viktorin

Es gibt eine Situation, in der der Punktoperator beim Umgang mit Arrays andere Antworten gibt als beim Umgang mit Matrizen. Nehmen wir zum Beispiel Folgendes an:

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

Lasst sie uns in Matrizen umwandeln:

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

Jetzt können wir eine unterschiedliche Ausgabe für die beiden Fälle sehen:

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

Referenz von http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html

... von der Verwendung der numpy.matrix Klasse wird abgeraten , da es nichts hinzufügt, was mit 2D numpy.ndarray Objekten nicht erreicht werden kann und zu einer Verwirrung führen kann von welcher Klasse verwendet wird. Zum Beispiel,

>>> 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.linalg Operationen können gleichermaßen auf numpy.matrix oder auf angewendet werden 2D numpy.ndarray Objekte.

8
Yong Yang

Dieser Trick könnte das sein, wonach Sie suchen. Es ist eine Art einfache Bedienerüberlastung.

Sie können dann so etwas wie die vorgeschlagene Infix-Klasse verwenden:

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

Ein passendes Zitat aus PEP 465 - Ein dedizierter Infix-Operator für die Matrixmultiplikation , wie von @ petr-viktorin erwähnt, verdeutlicht das Problem, bei dem das OP ankam:

numpy bietet zwei verschiedene Typen mit unterschiedlichen __mul__ Methoden. Zum numpy.ndarray Objekte, * führt eine elementweise Multiplikation durch, und die Matrixmultiplikation muss einen Funktionsaufruf (numpy.dot). Zum numpy.matrix Objekte, * führt eine Matrixmultiplikation durch, und die elementweise Multiplikation erfordert eine Funktionssyntax. Code schreiben mit numpy.ndarray funktioniert gut. Code schreiben mit numpy.matrix funktioniert auch gut. Aber Ärger beginnt , sobald wir versuchen, diese beiden Teile des Codes zusammen zu integrieren. Code, der ein ndarray erwartet und ein matrix erhält, oder umgekehrt, kann abstürzen oder falsche Ergebnisse zurückgeben

Die Einführung des @ Infix-Operator soll helfen, python Matrix-Code zu vereinheitlichen und zu vereinfachen.

5
cod3monk3y

Die Funktion matmul (seit numpy 1.10.1) funktioniert für beide Typen und gibt das Ergebnis als numpy-Matrixklasse zurück:

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

Ausgabe:

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

Seit python 3.5 als früh erwähnt können Sie auch einen neuen Matrixmultiplikationsoperator @ wie

C = A @ B

und erhalten Sie das gleiche Ergebnis wie oben.

1
Serenity