【问题标题】:Pandas - Rolling slope calculationPandas - 滚动坡度计算
【发布时间】:2017-06-27 13:27:09
【问题描述】:

如何计算每列的rolling(window=60)值的斜率,以5为单位?

我想计算每 5 分钟的值,我不需要每条记录的结果。

这是示例数据框和结果:

df
Time                A    ...      N
2016-01-01 00:00  1.2    ...    4.2
2016-01-01 00:01  1.2    ...    4.0
2016-01-01 00:02  1.2    ...    4.5
2016-01-01 00:03  1.5    ...    4.2
2016-01-01 00:04  1.1    ...    4.6
2016-01-01 00:05  1.6    ...    4.1
2016-01-01 00:06  1.7    ...    4.3
2016-01-01 00:07  1.8    ...    4.5
2016-01-01 00:08  1.1    ...    4.1
2016-01-01 00:09  1.5    ...    4.1
2016-01-01 00:10  1.6    ...    4.1
....

result
Time                A    ...      N
2016-01-01 00:04  xxx    ...    xxx
2016-01-01 00:09  xxx    ...    xxx
2016-01-01 00:14  xxx    ...    xxx
...

df.rolling 函数可以应用于这个问题吗?

如果 NaN 在窗口中就可以了,这意味着子集可以小于 60。

【问题讨论】:

    标签: python pandas regression


    【解决方案1】:

    您想要的似乎是以特定的步长滚动。 但是,根据documentation of pandasrolling 目前不支持步长。

    如果数据量不是太大,只需对所有数据进行滚动,并使用索引选择结果即可。

    这是一个示例数据集。为简单起见,时间列使用整数表示。

    data = pd.DataFrame(np.random.rand(500, 1) * 10, columns=['a'])
    
                a
    0    8.714074
    1    0.985467
    2    9.101299
    3    4.598044
    4    4.193559
    ..        ...
    495  9.736984
    496  2.447377
    497  5.209420
    498  2.698441
    499  3.438271
    

    然后,滚动并计算斜率,

    def calc_slope(x):
        slope = np.polyfit(range(len(x)), x, 1)[0]
        return slope
    
    # set min_periods=2 to allow subsets less than 60.
    # use [4::5] to select the results you need.
    result = data.rolling(60, min_periods=2).apply(calc_slope)[4::5]
    

    结果是,

                a
    4   -0.542845
    9    0.084953
    14   0.155297
    19  -0.048813
    24  -0.011947
    ..        ...
    479 -0.004792
    484 -0.003714
    489  0.022448
    494  0.037301
    499  0.027189
    

    或者,你可以参考这篇文章。第一个答案提供了一种实现此目的的 numpy 方法: step size in pandas.DataFrame.rolling

    【讨论】:

      【解决方案2】:

      试试这个

      windows = df.groupby("Time")["A"].rolling(60)
      df[out] = windows.apply(lambda x: np.polyfit(range(60), x, 1)[0], raw=True).values
      

      【讨论】:

        【解决方案3】:

        您可以使用pandas Resample。请注意,要使用它,您需要一个带有时间值的索引

        df.index = pd.to_datetime(df.Time)
        print df
        result = df.resample('5Min').bfill()
        print result
                                         Time    A    N
        Time                                           
        2016-01-01 00:00:00  2016-01-01 00:00  1.2  4.2
        2016-01-01 00:01:00  2016-01-01 00:01  1.2  4.0
        2016-01-01 00:02:00  2016-01-01 00:02  1.2  4.5
        2016-01-01 00:03:00  2016-01-01 00:03  1.5  4.2
        2016-01-01 00:04:00  2016-01-01 00:04  1.1  4.6
        2016-01-01 00:05:00  2016-01-01 00:05  1.6  4.1
        2016-01-01 00:06:00  2016-01-01 00:06  1.7  4.3
        2016-01-01 00:07:00  2016-01-01 00:07  1.8  4.5
        2016-01-01 00:08:00  2016-01-01 00:08  1.1  4.1
        2016-01-01 00:09:00  2016-01-01 00:09  1.5  4.1
        2016-01-01 00:10:00  2016-01-01 00:10  1.6  4.1
        2016-01-01 00:15:00  2016-01-01 00:15  1.6  4.1
                                         Time    A    N
        

        输出

        Time                                           
        2016-01-01 00:00:00  2016-01-01 00:00  1.2  4.2
        2016-01-01 00:05:00  2016-01-01 00:05  1.6  4.1
        2016-01-01 00:10:00  2016-01-01 00:10  1.6  4.1
        2016-01-01 00:15:00  2016-01-01 00:15  1.6  4.1
        

        【讨论】:

        • 谢谢,但我想要输出的是最后五条记录的斜率值。时间戳从 00:00 开始,因此 00:04 是输出的第一行。 (1-> 00:00, 2-> 00:01, 3-> 00:02, 4-> 00:03, 5-> 00:04)
        【解决方案4】:

        我用:

            df['slope_I'] = df['I'].rolling('600s').apply(lambda x: (x[-1]-x[0])/600) 
        

        其中斜率为 1/秒单位。

        结果的前 600 个可能是空的,您应该用零或平均值填充它。 斜率列中的第一个数字将是从窗口内第一行到最后一行的直线的斜率,以此类推。

        最好的问候。

        【讨论】:

          【解决方案5】:

          对于其他寻求答案的人,这里我得到了另一个解决方案,其中时间间隔不需要相同的长度。

          df.A.diff(60)/df.Time.diff(60).dt.total_seconds()
          

          这行代码将当前行与六十行的差值除以相同行的时间差。 如果您只想要每第五条记录,那么下一行应该可以工作。

          df.A.diff(60)/df.Time.diff(60).dt.total_seconds()[4::5]
          

          注意:计算每一行,只返回 5 step serie

          doc pandas diff:https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.diff.html

          【讨论】: