如果我需要知道索引,循环遍历3d numpy数组的最快方法是什么。
... some sort of loop ...
do something with each element that requires a knowledge of i,j,k.
例如
for i in range(N):
for j in range(N):
for k in range(N):
index = # something that depends on i,j,k
B[index] = A[i][j][k]**2
实际的循环如下所示:
for z in range(Ngrid):
kz = 2*pi/LMAX*(z - Ngrid/2)
for y in range(Ngrid):
ky = 2*pi/LMAX*(y - Ngrid/2)
for x in range(Ngrid):
kx = 2*pi/LMAX*(x - Ngrid/2)
kk = sqrt(kx**2 + ky**2 + kz**2)
bind = int((kk - kmin)/dk)
if bind >= Nk:
continue
delk = delta_k[x][y][z]
Pk[bind] += (delk.real**2 + delk.imag**2)/2
Numk[bind] += 1
鉴于我们可以使用NumPy工具,解决问题的最快方法是完全不循环(如果问题是可并行/可矢量化的)。对于眼前的问题,似乎我们可以向量化它。这个问题与先前的问题非常相似Q&A
。因此,我们将从该帖子中借用一些东西,主要是围绕使用broadcasting
。
因此,我们将提供一个解决方案,例如:
KXYZ = 2*np.pi/LMAX*(np.arange(Ngrid) - Ngrid/2)
KK = np.sqrt(KXYZ[:,None,None]**2 + KXYZ[:,None]**2 + KXYZ**2)
BIND = ((KK - kmin)/dk).astype(int)
valid_mask = BIND<Nk
IDs = BIND[valid_mask]
vals = (delta_k.real[valid_mask]**2 + delta_k.imag[valid_mask]**2)/2
Pk += np.bincount( IDs, vals, minlength=len(Pk))
Numk += np.bincount( IDs, minlength=len(Numk))
运行时测试
方法-
def loopy_app(Ngrid, LMAX, kmin, dk, Nk, delta_k):
Pk = np.zeros(Nk)
Numk = np.zeros(Nk)
for z in range(Ngrid):
kz = 2*np.pi/LMAX*(z - Ngrid/2)
for y in range(Ngrid):
ky = 2*np.pi/LMAX*(y - Ngrid/2)
for x in range(Ngrid):
kx = 2*np.pi/LMAX*(x - Ngrid/2)
kk = np.sqrt(kx**2 + ky**2 + kz**2)
bind = int((kk - kmin)/dk)
if bind >= Nk:
continue
delk = delta_k[x,y,z]
Pk[bind] += (delk.real**2 + delk.imag**2)/2
Numk[bind] += 1
return Pk, Numk
def vectorized_app(Ngrid, LMAX, kmin, dk, Nk, delta_k):
Pk = np.zeros(Nk)
Numk = np.zeros(Nk)
KXYZ = 2*np.pi/LMAX*(np.arange(Ngrid) - Ngrid/2)
KK = np.sqrt(KXYZ[:,None,None]**2 + KXYZ[:,None]**2 + KXYZ**2)
BIND = ((KK - kmin)/dk).astype(int)
valid_mask = BIND<Nk
IDs = BIND[valid_mask]
vals = (delta_k.real[valid_mask]**2 + delta_k.imag[valid_mask]**2)/2
Pk += np.bincount( IDs, vals, minlength=len(Pk))
Numk += np.bincount( IDs, minlength=len(Numk))
return Pk, Numk
输入设置:
# Setup inputs with random numbers
Ngrid = 100
LMAX = 3.45
kmin = 0.345
dk = 1.56
Nk = 80
delta_k = np.random.rand(Ngrid,Ngrid,Ngrid) + 1j * \
np.random.rand(Ngrid,Ngrid,Ngrid)
时间:
In [186]: app1_out1, app1_out2 = loopy_app(Ngrid, LMAX, kmin, dk, Nk, delta_k)
...: app2_out1, app2_out2 = vectorized_app(Ngrid, LMAX, kmin, dk, Nk, delta_k)
...: print np.allclose(app1_out1, app2_out1)
...: print np.allclose(app1_out2, app2_out2)
...:
True
True
In [187]: %timeit loopy_app(Ngrid, LMAX, kmin, dk, Nk, delta_k)
...: %timeit vectorized_app(Ngrid, LMAX, kmin, dk, Nk, delta_k)
...:
1 loops, best of 3: 2.61 s per loop
10 loops, best of 3: 20.7 ms per loop
In [188]: 2610/20.7
Out[188]: 126.08695652173914
120x+
在这些输入上看到加速。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句