将这两个向量相乘的大多数 Pythonic 方法?
Most Pythonic way to multiply these two vectors?
我有两个具有形状的 ndarrays:
A = (32,512,640)
B = (4,512)
我需要将 A 和 B 相乘,以便得到一个新的 ndarray:
C = (4,32,512,640)
另一种思考方式是,向量 B 的每一行都沿 A 的轴 = -2 相乘,得到一个新的 1,32,512,640 立方体。 B的每一行可以循环形成1,32,512,640个立方体,然后可以使用np.concatenate
或np.vstack
来构建C,例如:
# Sample inputs, where the dimensions aren't necessarily known
a = np.arange(32*512*465, dtype='f4').reshape((32,512,465))
b = np.ones((4,512), dtype='f4')
# Using a loop
d = []
for row in b:
d.append(np.expand_dims(row[None,:,None]*a, axis=0))
# Or using list comprehension
d = [np.expand_dims(row[None,:,None]*a,axis=0) for row in b]
# Stacking the final list
result = np.vstack(d)
但我想知道是否可以使用 np.einsum
或 np.tensordot
之类的东西在一行中将其矢量化。我还在学习如何使用这两种方法,所以我不确定放在这里是否合适。
谢谢!
我们可以利用 broadcasting
after extending the dimensions of B
with None/np.newaxis
-
C = A * B[:,None,:,None]
对于 einsum
,它将是 -
C = np.einsum('ijk,lj->lijk',A,B)
这里没有减和,所以 einsum
不会比 explicit-broadcasting
好多少。但是因为我们正在寻找 Pythonic 解决方案,一旦我们通过它的字符串表示法就可以使用它。
让我们安排一些时间来完成事情 -
In [15]: m,n,r,p = 32,512,640,4
...: A = np.random.rand(m,n,r)
...: B = np.random.rand(p,n)
In [16]: %timeit A * B[:,None,:,None]
10 loops, best of 3: 80.9 ms per loop
In [17]: %timeit np.einsum('ijk,lj->lijk',A,B)
10 loops, best of 3: 109 ms per loop
# Original soln
In [18]: %%timeit
...: d = []
...: for row in B:
...: d.append(np.expand_dims(row[None,:,None]*A, axis=0))
...:
...: result = np.vstack(d)
10 loops, best of 3: 130 ms per loop
杠杆率multi-core
我们可以利用适用于 arithmetic operations
和 large data
的 multi-core capability of numexpr
,从而在此处获得一些性能提升。让我们花点时间-
In [42]: import numexpr as ne
In [43]: B4D = B[:,None,:,None] # this is virtually free
In [44]: %timeit ne.evaluate('A*B4D')
10 loops, best of 3: 64.6 ms per loop
在一行中:ne.evaluate('A*B4D',{'A':A,'B4D' :B[:,None,:,None]})
.
关于如何控制多核功能。
我有两个具有形状的 ndarrays:
A = (32,512,640)
B = (4,512)
我需要将 A 和 B 相乘,以便得到一个新的 ndarray:
C = (4,32,512,640)
另一种思考方式是,向量 B 的每一行都沿 A 的轴 = -2 相乘,得到一个新的 1,32,512,640 立方体。 B的每一行可以循环形成1,32,512,640个立方体,然后可以使用np.concatenate
或np.vstack
来构建C,例如:
# Sample inputs, where the dimensions aren't necessarily known
a = np.arange(32*512*465, dtype='f4').reshape((32,512,465))
b = np.ones((4,512), dtype='f4')
# Using a loop
d = []
for row in b:
d.append(np.expand_dims(row[None,:,None]*a, axis=0))
# Or using list comprehension
d = [np.expand_dims(row[None,:,None]*a,axis=0) for row in b]
# Stacking the final list
result = np.vstack(d)
但我想知道是否可以使用 np.einsum
或 np.tensordot
之类的东西在一行中将其矢量化。我还在学习如何使用这两种方法,所以我不确定放在这里是否合适。
谢谢!
我们可以利用 broadcasting
after extending the dimensions of B
with None/np.newaxis
-
C = A * B[:,None,:,None]
对于 einsum
,它将是 -
C = np.einsum('ijk,lj->lijk',A,B)
这里没有减和,所以 einsum
不会比 explicit-broadcasting
好多少。但是因为我们正在寻找 Pythonic 解决方案,一旦我们通过它的字符串表示法就可以使用它。
让我们安排一些时间来完成事情 -
In [15]: m,n,r,p = 32,512,640,4
...: A = np.random.rand(m,n,r)
...: B = np.random.rand(p,n)
In [16]: %timeit A * B[:,None,:,None]
10 loops, best of 3: 80.9 ms per loop
In [17]: %timeit np.einsum('ijk,lj->lijk',A,B)
10 loops, best of 3: 109 ms per loop
# Original soln
In [18]: %%timeit
...: d = []
...: for row in B:
...: d.append(np.expand_dims(row[None,:,None]*A, axis=0))
...:
...: result = np.vstack(d)
10 loops, best of 3: 130 ms per loop
杠杆率multi-core
我们可以利用适用于 arithmetic operations
和 large data
的 multi-core capability of numexpr
,从而在此处获得一些性能提升。让我们花点时间-
In [42]: import numexpr as ne
In [43]: B4D = B[:,None,:,None] # this is virtually free
In [44]: %timeit ne.evaluate('A*B4D')
10 loops, best of 3: 64.6 ms per loop
在一行中:ne.evaluate('A*B4D',{'A':A,'B4D' :B[:,None,:,None]})
.