计算一系列numpy ndarray的外积

时间:2017-12-04 00:38:03

标签: python performance numpy matrix scientific-computing

我有一个存储在具有形状(N,3)的ndarray中的3D点 p 列表。我想用自己计算每个3d点的外积:

N = int(1e4)
p = np.random.random((N, 3))
result = np.zeros((N, 3, 3))
for i in range(N):
    result[i, :, :] = np.outer(p[i, :], p[i, :])

有没有办法在没有任何python级循环的情况下计算这个外部产品?问题是np.outer不支持axis参数之类的任何内容。

3 个答案:

答案 0 :(得分:4)

您可以使用广播:

p[..., None] * p[:, None, :]

此语法在第一个项的末尾(使其为Nx3x1)和第二个项的中间(使其为Nx1x3)插入轴。然后广播它们并产生Nx3x3结果。

答案 1 :(得分:2)

比我之前使用np.einsum更好的解决方案:

np.einsum('...i,...j', p, p)

甚至比广播方法更快:

In [ ]: %timeit p[..., None] * p[:, None, :]
514 µs ± 4.23 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [ ]: %timeit np.einsum('...i,...j', p, p)
169 µs ± 1.75 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

关于它是如何工作的我不太确定,我只是弄乱了einsum,直到我得到了我想要的答案:

In [ ]: np.all(np.einsum('...i,...j', p, p) == p[..., None] * p[:, None, :])
Out[ ]: True

答案 2 :(得分:0)

您至少可以使用apply_along_axis

result = np.apply_along_axis(lambda point: np.outer(point, point), 1, p)

然而,令人惊讶的是,这实际上比你的方法慢

In [ ]: %%timeit N = int(1e4); p = np.random.random((N, 3))
   ...: result = np.apply_along_axis(lambda point: np.outer(point, point), 1, p)
61.5 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [ ]: %%timeit N = int(1e4); p = np.random.random((N, 3))
   ...: result = np.zeros((N, 3, 3))
   ...: for i in range(N):
   ...:     result[i, :, :] = np.outer(p[i, :], p[i, :])
46 ms ± 709 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)