2017-04-14 56 views
2

真的有類似的問題here,here,here,但我真的不明白如何正確地將它們應用於我的案例。矩陣和向量的元素智慧點積

我有一個矩陣數組和向量數組,我需要基於元素的點積。插圖:

In [1]: matrix1 = np.eye(5) 

In [2]: matrix2 = np.eye(5) * 5 

In [3]: matrices = np.array((matrix1,matrix2)) 

In [4]: matrices 
Out[4]: 
array([[[ 1., 0., 0., 0., 0.], 
     [ 0., 1., 0., 0., 0.], 
     [ 0., 0., 1., 0., 0.], 
     [ 0., 0., 0., 1., 0.], 
     [ 0., 0., 0., 0., 1.]], 

     [[ 5., 0., 0., 0., 0.], 
     [ 0., 5., 0., 0., 0.], 
     [ 0., 0., 5., 0., 0.], 
     [ 0., 0., 0., 5., 0.], 
     [ 0., 0., 0., 0., 5.]]]) 

In [5]: vectors = np.ones((5,2)) 

In [6]: vectors 
Out[6]: 
array([[ 1., 1.], 
     [ 1., 1.], 
     [ 1., 1.], 
     [ 1., 1.], 
     [ 1., 1.]]) 

In [9]: np.array([m @ v for m,v in zip(matrices, vectors.T)]).T 
Out[9]: 
array([[ 1., 5.], 
     [ 1., 5.], 
     [ 1., 5.], 
     [ 1., 5.], 
     [ 1., 5.]]) 

這最後一行是我期望的輸出。不幸的是,它效率非常低,例如matrices @ vectors計算由於廣播而產生的不需要的點積(如果我理解的很好,它返回2個向量的第一個矩陣點和2個向量的第二個矩陣點)實際上更快。

我猜np.einsumnp.tensordot可能會在這裏有所幫助,但我所有的嘗試都失敗了:

In [30]: np.einsum("i,j", matrices, vectors) 
ValueError: operand has more dimensions than subscripts given in einstein sum, but no '...' ellipsis provided to broadcast the extra dimensions. 

In [34]: np.tensordot(matrices, vectors, axes=(0,1)) 
Out[34]: 
array([[[ 6., 6., 6., 6., 6.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.]], 

     [[ 0., 0., 0., 0., 0.], 
     [ 6., 6., 6., 6., 6.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.]], 

     [[ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 6., 6., 6., 6., 6.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.]], 

     [[ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 6., 6., 6., 6., 6.], 
     [ 0., 0., 0., 0., 0.]], 

     [[ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 6., 6., 6., 6., 6.]]]) 

注:我的真實的情況是使用更復雜的矩陣比matrix1matrix2

回答

3

隨着np.einsum,你可能使用:

np.einsum("ijk,ki->ji", matrices, vectors) 

#array([[ 1., 5.], 
#  [ 1., 5.], 
#  [ 1., 5.], 
#  [ 1., 5.], 
#  [ 1., 5.]]) 
+0

我想就是這樣。我必須在這個愛因斯坦符號上工作,我猜...謝謝! – nicoco

+0

不客氣。很高興幫助! – Psidom

1

您可以使用@作爲如下所示

matrices @ vectors.T[..., None] 
# array([[[ 1.], 
#   [ 1.], 
#   [ 1.], 
#   [ 1.], 
#   [ 1.]], 

#  [[ 5.], 
#   [ 5.], 
#   [ 5.], 
#   [ 5.], 
#   [ 5.]]]) 

正如我們可以看出它計算正確的東西,但安排他們錯了。因此

(matrices @ vectors.T[..., None]).squeeze().T 
# array([[ 1., 5.], 
#  [ 1., 5.], 
#  [ 1., 5.], 
#  [ 1., 5.], 
#  [ 1., 5.]]) 
+0

這也適用,顯然它和@ Psidom的解決方案一樣快。我會接受他的回答,因爲他速度更快,但這相當好... – nicoco

+0

@nicoco很好。感謝您的時間。這是有用的知道。 –