向量化大型 NumPy 乘法
Vectorize large NumPy multiplication
我对计算大型 NumPy 数组很感兴趣。我有一个大数组 A
,其中包含一堆数字。我想计算这些数字的不同组合的总和。数据结构如下:
A = np.random.uniform(0,1, (3743, 1388, 3))
Combinations = np.random.randint(0,3, (306,3))
Final_Product = np.array([ np.sum( A*cb, axis=2) for cb in Combinations])
我的问题是是否有更优雅和内存效率更高的方法来计算这个?当涉及 3-D 数组时,我发现使用 np.dot()
令人沮丧。
如果有帮助,Final_Product
的形状理想情况下应该是 (3743, 306, 1388)。当前 Final_Product
的形状为 (306, 3743, 1388),因此我可以重新调整形状以到达那里。
np.dot()
won't give give you the desired output , unless you involve extra step(s) that would probably include reshaping
. Here's one vectorized
approach using np.einsum
一次完成,没有任何额外的内存开销 -
Final_Product = np.einsum('ijk,lk->lij',A,Combinations)
为了完整性,这里有前面讨论过的np.dot
和reshaping
-
M,N,R = A.shape
Final_Product = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N)
运行时测试并验证输出 -
In [138]: # Inputs ( smaller version of those listed in question )
...: A = np.random.uniform(0,1, (374, 138, 3))
...: Combinations = np.random.randint(0,3, (30,3))
...:
In [139]: %timeit np.array([ np.sum( A*cb, axis=2) for cb in Combinations])
1 loops, best of 3: 324 ms per loop
In [140]: %timeit np.einsum('ijk,lk->lij',A,Combinations)
10 loops, best of 3: 32 ms per loop
In [141]: M,N,R = A.shape
In [142]: %timeit A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N)
100 loops, best of 3: 15.6 ms per loop
In [143]: Final_Product =np.array([np.sum( A*cb, axis=2) for cb in Combinations])
...: Final_Product2 = np.einsum('ijk,lk->lij',A,Combinations)
...: M,N,R = A.shape
...: Final_Product3 = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N)
...:
In [144]: print np.allclose(Final_Product,Final_Product2)
True
In [145]: print np.allclose(Final_Product,Final_Product3)
True
您可以使用 tensordot
而不是 dot
。您当前的方法相当于:
np.tensordot(A, Combinations, [2, 1]).transpose(2, 0, 1)
注意末尾的 transpose
以正确放置轴。
与 dot
一样,tensordot
函数可以向下调用快速 BLAS/LAPACK 库(如果安装了它们),因此对于大型数组应该表现良好。
我对计算大型 NumPy 数组很感兴趣。我有一个大数组 A
,其中包含一堆数字。我想计算这些数字的不同组合的总和。数据结构如下:
A = np.random.uniform(0,1, (3743, 1388, 3))
Combinations = np.random.randint(0,3, (306,3))
Final_Product = np.array([ np.sum( A*cb, axis=2) for cb in Combinations])
我的问题是是否有更优雅和内存效率更高的方法来计算这个?当涉及 3-D 数组时,我发现使用 np.dot()
令人沮丧。
如果有帮助,Final_Product
的形状理想情况下应该是 (3743, 306, 1388)。当前 Final_Product
的形状为 (306, 3743, 1388),因此我可以重新调整形状以到达那里。
np.dot()
won't give give you the desired output , unless you involve extra step(s) that would probably include reshaping
. Here's one vectorized
approach using np.einsum
一次完成,没有任何额外的内存开销 -
Final_Product = np.einsum('ijk,lk->lij',A,Combinations)
为了完整性,这里有前面讨论过的np.dot
和reshaping
-
M,N,R = A.shape
Final_Product = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N)
运行时测试并验证输出 -
In [138]: # Inputs ( smaller version of those listed in question )
...: A = np.random.uniform(0,1, (374, 138, 3))
...: Combinations = np.random.randint(0,3, (30,3))
...:
In [139]: %timeit np.array([ np.sum( A*cb, axis=2) for cb in Combinations])
1 loops, best of 3: 324 ms per loop
In [140]: %timeit np.einsum('ijk,lk->lij',A,Combinations)
10 loops, best of 3: 32 ms per loop
In [141]: M,N,R = A.shape
In [142]: %timeit A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N)
100 loops, best of 3: 15.6 ms per loop
In [143]: Final_Product =np.array([np.sum( A*cb, axis=2) for cb in Combinations])
...: Final_Product2 = np.einsum('ijk,lk->lij',A,Combinations)
...: M,N,R = A.shape
...: Final_Product3 = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N)
...:
In [144]: print np.allclose(Final_Product,Final_Product2)
True
In [145]: print np.allclose(Final_Product,Final_Product3)
True
您可以使用 tensordot
而不是 dot
。您当前的方法相当于:
np.tensordot(A, Combinations, [2, 1]).transpose(2, 0, 1)
注意末尾的 transpose
以正确放置轴。
与 dot
一样,tensordot
函数可以向下调用快速 BLAS/LAPACK 库(如果安装了它们),因此对于大型数组应该表现良好。