【发布时间】:2017-09-05 23:56:58
【问题描述】:
我正在计算时间序列的值(通过 myvalues 表示)。下面的代码识别事件发生的位置 (cross_indices),然后计算最后 8 个事件 (n_crosses)。第 8 次交叉相对于每行时间的索引在 Series max_lookback 中设置。
设置max_lookback 的总代码只需要约0.5 秒。但是,当我运行 pd.apply() 以获取从当前索引到 max_lookback 的 myvalues 的最小值和最大值时,代码需要 ~运行 22 秒。
我认为 apply() 应该比 for 循环更快地遍历行。为什么代码需要这么长时间才能执行,我怎样才能显着加快它的速度?
程序输出是
minmax 的总时间为 22.469 秒
总运行时间为 22.93 秒
import pandas as pd
import numpy as np
import timeit
complete_start = timeit.default_timer()
indices = pd.Series( range(20000), name='Index')
sample_from = np.append(np.zeros(9), 1) #10% odds of selecting 1
cross = pd.Series( np.random.choice( sample_from, size=len(indices) ), name='Cross' )
#cross = pd.Series(
cross_indices = np.flatnonzero( cross )
n_crosses = 8
def set_max_lookback(index):
sub = cross_indices[ cross_indices <= index ]
#get integer index where crosses occurred
if len( sub ) < n_crosses:
return int( 0 )
return int( sub[ len(sub) - n_crosses ] )
max_lookback = pd.Series( indices.apply( set_max_lookback ), name='MaxLookback' )
start = timeit.default_timer()
myvalues = pd.Series( np.random.randint(-100,high=100, size=len(indices) ), name='Random' )
def minmax_of_zero_crosses(index):
sub = myvalues.iloc[ range( max_lookback[index], index+1 ) ]
return ( sub.min(), sub.max() )
minmax_as_tuple_series = pd.Series( indices.apply( minmax_of_zero_crosses ), name='Min' )
minmax_df = pd.DataFrame( minmax_as_tuple_series.tolist() )
minmax_df.columns = [ 'Min', 'Max' ]
maxz = minmax_df['Max']
minz = minmax_df['Min']
end = timeit.default_timer()
print('total time of minmax is ' + str(end-start) + ' seconds.')
complete_end = timeit.default_timer()
print('total runtime is ' + str(complete_end-complete_start) + ' seconds.')
编辑 1
根据 Mitch 的评论,我仔细检查了 max_lookback 设置。使用 n_crosses=3,您可以看到为第 19,995 行选择了正确的索引 19,981。图片上看不到的列标签是index、myvalues、cross、max_lookback。
df = pd.DataFrame([myvalues, cross, max_lookback, maxz, minz ] ).transpose()
print(df.tail(n=60))
以图像为例,对于第 19,999 行,我想在第 19,981 行(max_lookback 列)和 19,999(即 -95 和 +97)之间找到 myvalues 的最小值/最大值。
【问题讨论】:
-
与您所听到的相反,逐行应用几乎从来都不是有效的解决方案。它不是矢量化的,实际上是一个底层的 for 循环。
-
另外,您确定目前它工作正常吗?我在质疑你的
max_lookback值......据我所知,它们并没有传播回 8 年前的事件。 -
用 for 循环替换 apply() 将时间增加到约 27 秒。我只是通过创建一个小屏幕截图仔细检查了最大回溯值。我将编辑帖子以确认工作。
-
是的,当然,应用速度略快。不过,使用矢量化解决方案您将看到的性能提升会非常更大。我只是想拼凑出你到底在做什么。
-
啊,没关系,我知道你是如何使用
max_lookback的。现在看看。
标签: python performance pandas numpy max