我正在寻找有关解决以下问题的最有效方法的建议:
我有两个数组,分别称为A和B。它们的形状均为NxNx3。它们代表位置的两个2D矩阵,其中每个位置都是x,y和z坐标的向量。
我想创建一个形状为NxN的名为C的新数组,其中C [i,j]是向量A [i,j]和B [i,j]的点积。
这是到目前为止我提出的解决方案。第一个使用numpy的einsum函数(在此进行了详细介绍)。第二种使用numpy的广播规则及其sum函数。
>>> import numpy as np
>>> A = np.random.randint(0, 10, (100, 100, 3))
>>> B = np.random.randint(0, 10, (100, 100, 3))
>>> C = np.einsum("ijk,ijk->ij", A, B)
>>> D = np.sum(A * B, axis=2)
>>> np.allclose(C, D)
True
有没有更快的方法?我曾经听到过一些杂语,说numpy的tensordot函数可以快速发展,但我一直都很难理解它。使用numpy的点或内部函数呢?
在某些情况下,A和B数组通常具有100到1000个元素。
任何指导,不胜感激!
经过一些调整,我们可以使用matmul
。想法是将前两个维视为“批量”维,dot
最后一个维视为:
In [278]: E = A[...,None,:]@B[...,:,None]
In [279]: E.shape
Out[279]: (100, 100, 1, 1)
In [280]: E = np.squeeze(A[...,None,:]@B[...,:,None])
In [281]: np.allclose(C,E)
Out[281]: True
In [282]: timeit E = np.squeeze(A[...,None,:]@B[...,:,None])
130 µs ± 2.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [283]: timeit C = np.einsum("ijk,ijk->ij", A, B)
90.2 µs ± 1.53 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
比较时间可能会有些棘手。在当前版本中,einsum
可以根据尺寸采取不同的路线。在某些情况下,似乎将任务委托给了matmul
(或至少与相同的底层BLAS类似代码)。虽然einsum
在此测试中更快是很好的,但我不会对此进行概括。
tensordot
只需调整数组的形状(并在需要时转置),以便可以应用普通的2d np.dot
。实际上,它在这里不起作用,因为您将前两个轴视为“批处理”,就像outer product
在它们上那样。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句