我正在处理一段庞大的代码,发现需要加速其中的某个部分。我已经创建了下面展示的 MWE
:
import numpy as np
import time
def random_data(N):
# Generate some random data.
return np.random.uniform(0., 10., N).tolist()
# Lists that contain all the data.
list1 = [random_data(10) for _ in range(1000)]
list2 = [random_data(1000), random_data(1000)]
# Start taking the time.
tik = time.time()
list4 = []
# Loop through all elements in list1.
for elem in list1:
list3 = []
# Loop through elements in list2.
for elem2 in zip(*list2):
A = np.exp(-0.5*((elem[0]-elem2[0])/elem[3])**2)
B = np.exp(-0.5*((elem[1]-elem2[1])/elem[3])**2)
list3.append(A*B)
# Sum elements in list3 and append result to list4.
sum_list3 = sum(list3) if sum(list3)>0. else 1e-06
list4.append(sum_list3)
# Print the elapsed time.
print time.time()-tik
< p > list1
和 list2
的奇怪格式是因为这个代码块需要它们。
显而易见的部分,大部分时间都花在了递归计算A
和B
项上。
有没有办法加速这段代码的执行而不必进行并行化(我以前尝试过,但给我带来了很多 麻烦)?我可以使用任何包,例如numpy
,scipy
等。
添加
这是应用abarnert的优化和Jaime的建议后的结果,只进行了一次指数运算。在我的系统上,优化后的函数平均快了约60倍。
import numpy as np
import timeit
def random_data(N):
return np.random.uniform(0., 10., N).tolist()
# Lists that contain all the data.
list1 = [random_data(10) for _ in range(1000)]
list2 = [random_data(1000), random_data(1000)]
array1 = np.array(list1)
array2 = np.array(zip(*list2))
# Old non-optimezed function.
def func1():
list4 = []
# Process all elements in list1.
for elem in list1:
# Process all elements in list2.
list3 = []
for elem2 in zip(*list2):
A = np.exp(-0.5*((elem[0]-elem2[0])/elem[3])**2)
B = np.exp(-0.5*((elem[1]-elem2[1])/elem[3])**2)
list3.append(A*B)
# Sum elements in list3 and append result to list4.
sum_list3 = sum(list3) if sum(list3)>0. else 1e-06
list4.append(sum_list3)
# New optimized function.
def func2():
list4 = []
# Process all elements in list1.
for elem in array1:
# Broadcast over elements in array2.
A = -0.5*((elem[0]-array2[:,0])/elem[3])**2
B = -0.5*((elem[1]-array2[:,1])/elem[3])**2
array3 = np.exp(A+B)
# Sum elements in array3 and append result to list4.
sum_list3 = max(array3.sum(), 1e-10)
list4.append(sum_list3)
# Get time for both functions.
func1_time = timeit.timeit(func1, number=10)
func2_time = timeit.timeit(func2, number=10)
# Print hom many times faster func2 is versus func1.
print func1_time/func2_time
list1
和list2
。至于list3
和list4
,这是我能想到的最好的填充方法。如果您认为有所区别,它们都可以转换为numpy数组。 - Gabrielnumpy
的全部意义——如果您可以在数组上广播计算,那么您将用C循环替换Python循环,并消除每个算术计算周围的所有装箱/拆箱,这意味着您的代码通常会快4-400倍。 - abarnerttime.time
自己计时。 [timeit
] (http://docs.python.org/3/library/timeit.html) 模块(如果您在使用IPython,则使用%timeit
魔术语句)会确保选择正确的计时器,处理您甚至没有想到的许多问题,允许您重复测试并正确汇总它们,并使事情更简单。 (当您的代码比预期慢100倍时,通常不是太大的问题,但值得养成始终使用timeit
的习惯。) - abarnert