我有一个存储在具有形状(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
参数之类的任何内容。
答案 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)