bagaimana perbedaan perkalian untuk kelas NumPy Matrix vs Array?

130

Dokumen numpy merekomendasikan penggunaan array daripada matriks untuk bekerja dengan matriks. Namun, tidak seperti oktaf (yang saya gunakan sampai saat ini), * tidak melakukan perkalian matriks, Anda perlu menggunakan fungsi matrixmultipy (). Saya merasa ini membuat kode sangat tidak terbaca.

Apakah ada yang berbagi pandangan saya, dan telah menemukan solusi?

elexhobby
sumber
8
Anda meminta pendapat dan bukan pertanyaan. Adakah sesuatu yang lebih spesifik yang dapat kami bantu atau mungkin membimbing Anda agar lebih mudah dibaca?
Wheaties
2
Sebenarnya dokumen merekomendasikan menggunakan matriks jika Anda melakukan aljabar linier dan tidak ingin menggunakan multiply () jadi apa masalahnya?
Matti Pastell
1
Saya belum membaca dokumen secara terperinci. Hanya ingin tahu, apa kelebihan yang ditawarkan array daripada kelas matriks? Saya menemukan bahwa array tidak membedakan antara baris dan kolom. Apakah karena array seharusnya dianggap sebagai tensor daripada matriks? Seperti yang ditunjukkan oleh Joe, fakta bahwa kelas matriks adalah 2-dim sangat terbatas. Apa pemikiran di balik desain semacam ini, seperti, mengapa tidak memiliki kelas matriks tunggal seperti matlab / oktaf?
elexhobby
Saya kira masalah utama adalah bahwa python tidak memiliki .*sintaks vs '*' untuk perkalian elemen vs matriks. Jika sudah demikian maka semuanya akan lebih sederhana meskipun saya terkejut mereka memilih *untuk berarti elemen-bijaksana dan bukan perkalian matriks.
Charlie Parker

Jawaban:

127

Alasan utama untuk menghindari penggunaan matrixkelas adalah bahwa a) itu secara inheren 2 dimensi, dan b) ada overhead tambahan dibandingkan dengan array numpy "normal". Jika semua yang Anda lakukan adalah aljabar linier, maka tentu saja, jangan ragu untuk menggunakan kelas matriks ... Secara pribadi saya merasa lebih banyak kesulitan daripada nilainya.

Untuk array (sebelum Python 3.5), gunakan dot sebagai ganti matrixmultiply.

Misalnya

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

print np.dot(x,y)

Atau dalam versi numpy yang lebih baru, cukup gunakan x.dot(y)

Secara pribadi, saya merasa lebih mudah dibaca daripada * operator yang menyiratkan perkalian matriks ...

Untuk array dalam Python 3.5, gunakan x @ y.

Joe Kington
sumber
10
Tidak dapat dibaca ketika Anda memiliki setumpuk perkalian, misalnya x ' A' * A x.
elexhobby
14
@elexhobby - x.T.dot(A.T).dot(A).dot(x)bukankah itu tidak bisa dibaca, imo Untuk masing-masing miliknya sendiri. Jika Anda terutama melakukan perkalian matriks, maka tentu saja, gunakan numpy.matrix!
Joe Kington
7
Ngomong-ngomong, mengapa perkalian matriks disebut "dot"? Dalam arti apakah itu produk titik?
amcnabb
8
@amcnabb - Penggandaan matriks kadang-kadang disebut sebagai "produk titik" dalam buku teks (dalam buku-buku itu, produk titik yang Anda pikirkan disebut "produk skalar" atau "produk skalar dot"). Produk skalar dot hanyalah perkalian matriks dari dua vektor, jadi, menggunakan "dot" untuk mengartikan perkalian matriks secara umum tidak terlalu banyak. Notasi khusus itu nampaknya (?) Lebih umum dalam rekayasa dan teks sains daripada dalam matematika, setidaknya dalam pengalaman saya. Prevalensinya pada numpy sebagian besar karena numpy.matrixmultiplysulit untuk diketik.
Joe Kington
7
@ amcnabb intinya adalah bahwa titik menggeneralisasi ke dimensi arbitrer tanpa ambiguitas. Inilah yang membuat numpy.dotsetara dengan perkalian matriks. Jika Anda benar-benar tidak menyukai notasi, gunakan matrixkelas.
Henry Gomersall
80

hal-hal utama yang perlu diketahui untuk operasi pada array NumPy versus operasi pada matriks NumPy adalah:

  • Matriks NumPy adalah subkelas dari array NumPy

  • Operasi array NumPy adalah elemen-bijaksana (setelah penyiaran diperhitungkan)

  • Operasi matriks NumPy mengikuti aturan biasa dari aljabar linier

beberapa cuplikan kode untuk diilustrasikan:

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

tetapi operasi ini gagal jika dua matriks NumPy ini dikonversi menjadi 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) 

meskipun menggunakan sintaks NP.dot bekerja dengan array ; operasi ini bekerja seperti perkalian matriks:

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

jadi apakah Anda pernah membutuhkan matriks NumPy? yaitu, apakah array NumPy cukup untuk perhitungan aljabar linier (asalkan Anda tahu sintaks yang benar, yaitu, NP.dot)?

aturan tampaknya bahwa jika argumen (array) memiliki bentuk (mxn) yang kompatibel dengan operasi aljabar linier yang diberikan, maka Anda ok, jika tidak, NumPy melempar.

satu-satunya pengecualian yang saya temui (ada kemungkinan yang lain) menghitung invers matriks .

di bawah ini adalah potongan-potongan yang saya sebut operasi aljabar linier murni (sebenarnya, dari modul Aljabar Linear Numpy) dan dilewatkan dalam array NumPy

penentu 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

pasangan vektor eigen / nilai eigen :

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

>>>> LA.norm(m)
22.0227

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

peringkat matriks :

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

kondisi matriks :

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

inversi membutuhkan matriks 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'

tetapi pseudoinverse Moore-Penrose tampaknya bekerja dengan baik

>>> 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]])
doug
sumber
3
mInv = NP.linalg.inv (m) menghitung kebalikan dari array
db1234
Poin penting yang perlu diperhatikan di sini adalah * adalah perkalian elemen-bijaksana, titik adalah perkalian matriks yang benar. Silakan lihat stackoverflow.com/a/18255635/1780570
Minh Triet
Catatan IMP: matriks numpy harus dihindari demi array. Catatan dari dokumentasi -> "Tidak lagi direkomendasikan untuk menggunakan kelas ini, bahkan untuk aljabar linier. Alih-alih menggunakan array reguler. Kelas dapat dihapus di masa depan." Lihat juga stackoverflow.com/a/61156350/6043669
HopeKing
21

Pada 3.5, Python akhirnya mendapat operator perkalian matriks . Sintaksnya adalah a @ b.

Petr Viktorin
sumber
2
Terima kasih! Yay, senang melihat bahwa saya bukan satu-satunya yang merasa bahwa notasi saat ini tidak dapat dibaca.
elexhobby
15

Ada situasi di mana operator titik akan memberikan jawaban yang berbeda ketika berhadapan dengan array seperti halnya berurusan dengan matriks. Misalnya, anggap sebagai berikut:

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

Mari kita ubah menjadi matriks:

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

Sekarang, kita dapat melihat output yang berbeda untuk dua kasus:

>>> print numpy.dot(a.T, b)
14
>>> print am.T*bm
[[1.  2.  3.]
 [2.  4.  6.]
 [3.  6.  9.]]
Jadiel de Armas
sumber
Untuk lebih spesifik, * adalah perkalian elemen-bijaksana, titik adalah perkalian matriks yang benar. Silakan lihat stackoverflow.com/a/18255635/1780570
Minh Triet
Itu karena sebagai array numpy, aT == a, transpos tidak melakukan apa pun.
patapouf_ai
Jika Anda menulis di = np.array ([[1], [2], [3]]), maka numpy.dot (at, b) akan memberi Anda hal yang sama. Perbedaan antara matix dan array bukan pada titik tetapi pada transpos.
patapouf_ai
Atau sebenarnya, jika Anda menulis a = numpy.array ([[1,2,3]]) maka aT akan benar-benar berubah dan semuanya akan berfungsi seperti dalam matriks.
patapouf_ai
8

Referensi dari http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html

..., penggunaan kelas numpy.matrix tidak disarankan , karena tidak menambahkan apa pun yang tidak dapat dilakukan dengan objek numpy.ndarray 2D , dan dapat menyebabkan kebingungan tentang kelas mana yang sedang digunakan. Sebagai contoh,

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

operasi scipy.linalg dapat diterapkan secara merata pada objek numpy.matrix atau 2D numpy.ndarray .

Yong Yang
sumber
7

Trik ini bisa jadi apa yang Anda cari. Ini adalah semacam kelebihan operator yang sederhana.

Anda kemudian dapat menggunakan sesuatu seperti kelas Infix yang disarankan seperti ini:

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

Kutipan terkait dari PEP 465 - Operator infiks khusus untuk perkalian matriks , sebagaimana disebutkan oleh @ petr-viktorin, mengklarifikasi masalah yang dihadapi OP:

[...] numpy menyediakan dua tipe berbeda dengan __mul__metode berbeda . Untuk numpy.ndarrayobjek, *melakukan perkalian elemen, dan perkalian matriks harus menggunakan pemanggilan fungsi ( numpy.dot). Untuk numpy.matrixobjek, *melakukan perkalian matriks, dan perkalian elemen membutuhkan sintaks fungsi. Menulis kode menggunakan numpy.ndarrayberfungsi dengan baik. Menulis kode menggunakan numpy.matrixjuga berfungsi dengan baik. Tetapi masalah dimulai segera setelah kami mencoba mengintegrasikan dua bagian kode ini bersama-sama. Kode yang mengharapkan ndarraydan mendapat matrix, atau sebaliknya, dapat macet atau mengembalikan hasil yang salah

Pengenalan @operator infiks harus membantu menyatukan dan menyederhanakan kode matriks python.

cod3monk3y
sumber
1

Fungsi matmul (karena numpy 1.10.1) berfungsi dengan baik untuk kedua jenis dan mengembalikan hasil sebagai kelas matriks 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))

Keluaran:

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

Sejak python 3.5 seperti yang disebutkan sebelumnya Anda juga dapat menggunakan operator perkalian matriks baru @seperti

C = A @ B

dan dapatkan hasil yang sama seperti di atas.

Ketenangan
sumber