元素明智的矩阵和向量的点积

时间:2017-04-14 16:08:03

标签: python numpy matrix numpy-broadcasting

确实存在类似的问题hereherehere,但我并不真正理解如何将它们恰好应用于我的案例。

我有一个矩阵数组和一组向量,我需要逐元素的点积。插图:

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

更复杂

2 个答案:

答案 0 :(得分:3)

使用np.einsum,您可以使用:

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

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

答案 1 :(得分: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.]])