2017-04-06 218 views
1

我有許多3 * 2矩陣(A1,A2,A3 ..),每個3 * 2都是一個畫圖。在兩次抽籤的情況下,我們有一個3 * 4(我們水平疊加每個A1,A2的抽籤)。顯然,我更容易將3 * 4矩陣(A)繪製爲更大的矩陣,而不是一遍又一遍地繪製3 * 2。矩陣乘法的矢量化

但我需要爲每個抽獎(每個A1,A2 ......)的矩陣B.說A1 * B執行矩陣乘法,和A2 * B ... AN * B

#each draw of the 3*2 matrix 
A1 = np.array([[ 0, 1], 
       [ 4, 5], 
       [ 8, 9]]) 

A2 = np.array([[ 2, 3], 
       [ 6, 7], 
       [ 10, 11]]) 

# A is [A1,A2] 
# Easier to draw A once for all (the larger matrix) 
A = np.array([[ 0, 1, 2, 3], 
       [ 4, 5, 6, 7], 
       [ 8, 9, 10, 11]]) 

b = np.array([[ 0, 1], 
       [ 4, 5] 
       ]) 

desired output 
array([[ 4, 5, 12, 17], 
     [20, 29, 28, 41], 
     [36, 53, 44, 65]]) 
+0

你是什麼意思通過「draw」? –

+0

@ juanpa.arrivillaga,A1,A2 ..... a從一些分佈重新繪製,它們是相似的。 – alphabetagamma

+0

所以你想要'np.hstack([A1.dot(b),A2.dot(b)])',但是用'A'來代替? –

回答

4

可以重塑矩陣A爲2列,使其適形於b,做矩陣乘法,然後重塑回:

np.dot(A.reshape(-1, 2), b).reshape(3, -1) 

#array([[ 4, 5, 12, 17], 
#  [20, 29, 28, 41], 
#  [36, 53, 44, 65]]) 
2

轉變你的觀點。你不必要地鎖定自己到3 x 2

你能想到的A1A22x3代替,然後A

array([[ 0, 4, 8, 2, 6, 10], 
     [ 1, 5, 9, 3, 7, 11]]) 

然後取b = b.T

array([[0, 4], 
     [1, 5]]) 

轉置這樣你可以做你運行

b @ A 

array([[ 4, 20, 36, 12, 28, 44], 
     [ 5, 29, 53, 17, 41, 65]]) 

讓你的「畫」這個樣子

A = np.random.randint(10, size=(2, 9)) 
A 

array([[7, 2, 1, 0, 9, 9, 1, 0, 2], 
     [8, 6, 1, 6, 6, 2, 4, 2, 9]]) 

b @ A 

array([[32, 24, 4, 24, 24, 8, 16, 8, 36], 
     [47, 32, 6, 30, 39, 19, 21, 10, 47]]) 

​ 
3

如果您不確定如何存儲/堆棧傳入陣列,一種方式是堆疊那些爲3D陣列,使得那些進入陣列的每一個都其第一軸指數能夠 -

a = np.array((A1,A2)) 

採樣運行 -

In [143]: a = np.array((A1,A2)) 

In [144]: a.shape 
Out[144]: (2, 3, 2) 
      |-----------------> axis of stacking 

然後,拿到equivalen每個進入陣列的矩陣乘法的T個輸出與b,我們可以在3D堆疊陣列a上使用np.tensordotb,從而從ab丟失最後軸和第一總和中還原,像這樣 -

out = np.tensordot(a,b,axes=((2),(0))) 

讓我們來看看輸出值,並與A1,A2等的每個矩陣乘法進行比較。 -

In [138]: out[0] 
Out[138]: 
array([[ 4, 5], 
     [20, 29], 
     [36, 53]]) 

In [139]: out[1] 
Out[139]: 
array([[12, 17], 
     [28, 41], 
     [44, 65]]) 

In [140]: A1.dot(b) 
Out[140]: 
array([[ 4, 5], 
     [20, 29], 
     [36, 53]]) 

In [141]: A2.dot(b) 
Out[141]: 
array([[12, 17], 
     [28, 41], 
     [44, 65]]) 

因此,本質上與此層疊動作,後來tensordot我們:

out[0], out[1], .... = A1.dot(b), A2.dot(b), .... 

替代np.tensordot -

我們可以用一個簡單的版本np.matmul,得到與tensordot相同的輸出 -

out = np.matmul(a,b) 

關於Python 3.5,還有一個更簡單的版本替換np.matmul,將@ operator -

out = a @ b 
3

即使不計算所需einsum可以幫助我們思考這個問題:

In [584]: np.einsum('ij,jk->ik', A1,b) 
Out[584]: 
array([[ 4, 5], 
     [20, 29], 
     [36, 53]]) 
In [585]: np.einsum('ij,jk->ik', A2,b) 
Out[585]: 
array([[12, 17], 
     [28, 41], 
     [44, 65]]) 

A是(3,4),它不會與(2,2)b一起使用。可以把它想象成嘗試使用加倍的j尺寸:'i(2j),jk->i?k'。但是如果我們插入一個軸呢? 'IMK,JK-> IMK'?或者將額外的維度添加到i

In [587]: np.einsum('imj,jk->imk', A.reshape(3,2,2),b) 
Out[587]: 
array([[[ 4, 5], 
     [12, 17]], 

     [[20, 29], 
     [28, 41]], 

     [[36, 53], 
     [44, 65]]]) 

數字在那裏,只是形狀是(3,2,2)。

In [590]: np.einsum('imj,jk->imk', A.reshape(3,2,2),b).reshape(3,4) 
Out[590]: 
array([[ 4, 5, 12, 17], 
     [20, 29, 28, 41], 
     [36, 53, 44, 65]]) 

或者你也可以從一開始就建立A使mij,jk->mik作品(@Divaker

@Psidom

np.einsum('ij,jk->ik', A.reshape(3,2,2).reshape(-1,2) ,b).reshape(3,-1) 

`@piRSquared':

'kj,jI->kI` 
+0

我會重新審視這一個。我想要和朋友一起做好事。 – piRSquared