2017-04-06 215 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