NumPy Matrix ve Array sınıfları için çarpma nasıl farklılık gösterir?


130

Numpy docs, matrislerle çalışmak için matris yerine dizi kullanılmasını önerir. Bununla birlikte, oktavın aksine (yakın zamana kadar kullandığım), * matris çarpımını gerçekleştirmiyor, matrixmultipy () işlevini kullanmanız gerekir. Bunun kodu çok okunamaz hale getirdiğini düşünüyorum.

Görüşlerimi paylaşan ve bir çözüm bulan var mı?


8
Fikir soruyorsun, soru değil. Size yardımcı olabileceğimiz veya belki de daha okunaklı hale getirmeniz için size rehberlik edebileceğimiz daha spesifik bir şey var mı?
buğdaylar

2
Doğrusal cebir yapıyorsanız ve multiply () kullanmak istemiyorsanız, dokümanlar matrisi kullanmanızı tavsiye ediyor, peki sorun nedir?
Matti Pastell

1
Dokümanlara ayrıntılı olarak bakmadım. Merak ediyorum, dizilerin matris sınıfına göre sunduğu avantajlar nelerdir? Dizilerin satırlar ve sütunlar arasında ayrım yapmadığını buldum. Dizilerin matrisler yerine tensörler olarak düşünülmesi gerektiğinden mi? Joe'nun da belirttiği gibi, matris sınıfının 2-boyutlu olması oldukça sınırlayıcıdır. Bu tür bir tasarımın arkasındaki düşünce nedir, olduğu gibi, neden matlab / oktav gibi tek bir matris sınıfınız olmasın?
elexhobby

Sanırım ana sorun, python'un .*element wise ve matris çarpımı için vs '*' sözdizimine sahip olmamasıdır . Eğer bu olsaydı, o zaman her şey daha basit olurdu, ancak *matris çarpımını değil, eleman bazında çarpımı kastetmelerine şaşırdım .
Charlie Parker

Yanıtlar:


127

matrixSınıfı kullanmaktan kaçınmanın ana nedeni , a) doğası gereği 2 boyutlu olması ve b) "normal" bir uyuşuk diziye kıyasla ek yük olmasıdır. Eğer yaptığınız tek şey doğrusal cebir ise, o zaman elbette, matris sınıfını kullanmaktan çekinmeyin ... Şahsen ben bunu değerinden daha fazla sorun buluyorum.

Diziler için (Python 3.5 öncesi) dotyerine matrixmultiply.

Örneğin

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

print np.dot(x,y)

Veya numpy'nin daha yeni sürümlerinde şunu kullanın: x.dot(y)

Şahsen, *matris çarpımını ima eden operatörden çok daha okunaklı buluyorum ...

Python 3.5'teki diziler için x @ y.


10
Örneğin, x ' A' * A x gibi bir çarpma yığınınız olduğunda okunamaz .
elexhobby

14
@elexhobby - x.T.dot(A.T).dot(A).dot(x)o kadar okunamaz değil, yine de her biri için imo. Öncelikle matris çarpımı yapıyorsanız, o zaman kesinlikle kullanın numpy.matrix!
Joe Kington

7
Bu arada, matris çarpımına neden "nokta" deniyor? Hangi anlamda bir iç çarpımdır?
amcnabb

8
@amcnabb - Matris çarpımına bazen ders kitaplarında "nokta çarpım" olarak atıfta bulunulur (bu kitaplarda, düşündüğünüz iç çarpıma "skaler çarpım" veya "skaler nokta çarpım" denir). Skaler nokta çarpımı, sonuçta sadece iki vektörün matris çarpımıdır, bu nedenle genel olarak matris çarpımını ifade etmek için "nokta" kullanmak çok da zor değildir. Bu özel notasyon (?) Mühendislik ve bilim metinlerinde matematikten daha yaygın görünüyor, en azından benim tecrübemde. Uyuşukluktaki yaygınlığı, çoğunlukla yazmanın numpy.matrixmultiplyzor olmasıdır.
Joe Kington

7
@amcnabb nokta, noktanın belirsizlik olmadan keyfi boyutluluğa genelleştirilmesidir . O kılan budur numpy.dotmatris çarpma eşdeğerdir. Gösterimi gerçekten beğenmediyseniz, matrixsınıfı kullanın .
Henry Gomersall

80

NumPy dizilerindeki işlemler ve NumPy matrislerindeki işlemler için bilinmesi gereken temel şeyler şunlardır:

  • NumPy matrisi, NumPy dizisinin bir alt sınıfıdır

  • NumPy dizi işlemleri öğe bazındadır (yayın bir kez hesaba katıldığında )

  • NumPy matris işlemleri, doğrusal cebirin sıradan kurallarını takip eder

gösterilecek bazı kod parçacıkları:

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

ancak bu iki NumPy matrisi dizilere dönüştürülürse bu işlem başarısız olur:

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

NP.dot sözdiziminin kullanılması dizilerle çalışsa da ; bu işlemler matris çarpımı gibi çalışır:

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

Öyleyse hiç NumPy matrisine ihtiyacınız var mı? Örneğin, bir NumPy dizisi doğrusal cebir hesaplaması için yeterli olur mu (doğru sözdizimini, yani NP.dot'u biliyorsanız)?

Kural, eğer argümanlar (diziler) verilen doğrusal cebir işlemiyle uyumlu şekillere (mxn) sahipse, o zaman sorun yok, aksi takdirde NumPy atar.

Karşılaştığım tek istisna (muhtemelen başkaları da vardır) matris tersini hesaplamaktır .

aşağıda saf doğrusal cebir işlemi olarak adlandırdığım (aslında, Numpy'nin Doğrusal Cebir modülünden) ve bir NumPy dizisinde geçirdiğim parçacıkları var.

bir dizinin determinantı :

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

özvektörler / özdeğer çiftleri:

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

matris normu :

>>>> LA.norm(m)
22.0227

qr çarpanlara ayırma :

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

matris sıralaması :

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

matris koşulu :

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

ters çevirme bir NumPy matrisi gerektirir:

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

ama Moore-Penrose sözde tersi gayet iyi çalışıyor gibi görünüyor

>>> 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) bir dizinin tersini hesaplar
db1234

Burada dikkat edilmesi gereken önemli bir nokta şudur: * eleman bazında çarpma, nokta gerçek matris çarpımıdır. Lütfen stackoverflow.com/a/18255635/1780570 sayfasına
Minh Triet

IMP notu: diziler lehine uyuşmuş matrislerden kaçınılmalıdır. Dokümantasyondan not -> "Artık bu sınıfın, doğrusal cebir için bile kullanılması tavsiye edilmiyor. Bunun yerine normal dizileri kullanın. Sınıf ileride kaldırılabilir." Ayrıca bkz. Stackoverflow.com/a/61156350/6043669
HopeKing


15

Matrislerle uğraşırken olduğu gibi dizilerle uğraşırken nokta operatörünün farklı yanıtlar vereceği bir durum vardır. Örneğin, şunu varsayalım:

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

Bunları matrislere çevirelim:

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

Şimdi, iki durum için farklı bir çıktı görebiliriz:

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

Spesifik olmak gerekirse, * eleman bazında çarpımdır, nokta gerçek matris çarpımıdır. Lütfen stackoverflow.com/a/18255635/1780570 sayfasına
Minh

Bunun nedeni, uyuşmuş bir dizi olarak, aT == a, devrik hiçbir şey yapmaz.
patapouf_ai

= Np.array ([[1], [2], [3]]) olarak yazarsanız, numpy.dot (at, b) size aynısını vermelidir. Matix ve dizi arasındaki fark nokta değil, devriktir.
patapouf_ai

Ya da aslında, eğer a = numpy.array ([[1,2,3]]) yazarsanız, o zaman aT gerçekten transpoze olur ve her şey matrislerdeki gibi çalışır.
patapouf_ai

8

Http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html adresinden referans

... 2 boyutlu numpy.ndarray nesneleriyle gerçekleştirilemeyecek hiçbir şey eklemediği ve hangi sınıfın kullanıldığına dair bir kafa karışıklığına yol açabileceği için numpy.matrix sınıfının kullanılması önerilmez . Örneğin,

>>> 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 işlemleri numpy.matrix veya 2D numpy.ndarray nesnelerine eşit olarak uygulanabilir .


7

Bu numara aradığınız şey olabilir. Bir tür basit operatör aşırı yüklemesidir.

Daha sonra aşağıdaki gibi önerilen Infix sınıfı gibi bir şey kullanabilirsiniz:

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

PEP 465'ten ilgili bir alıntı - @ petr-viktorin'de belirtildiği gibi, matris çarpımı için özel bir infix operatörü , OP'nin karşılaştığı sorunu açıklığa kavuşturuyor:

[...] numpy, farklı __mul__yöntemlerle iki farklı tür sağlar . İçin numpy.ndarraynesnelerin, *gerçekleştirir çarpma elementwise ve matris çarpım bir işlev çağrısı kullanmalıdır ( numpy.dot). numpy.matrixNesneler için *matris çarpımını gerçekleştirir ve eleman düzeyinde çarpma, işlev sözdizimi gerektirir. Kullanarak kod yazmak numpy.ndarrayiyi çalışıyor. Kullanarak kod yazmak numpy.matrixda iyi çalışıyor. Ancak bu iki kod parçasını bütünleştirmeye çalıştığımızda sorun başlar . Bir bekleyen ndarrayve bir alan matrixveya tersi olan kod çökebilir veya yanlış sonuçlar döndürebilir

@İnfix operatörünün tanıtımı, python matris kodunu birleştirmeye ve basitleştirmeye yardımcı olmalıdır.


1

Fonksiyon matmul (numpy 1.10.1 beri) türleri ve bir numpy matris sınıf olarak dönüş sonucu hem cezasını çalışır:

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

Çıktı:

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

Python 3.5'ten daha önce bahsedildiği@ gibi yeni bir matris çarpım operatörü de kullanabilirsiniz.

C = A @ B

ve yukarıdakiyle aynı sonucu elde edin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.