Код, который вы предоставили, довольно большой и грязный. Тем не менее, самая большая проблема заключается в том, что использовать NumPy неправильно. Numpy это все о векторизации, а не петли. Так что how can I further speed up my code?
- используйте numpy правильно.
Давайте рассмотрим очень небольшую часть вашего кода:
# original code with nested loops with +1 to avoid zero division
def f_1(rr, pchargepos, nchargepos, phiext):
for pos1 in range(n):
for pos2 in range(int(len(nchargepos))):
phiext[pos1] += (
1 / (np.linalg.norm(rr[pos1] - pchargepos[pos2]) + 1) -
1 / (np.linalg.norm(rr[pos1] - nchargepos[pos2]) + 1))
return phiext
# modified code with numpy methods instead of loops
def f_2(rr, pchargepos, nchargepos, phiext):
a = np.tile(pchargepos, (len(rr), 1))
b = np.tile(nchargepos, (len(rr), 1))
c = np.tile(rr, (len(pchargepos), 1)).T
d = 1 / (abs(c - a) + 1)
e = 1 / (abs(c - b) + 1)
phiext += (d - e).sum(axis=1)
return phiext
if __name__ == '__main__':
n, m = 100, 200
rr = np.random.randint(-10, 10, (n,))
pchargepos = np.random.randint(-10, 10, (m,))
nchargepos = np.random.randint(-10, 10, (m,))
phiext = np.zeros((n,))
ans_1 = f_1(rr, pchargepos, nchargepos, phiext)
phiext = np.zeros((n,))
ans_2 = f_2(rr, pchargepos, nchargepos, phiext)
# check results
print(sum(ans_1), sum(ans_2))
Время работы на моей машине:
%timeit f_1(rr, pchargepos, nchargepos, phiext)
211 ms ± 967 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit f_2(rr, pchargepos, nchargepos, phiext)
205 µs ± 214 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Так что numpy примерно в 1000 раз быстрее, чем ваши вложенные циклы в обычном питоне.