gpt4 book ai didi

python - 使用元素求幂加速嵌套 for 循环

转载 作者:太空狗 更新时间:2023-10-29 22:30:39 26 4
gpt4 key购买 nike

我正在处理一个大型代码,我发现自己需要加快其中的特定部分。我创建了一个如下所示的 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

list1list2 的奇怪格式是因为这就是这段代码接收它们的方式。

最明显的部分是 AB 项的递归计算。

有什么方法可以加快这段代码的速度而不必对其进行并行化(我之前已经尝试过并且它给了我 a lot of troubles )?我愿意使用任何包,numpyscipy 等。


添加

这是应用 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

最佳答案

您希望逐渐将其从使用列表和循环转换为使用数组和广播,首先捕获最简单和/或最时间关键的部分,直到它足够快为止。

第一步是不要那样做zip(*list2)一遍又一遍(特别是如果这是 Python 2.x)。当我们这样做的时候,我们不妨将它存储在一个数组中,并对 list1 做同样的事情。 ——你现在仍然可以迭代它们。所以:

array1 = np.array(list1)
array2 = np.array(zip(*list2))
# …
for elem in array1:
# …
for elem2 in array2:

这不会加快速度——在我的机器上,它需要我们从 14.1 秒到 12.9——但它给了我们一个开始工作的地方。

您还应该删除 sum(list3) 的双重计算:

sum_list3 = sum(list3)
sum_list3 = sum_list3 if sum_list3>0. else 1e-06

与此同时,您想要 value <= 0 有点奇怪去1e-6 ,但是 0 < value < 1e-6一个人呆着。真的是故意的吗?如果没有,您可以解决这个问题,同时简化代码,方法是:

sum_list3 = max(array3.sum(), 1e-06)

现在,让我们广播AB计算:

# Broadcast over elements in list2.
A = np.exp(-0.5*((elem[0]-array2[:,0])/elem[3])**2)
B = np.exp(-0.5*((elem[1]-array2[:, 1])/elem[3])**2)
array3 = A*B

# Sum elements in list3 and append result to list4.
sum_list3 = max(array3.sum(), 1e-06)

list4.append(sum_list3)

这让我们从 12.9 秒减少到 0.12。您还可以通过广播 array1 更进一步,并替换 list4使用预分配数组等,但这可能已经足够快了。

关于python - 使用元素求幂加速嵌套 for 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21269833/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com