【问题标题】:Pandas: Performance For Rolling Rank On Large DataframesPandas:在大型数据帧上滚动排名的性能
【发布时间】:2015-04-10 10:11:32
【问题描述】:

我希望将统计分析项目迁移到 pandas。我想在 N 天的滚动窗口中对 3 列进行排名。我已经找到了在这个问题 [rank-data-over-a-rolling-window][1] 中回答的方法,但是性能对于我的数据集(45K 行)来说是不够的。我发现最快的方法是使用bottleneck library或numpy argsort,如下所示。这显着提高了性能,但与应该具有相似性能的 rolling_mean 函数相比仍有一段距离。

编辑:我已经更新了下面的代码,以提供一个可重现的计时示例。系列排名功能是最灵活的,允许我选择如何对关系进行排名,但速度很慢。我能找到的最好的两个是瓶颈方法或 argsort。两者在性能上具有可比性,但对关系的处理有限制。但是,与滚动平均值相比,两者仍然慢得多?

rollWindow = 240
df = pd.DataFrame(np.random.randn(100000,4), columns=list('ABCD'), index=pd.date_range('1/1/2000', periods=100000, freq='1H'))
df.iloc[-3:-1]['A'] = 7.5
df.iloc[-1]['A'] = 5.5

df["SER_RK"] = pd.rolling_apply(df["A"], rollWindow, rollingRankOnSeries)
 # 28.9secs (allows competition/min ranking for ties)

df["SCIPY_RK"] = pd.rolling_apply(df["A"], rollWindow, rollingRankSciPy)
 # 70.89secs (allows competition/min ranking for ties)

df["BNECK_RK"] = pd.rolling_apply(df["A"], rollWindow, rollingRankBottleneck)
 # 3.64secs (only provides average ranking for ties)

df["ASRT_RK"] = pd.rolling_apply(df["A"], rollWindow, rollingRankArgSort)
 # 3.56secs (only provides competition/min ranking for ties)

df["MEAN"] = pd.rolling_mean(df['A'], window=rollWindow)
 # 0.008secs

def rollingRankOnSeries (array):
    s = pd.Series(array)
    return s.rank(method='min', ascending=False)[len(s)-1]

def rollingRankSciPy (array):
     return array.size + 1 - sc.rankdata(array)[-1]

def rollingRankBottleneck (array):
    return array.size + 1 - bd.rankdata(array)[-1]

def rollingRankArgSort (array):
    return array.size - array.argsort().argsort()[-1]


                        A   SER_RK  SCIPY_RK  BNECK_RK  ASRT_RK     MEAN  
2011-05-29 11:00:00  1.37       23      23.0      23.0     23   0.013526  
2011-05-29 12:00:00  0.45       85      85.0      85.0     85   0.016833   
2011-05-29 13:00:00  7.50        1       1.0       1.0      1   0.049606   
2011-05-29 14:00:00  7.50        1       1.5       1.5      1   0.083655   
2011-05-29 15:00:00  5.50        3       3.0       3.0      3   0.112001 

我以前通过保持每个窗口(在线)之间的差异来实现移动窗口统计,以便轻松计算排名变化,目前看来我必须完全重新排列每个窗口,这是不必要的。我看到之前有人问过类似的问题[Pandas performance on rolling stats][2]。

  1. 您知道 pandas 中是否有一种方法可以更有效地执行此计算?
  2. 是否有一种简单的方法可以在 pandas 的移动窗口上实现一个函数,我可以在其中找到为每个步骤添加和删除的元素并相应地返回一个值,从而可能维护我自己的运行排名计算?

谢谢

[1]: http://stackoverflow.com/questions/14440187/rank-data-over-a-rolling-window-in-pandas-dataframe
[2]: http://stackoverflow.com/questions/24613850/pandas-performance-on-multiple-rolling-statistics-on-different-time-intervals

【问题讨论】:

    标签: python performance pandas


    【解决方案1】:

    文档here 符合您所描述的我相信。

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000',
        periods=1000))
    plot1 = pd.rolling_max(ts, 240)
    plot2 = pd.rolling_min(ts, 240)
    plot3 = pd.rolling_mean(ts, 240)
    
    plt.plot(plot1.values.tolist())
    plt.plot(plot2.values.tolist())
    plt.plot(plot3.values.tolist())
    plt.show()
    

    这就是 Pandas 优化执行任务的方式。如果这还不够快,我不确定解决方法是否会比内置函数更快。如果这是多余的,请随意投反对票:)

    编辑: 这就是你在说的吗?

    ts = pd.Series(np.random.randn(1000000), index=pd.date_range('1/1/2000', periods=1000000))
    
    listofmax = []
    for number in range(0, len(ts), 240):
        listofmax.append(ts[number:number+240].max())
    

    根据 timeit,100 万行需要 0.4 秒。当然,这只是一个日期时间戳和一个值。您是否正在寻找比这更快的东西,我是否更好地理解您的尝试?

    【讨论】:

    • 嗨,谢谢,但我认为这并不能回答我的问题。这些方法不会在窗口上创建排名。我已经阅读了引导我到rolling_apply 的文档。然而,这似乎只是简单地将新函数应用到每个窗口,并且在一个大型数据集上可能需要很长时间才能迭代地应用该函数。使用 pandas roll 功能非常缓慢。 argsort 更快,更接近上面的瓶颈方法,但我仍然相信通过使用在线窗口或我缺少的方法来实现更有效的方法应该不难?
    • 再次感谢您的回复,但您的示例返回最大值。我想要滚动寡妇中项目的等级(如果可能),并使用平局的最小值。我已经更新了我的问题以创建一个可重现的示例。
    猜你喜欢
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多