我有一个pandas数据帧df
,它的DatatimeIndex大约有2年,2列和超过3000万行的float64数据。我很快发现df.rolling('1d').mean()
和df.rolling('1d').max()
>>> n=100000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.max(), number=1)
2.5886592870228924
>>> n=100000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.mean(), number=1)
0.011829487979412079
>>> n=1000000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.max(), number=1)
53.8340517100296
>>> n=1000000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.mean(), number=1)
0.06093513499945402
如您所见,df.rolling('1d').mean()
比df.rolling('1d').max()
快几百倍。我希望它有点快,因为计算最大熊猫可能必须跟踪每一步滚动窗口中所有值的顺序。但是,很容易看到如何通过添加最多一个日志因子来实现这一点,所以我希望有一个较小的差异。如果这是最好的,那么使用df.rolling('1d').max
会对整个数据集造成痛苦,因为看起来每次都需要几个小时。
之前遇到过pandas的效率问题(Series.iloc索引),我很好奇这是否是一个熊猫问题,或者是否有更快的方法来解决这个问题。
最近在大熊猫的主分支中修复了这个问题。即使在完整数据集上,现在可以在2.35秒内计算滚动最大值,而在它可能需要数小时之前。感谢hexgnu的修复。
>>> runtime(lambda: df.rolling('1d').max())
2.3093386580003425
>>> n=100000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.max(), number=1)
0.015023122999991756
>>> n=1000000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.max(), number=1)
0.08013121400290402
>>> n=10000000; import timeit; r=df[:n].rolling('1d'); timeit.timeit(lambda: r.max(), number=1)
0.6795377829985227
>>> import timeit; r=df.rolling('1d'); timeit.timeit(lambda: r.max(), number=1)
2.3540661859951797
>>> len(df)
32819278
答案 0 :(得分:3)
Pandas正在使用linear scan over the window for every sample运行max的天真实现。因此,它是窗口大小的线性复杂度,即每天几百+样本,它将比平均值慢百倍。
可能的解决方法:花费几分钟,然后超过这个最大值数小时,然后是几天 - 它应该会产生一种日志效果,但常量可能会吞噬所有渐近优势。
更好的解决方案:将堆min_max实现贡献给pandas