在过去的几天里,我一直在致力于改进python函数的运行时,这需要多次使用余数函数(%)以及其他一些东西。我的主要测试用例是超过80,000个元素的numpy数组(单调增加),有10000次迭代,尽管我也尝试过各种不同大小的数组。
最终,我达到了余数函数成为主要瓶颈的地步,并尝试了各种解决方案。这是我在运行以下代码时发现的行为:
import numpy as np
import time
a = np.random.rand(80000)
a = np.cumsum(a)
d = 3
start_time1 = time.time()
for i in range(10000):
b = a % d
d += 0.001
end_time1 = time.time()
d = 3
start_time2 = time.time()
for i in range(10000):
b = a - (d * np.floor(a / d))
d += 0.001
end_time2 = time.time()
print((end_time1 - start_time1) / 10000)
print((end_time2 - start_time2) / 10000)
输出为:
0.0031344462633132934
0.00022937238216400147
将数组大小增加到800,000时:
0.014903099656105041
0.010498356819152833
(对于这篇文章,我只运行了一次代码作为实际输出,同时试图理解问题,我得到了一致的结果。)
虽然这解决了我的运行时问题--我很难理解为什么。我是不是遗漏了什么?我能想到的唯一区别是额外的函数调用的开销,但第一种情况相当极端(1.5倍的运行时也不够好),如果是这种情况,我会认为np.remainder
函数的存在是没有意义的。
编辑:我尝试用非numpy循环测试相同的代码:
import numpy as np
import time
def pythonic_remainder(array, d):
b = np.zeros(len(array))
for i in range(len(array)):
b[i] = array[i] % d
def split_pythonic_remainder(array, d):
b = np.zeros(len(array))
for i in range(len(array)):
b[i] = array[i] - (d * np.floor(array[i] / d))
def split_remainder(a, d):
return a - (d * np.floor(a / d))
def divide(array, iterations, action):
d = 3
for i in range(iterations):
b = action(array, d)
d += 0.001
a = np.random.rand(80000)
a = np.cumsum(a)
start_time = time.time()
divide(a, 10000, split_remainder)
print((time.time() - start_time) / 10000)
start_time = time.time()
divide(a, 10000, np.remainder)
print((time.time() - start_time) / 10000)
start_time = time.time()
divide(a, 10000, pythonic_remainder)
print((time.time() - start_time) / 10000)
start_time = time.time()
divide(a, 10000, split_pythonic_remainder)
print((time.time() - start_time) / 10000)
我得到的结果是:
0.0003770533800125122
0.003932329940795899
0.018835473942756652
0.10940513386726379
我发现有趣的是,在非麻木的情况下,情况正好相反。
https://stackoverflow.com/questions/52242832
复制相似问题