Numpy docs zalecają używanie tablicy zamiast matrix do pracy z macierzami. Jednak w przeciwieństwie do oktawy (której używałem do niedawna), * nie wykonuje mnożenia macierzy, musisz użyć funkcji matrixmultipy (). Czuję, że to sprawia, że kod jest bardzo nieczytelny.
Czy ktoś podziela moje poglądy i znalazł rozwiązanie?
.*
składni vs '*' dla mnożenia elementów vs mnożenia macierzy. Gdyby tak było, wszystko byłoby prostsze, chociaż jestem zaskoczony, że wybrali*
na myśli elementy, a nie mnożenie macierzy.Odpowiedzi:
Głównym powodem unikania używania tej
matrix
klasy jest to, że a) jest z natury dwuwymiarowa oraz b) ma dodatkowe obciążenie w porównaniu z „normalną” tablicą numpy. Jeśli wszystko, co robisz, to algebra liniowa, to zdecydowanie możesz użyć klasy macierzy ... Osobiście uważam, że jest to bardziej kłopotliwe niż warte.W przypadku tablic (starszych niż Python 3.5) użyj
dot
zamiastmatrixmultiply
.Na przykład
import numpy as np x = np.arange(9).reshape((3,3)) y = np.arange(3) print np.dot(x,y)
Lub w nowszych wersjach numpy po prostu użyj
x.dot(y)
Osobiście uważam to za znacznie bardziej czytelne niż
*
operator implikujący mnożenie macierzy ...W przypadku tablic w Pythonie 3.5 użyj
x @ y
.źródło
x.T.dot(A.T).dot(A).dot(x)
to nie jest nieczytelne, imo Jednak dla każdego z nich. Jeśli zajmujesz się głównie mnożeniem macierzy, zdecydowanie użyjnumpy.matrix
!numpy.matrixmultiply
.numpy.dot
mnożenie macierzy jest równoważne. Jeśli naprawdę nie podoba ci się notacja, użyjmatrix
klasy.kluczowe rzeczy, które należy wiedzieć o operacjach na tablicach NumPy w porównaniu z operacjami na macierzach NumPy to:
Macierz NumPy jest podklasą tablicy NumPy
NumPy tablicy operacje są elementem mądry (raz transmisja jest wykazywana)
Operacje na macierzach NumPy podlegają zwykłym regułom algebry liniowej
kilka fragmentów kodu do zilustrowania:
>>> 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]])
ale ta operacja kończy się niepowodzeniem, jeśli te dwie macierze NumPy zostaną przekonwertowane na tablice:
>>> 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)
chociaż użycie składni NP.dot działa z tablicami ; te operacje działają jak mnożenie macierzy:
>> NP.dot(a1, a2t) array([[127, 84, 85, 89], [218, 139, 142, 173], [226, 157, 136, 103], [352, 197, 214, 393]])
więc czy kiedykolwiek potrzebujesz macierzy NumPy? tj. czy tablica NumPy wystarczy do obliczenia algebry liniowej (pod warunkiem, że znasz poprawną składnię, np. NP.dot)?
zasada wydaje się być taka, że jeśli argumenty (tablice) mają kształty (mxn) zgodne z daną operacją algebry liniowej, to wszystko jest w porządku, w przeciwnym razie rzuca NumPy.
jedynym wyjątkiem, na jaki się natknąłem (prawdopodobnie są inne), jest odwrotne obliczanie macierzy .
poniżej znajdują się fragmenty, w których nazwałem operację czystej algebry liniowej (w rzeczywistości z modułu Linear Algebra Numpy'ego) i przekazane w tablicy NumPy
wyznacznik tablicy:
>>> 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
wektory własne / pary wartości własnych :
>>> 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 macierzy :
>>>> LA.norm(m) 22.0227
rozkład na czynniki 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.]]))
ranga matrycy :
>>> 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
stan matrycy :
>>> a1 = NP.random.randint(1, 10, 12).reshape(4, 3) >>> LA.cond(a1) 5.7093446189400954
inwersja wymaga jednak macierzy NumPy:
>>> 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'
ale pseudoinverse Moore'a-Penrose'a wydaje się działać dobrze
>>> 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]])
źródło
W 3.5 Python w końcu uzyskał operator mnożenia macierzy . Składnia to
a @ b
.źródło
Jest sytuacja, w której operator kropkowy będzie udzielał innych odpowiedzi podczas pracy z tablicami, jak w przypadku macierzy. Załóżmy na przykład, że:
>>> a=numpy.array([1, 2, 3]) >>> b=numpy.array([1, 2, 3])
Przekształćmy je w macierze:
>>> am=numpy.mat(a) >>> bm=numpy.mat(b)
Teraz możemy zobaczyć inne dane wyjściowe dla dwóch przypadków:
>>> print numpy.dot(a.T, b) 14 >>> print am.T*bm [[1. 2. 3.] [2. 4. 6.] [3. 6. 9.]]
źródło
Źródła z http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html
..., korzystanie z numpy.matrix klasie jest zniechęcony , ponieważ nie wnosi nic nowego, że nie można osiągnąć z 2D numpy.ndarray obiektów i może prowadzić do nieporozumień , których klasa jest używany. Na przykład,
>>> 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])
Operacje scipy.linalg można zastosować w równym stopniu do obiektów numpy.matrix lub 2D numpy.ndarray .
źródło
Ta sztuczka może być tym, czego szukasz. Jest to rodzaj prostego przeciążenia operatora.
Możesz wtedy użyć czegoś podobnego do sugerowanej klasy Infix w następujący sposób:
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
źródło
Odpowiedni cytat z PEP 465 - Dedykowany operator wrostek do mnożenia macierzy , jak wspomniał @ petr-viktorin, wyjaśnia problem, z którym miał do czynienia PO:
Wprowadzenie
@
operatora infix powinno pomóc ujednolicić i uprościć kod macierzy Pythona.źródło
Funkcja matmul (od numpy 1.10.1) działa dobrze dla obu typów i zwraca wynik jako numpy matrix 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))
Wynik:
(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'>)
Od czasu Pythona 3.5, jak wspomniano wcześniej, możesz również użyć nowego operatora mnożenia macierzy,
@
takiego jaki uzyskaj taki sam wynik jak powyżej.
źródło