您可以使用 Numpy 中的矢量化来删除代码中的所有 for 循环。我建议您在开始冒险时阅读Look Ma No For Loops。
我以您的示例为例,并使用random 生成了一些垃圾数据来代替您的数组和变量。
import numpy as np
import random
import time
kvec_used = 0
k_array = []
sqmax = 10
beta = .5
kfac = []
sites = 3
q_array_initial = r_cart_initial = [.1, .2, .3]
for i in range(12000):
temp = [random.random(), random.random(), random.random()]
k_array.append(temp)
kfac.append(random.random())
mytime = time.time()
for i in range(12000):
cossum = 0
sinsum = 0
sq = k_array[i][0]**2 + k_array[i][1]**2 + k_array[i][2]**2
if sq <= sqmax and sq>0:
kvec_used = kvec_used + 1
kfac[i] = np.exp(-sq/(4*beta**2))/(sq)
for j in range(sites):
cossum = cossum + q_array_initial[j]*np.cos(np.dot(k_array[i],r_cart_initial[j]))
sinsum = sinsum + q_array_initial[j]*np.sin(np.dot(k_array[i],r_cart_initial[j]))
cos_part = (abs(cossum))**2
sin_part = (abs(sinsum))**2
print("looped", time.time() - mytime)
mytime = time.time()
k_array = np.asarray(k_array)
sq = np.square(k_array[:, 0]) + np.square(k_array[:, 1]) + np.square(k_array[:, 2])
sq = sq[np.where(np.logical_and(sq[:] <= sqmax, sq[:] > 0))]
kvec = np.shape(sq)[0]
kfac = np.exp(-sq[:]/(4*beta**2))/(sq[:])
for j in range(sites):
cossum = cossum + q_array_initial[j]*np.cos(np.dot(k_array[i],r_cart_initial[j]))
sinsum = sinsum + q_array_initial[j]*np.sin(np.dot(k_array[i],r_cart_initial[j]))
cos_part = (abs(cossum))**2
sin_part = (abs(sinsum))**2
print("vectorized:", time.time() - mytime)
通过仅对第一个 for 循环进行矢量化,当我使用 time.time() 进行测量时,我的速度提高了约 100 倍。在我的机器上,这段代码的输出是:
looped 0.40552735328674316
vectorized: 0.004940986633300781
当你对第二个循环进行矢量化时,你应该能够加快速度。
编辑:我刚刚意识到您在原始问题中要求提供更多解释。我上面链接的文章详细解释了一些事情,并且是我第一次开始对大型数据集进行矢量化时使用的。但是,我可以提供一个超级简单的解释来帮助您了解这里:
当你有一个大数组时,在 Python 中运行for 循环实际上有点慢。 Numpy 使用了一些更高级的幕后代码,它们可以比在for 循环中顺序运行操作更快。对于新手学习这一点,您可以接受 Numpy 暂时是“神奇的”。这里最大的收获是,与其对数组的ith 元素进行操作,不如告诉Numpy 对整个事物进行操作,表示为myarray[:]。您可以将其扩展到多维数组。一个完整的二维数组是myarray[:, :]。如果(从电子表格的角度考虑)您只想对第 0 列和 2d 数组上的所有行进行操作,则变为 myarray[:, 0]。
在这里,我使用了花哨的 Numpy 特定方法 where 和 logical_and 来替换您的 if 条件。这是另一种向量化技术,它能够比迭代方法更快地处理条件语句。
我特意留下了第二个for 循环未翻译作为练习给你。没有人不吃苦就学!您在这里使用np.cos 和np.sin 做得很好,但是您以迭代的方式使用它们。使用向量方法对结果向量的所有元素运行这些数学运算符。