【发布时间】:2017-11-07 10:32:36
【问题描述】:
我有几个for 循环,最里面的循环会被执行很多次。这个最里面的循环包含一些使用 numpy 的繁重计算,所以所有这些都需要很多时间。所以我正在尝试优化最里面的循环。
最内层循环包含以下逻辑:
我有两个 numpy 数组(在现实生活中要大得多):
left = np.asarray([0.4, 0.2, 0.2, 0.7, 0.6, 0.2, 0.3])
right= np.asarray([0.2, 0.7, 0.3, 0.2, 0.1, 0.9, 0.7])
将这些与阈值进行比较,看看我应该向左还是向右。如果left[x] > 0.55 and right[x] < 0.45 我想向左走。
如果left[x] < 0.55 and right[x] > 0.45 我想向右走。
我已经通过创建两个布尔数组来解决这个问题,一个用于左侧,一个用于右侧,根据:
leftListBool = ((left > 0.55)*1 + (right < 0.45)*1 - 1) > 0
rightListBool = ((right > 0.55)*1 + (left < 0.45)*1 - 1) > 0
上面的例子给了我:
leftListBool = [False False False True True False False]
rightListBool = [False True False False False True True]
但是如果我最后一次向左走,我就不能向左走(右边也一样)。因此,我根据以下内容循环这些列表:
wentLeft = False
wentRight = False
a = 0
for idx, v in enumerate(leftListBool):
if leftListBool[idx] and not wentRight:
a += DoAThing(idx)
wentLeft = False
wentRight = True
elif rightListBool[idx] and not wentLeft:
a += DoAnotherThing(idx)
wentLeft = True
wentRight = False
DoAThing() 和 DoAnotherThing() 只是从 numpy 数组中获取一个值。
这是我在优化方面所做的(以前更糟)。请注意,我需要以正确的顺序执行 DoAThing() 和 DoAnotherThing(),因为它们取决于之前的值。
我尝试了什么?
我的第一个想法是创建一个leftListbool 和rightListBool 的统一列表,看起来像(左 = 1 和右 = -1):
unified = [0 1 0 -1 -1 1 1]
但我坚持以比以下更优化的方式做到这一点:
buyListBool.astype(int)-sellListBool.astype(int)
但即使我实现了这一点,我也只需要包含第一个值,例如,如果我有两个 1 彼此跟随,这将导致:
unified = [0 1 0 -1 0 1 0]
在这种情况下,我可以将 for 循环简化为:
for i in unified:
if i == 1:
a += DoAThing(a)
elif i == -1:
a += DoAnotherThing(a)
但即使是这个 for 循环也可以使用一些我还没有弄清楚的 numpy-magic 进行优化。
完整的可运行代码:
start = time.time()
topLimit = 0.55
bottomLimit = 0.45
for outI in range(200):
for midI in range(200):
topLimit = 0.55
bottomLimit = 0.45
res = np.random.rand(200,3)
left = res[:,0]
right = res[:,1]
valList = res[:,2]
#These two statements can probably be optimized
leftListBool = ((left > topLimit)*1 + (right < bottomLimit)*1 - 1) > 0
rightListBool = ((right > topLimit)*1 + (left < bottomLimit)*1 - 1) > 0
wentLeft = False
wentRight = False
a=0
#Hopefully this loop can be optimized
for idx, v in enumerate(leftListBool):
if leftListBool[idx] and not wentRight:
a += valList[idx]
wentLeft = False
wentRight = True
elif rightListBool[idx] and not wentLeft:
a += valList[idx]
wentLeft = True
wentRight = False
end = time.time()
print(end - start)
【问题讨论】:
-
我觉得这个问题适合codereview
-
leftListBool = ((left > 0.55)*1 + (right < 0.45)*1 - 1) > 0例如,这可能是leftListBool = (left > 0.55 AND right < 0.45) -
如果处理就这么简单,我认为任何微优化都不会产生重大影响。由于您将 DoAThing 和 DoAnotherThing 留在黑匣子中,我们无法判断它们是否代表重要的处理。
-
val到底是什么?我认为这是一个错字,应该是leftListBool,就像前面的例子一样。但是,如果您更正它(或提供它的生成方式)会很好。 -
@Ev.Kounis 如果这些是 numpy 数组,我真的可以做
left > 0.55 AND right < 0.45吗?
标签: python performance loops numpy optimization