当然,最快的方法是不使用 Python 中的任何 for 循环或 itertools 中的生成器,而是使用 Numpy 中的矢量化数学,如下所示:
n = len(delta_vec)
jj, kk = np.triu_indices(n, 1)
ww = 1. / np.exp((mjd_list[kk] - mjd_list[jj]) / avg_time)
w_sum = np.sum(ww)
PP = delta_vec[jj] * delta_vec[kk]
j_index = np.sum(ww * np.sign(PP) * np.sqrt(np.abs(PP)))
其中所有带有双字母的变量都是长度为n 的向量。请注意,您必须将列表转换为 numpy-arrays 才能正常工作。您甚至可以通过将1. / exp((a - b) / c) 替换为exp((b - a) / c) 来获得更快的速度。
说明:您正在使用直到n 的所有索引对进行计算,而不是使用具有相同索引的对(所以没有 1,1)并且对中的第一个总是最小的数字(所以没有 2 ,1)。如果您要制作所有可能对的二维矩阵,您会发现您只在对角线以上的元素上进行计算,因此您可以使用函数np.triu_index。为了证明这是可行的,您的循环会生成这些索引:
In [18]: n = 4
...: for j in range(0, n - 1, 1):
...: for k in range(j + 1, n, 1):
...: print j, k
0 1
0 2
0 3
1 2
1 3
2 3
您可以使用triu_indices 生成完全相同的索引:
In [19]: np.triu_indices(n, 1)
Out[19]: (array([0, 0, 0, 1, 1, 2]), array([1, 2, 3, 2, 3, 3]))
正确性和速度的快速测试:
import numpy as np
# generate some fake data
n = 300
mjd_vec = np.random.rand(n)
delta_vec = np.random.rand(n)
mjd_list = list(mjd_vec)
delta_list = list(delta_vec)
avg_time = 123
def f1():
w_sum = j_index = 0
n = len(delta_list)
for j in range(0, n - 1, 1):
for k in range(j + 1, n, 1):
w = 1. / np.exp((mjd_list[k] - mjd_list[j]) / avg_time)
w_sum = w_sum + w
P = delta_vec[j] * delta_vec[k]
j_index = j_index + w * np.sign(P) * np.sqrt(np.abs(P))
return w_sum, j_index
def f2():
n = len(delta_vec)
jj, kk = np.triu_indices(n, 1)
ww = 1. / np.exp((mjd_vec[kk] - mjd_vec[jj]) / avg_time)
w_sum = np.sum(ww)
PP = delta_vec[jj] * delta_vec[kk]
j_index = np.sum(ww * np.sign(PP) * np.sqrt(np.abs(PP)))
return w_sum, j_index
结果:
In [3]: f1()
Out[3]: (44839.864280781003, 18985.189058689775)
In [4]: f2()
Out[4]: (44839.864280781003, 18985.189058689775)
In [5]: timeit f1()
1 loops, best of 3: 629 ms per loop
In [6]: timeit f2()
100 loops, best of 3: 7.88 ms per loop
因此,numpy 版本产生相同的结果,并且快了 80 倍!