【问题标题】:Multiply array of vectors with array of matrices; return array of vectors?将向量数组与矩阵数组相乘;返回向量数组?
【发布时间】:2016-03-09 14:40:10
【问题描述】:

我有一个形状为 (n,3) 的行向量的 numpy 数组和另一个形状为 (n,3,3) 的矩阵的 numpy 数组。我想将 n 个向量中的每一个与相应的矩阵相乘,并返回结果向量的形状为 (n,3) 的数组。

到目前为止,我一直在使用 for 循环遍历 n 个向量/矩阵并逐项进行乘法运算。

我想知道是否有更 numpy-ish 的方式来做到这一点。一种没有 for 循环甚至可能更快的方法。

//编辑1:

根据要求,这是我的循环代码(带有n = 10):

    arr_in = np.random.randn(10, 3)
    matrices = np.random.randn(10, 3, 3)

    for i in range(arr_in.shape[0]): # 10 iterations
        arr_out[i] = np.asarray(np.dot(arr_in[i], matrices[i]))

【问题讨论】:

  • 分享你的循环代码?
  • 我会的,等一下……
  • 使用编辑后的代码,输出似乎是(n,3,3) 而不是(n,3).
  • 嗯,是的,我明白了……等一下……我会更正代码。奇怪的是:这个简化的示例完全按照预期在开发环境中工作。

标签: python arrays numpy matrix


【解决方案1】:

dot-product 本质上是沿两个输入数组的axis=1 执行缩减。尺寸可以这样表示 -

arr_in   :     n   3 
matrices : n   3   3

因此,解决它的一种方法是将arr_in 的维度“推”到前面一个axis/dimension,从而在axis=2 的3D 数组版本中创建一个单一维度。然后,沿axis = 1 对元素进行求和会得到我们想要的输出。让我们展示一下-

arr_in   : n   [3]   1 
matrices : n   [3]   3

现在,这可以通过两种方式实现。

1) 使用np.einsum -

np.einsum('ij,ijk->ik',arr_in,matrices)

2) 使用NumPy broadcasting -

(arr_in[...,None]*matrices).sum(1)

运行时测试和验证输出(einsum 版本)-

In [329]: def loop_based(arr_in,matrices):
     ...:     arr_out = np.zeros((arr_in.shape[0], 3))
     ...:     for i in range(arr_in.shape[0]):
     ...:         arr_out[i] =  np.dot(arr_in[i], matrices[i])
     ...:     return arr_out
     ...: 
     ...: def einsum_based(arr_in,matrices):
     ...:     return np.einsum('ij,ijk->ik',arr_in,matrices)
     ...: 

In [330]: # Inputs
     ...: N = 16935
     ...: arr_in = np.random.randn(N, 3)
     ...: matrices = np.random.randn(N, 3, 3)
     ...: 

In [331]: np.allclose(einsum_based(arr_in,matrices),loop_based(arr_in,matrices))
Out[331]: True

In [332]: %timeit loop_based(arr_in,matrices)
10 loops, best of 3: 49.1 ms per loop

In [333]: %timeit einsum_based(arr_in,matrices)
1000 loops, best of 3: 714 µs per loop

【讨论】:

  • 这给出了转置。 IE。 matrix[i].T.dot(arr_in[i]),而不是 matrix[i].dot(arr_in[i])。我猜这取决于 OP 想要什么。
  • 我需要未转置的乘法。
  • np.einsum 建议就像一个魅力,但并不比 for 循环快多少。无论如何,我想我会坚持下去。谢谢!
  • @HendrikWiese 您的实际用例的输入数组形状是什么?
  • 在一种情况下,例如它是 (16935, 3)(以及相应的矩阵:(16935, 3, 3))
【解决方案2】:

您可以使用np.einsum。要为每个向量矩阵对获取v.dot(M),请使用np.einsum("...i,...ij", arr_in, matrices)。要获取M.dot(v),请使用np.einsum("...ij,...i", matrices, arr_in)

【讨论】:

  • 好的,我试试看。
猜你喜欢
  • 1970-01-01
  • 2020-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多