Pandas 滚动时间 window 按天而不是单独的行

Pandas rolling time window by days instead of individual rows

我有一个大型数据集,我需要计算 N 天滚动时间 window 的一些统计数据。每天有多个条目。我需要计算 N 天时间范围内所有行的统计数据,即两端每天计算。

带时间偏移的pandas.DataFrame.rolling()方法差不多可以用了。此方法的时间偏移向后看以包括 N 天时间范围内的所有天,但向前看,window 按行滚动,即直到一天结束。

我已经编写了一个循环来执行此操作,但它在我的大型数据集上运行得非常慢。有没有一种有效的方法可以使用 rolling()、使用某种索引器或其他方式来做到这一点?

我需要计算的测试统计量是计数、均值和标准差。我修改后的例子:

#Create test dataframe:
import pandas as pd
l1=[1,2,3,4,5,6,7,8,9,10,11,12]
                                                            
ts=[pd.Timestamp('2017-01-01'),
    pd.Timestamp('2017-01-02'),
    pd.Timestamp('2017-01-03'),
    pd.Timestamp('2017-01-04'),
    pd.Timestamp('2017-01-05'),
    pd.Timestamp('2017-01-05'),
    pd.Timestamp('2017-01-05'),
    pd.Timestamp('2017-01-06'),
    pd.Timestamp('2017-01-06'),
    pd.Timestamp('2017-01-07'),
    pd.Timestamp('2017-01-07'),
    pd.Timestamp('2017-01-08')]

In [58]: df=pd.DataFrame({'t':ts, 'c':l1, 'm':l1, 's':l1}).set_index('t')
In [59]: df
Out[59]:
             c   m   s
t                    
2017-01-01   1   1   1
2017-01-02   2   2   2
2017-01-03   3   3   3
2017-01-04   4   4   4
2017-01-05   5   5   5
2017-01-05   6   6   6
2017-01-05   7   7   7
2017-01-06   8   8   8
2017-01-06   9   9   9
2017-01-07  10  10  10
2017-01-07  11  11  11
2017-01-08  12  12  12
 
In [60]: df.rolling('3D').agg({'c':'count', 'm':'mean', 's':'std'})
Out[60]:
              c     m         s
t                             
2017-01-01  1.0   1.0       NaN
2017-01-02  2.0   1.5  0.707107
2017-01-03  3.0   2.0  1.000000
2017-01-04  3.0   3.0  1.000000
2017-01-05  3.0   4.0  1.000000  #incorrect for day-end window boundary
2017-01-05  4.0   4.5  1.290994  #incorrect for day-end window boundary
2017-01-05  5.0   5.0  1.581139
2017-01-06  5.0   6.0  1.581139  #incorrect for day-end window boundary
2017-01-06  6.0   6.5  1.870829
2017-01-07  6.0   7.5  1.870829  #incorrect for day-end window boundary
2017-01-07  7.0   8.0  2.160247
2017-01-08  5.0  10.0  1.581139

但是根据以同一天的所有行结尾的 window 计算,结果将是:

              c     m         s
t                             
2017-01-01  1.0   1.0       NaN
2017-01-02  2.0   1.5  0.707107
2017-01-03  3.0   2.0  1.000000
2017-01-04  3.0   3.0  1.000000
2017-01-05  5.0   5.0  1.581139  #This is what it should be
2017-01-05  5.0   5.0  1.581139  #This is what it should be
2017-01-05  5.0   5.0  1.581139
2017-01-06  6.0   6.5  1.870829  #This is what it should be
2017-01-06  6.0   6.5  1.870829
2017-01-07  7.0   8.0  2.160247  #This is what it should be
2017-01-07  7.0   8.0  2.160247
2017-01-08  5.0  10.0  1.581139

请注意,每一天的最后一行都是正确的,同一天所有其他行的答案都是正确的。

如果你的数据一直是正数,你可以滚动后变换:

# if your index is not always on the day, e.g. 2017-01-01 01:00:00
# use `pd.Grouper(freq='D')` instead of `level` 
df.rolling('3D').sum().groupby(level='t').transform('max')

输出:

              a
t              
2017-01-01  1.0
2017-01-02  2.0
2017-01-03  3.0
2017-01-04  3.0
2017-01-05  5.0
2017-01-05  5.0
2017-01-05  5.0
2017-01-06  6.0
2017-01-06  6.0
2017-01-07  7.0
2017-01-07  7.0
2017-01-08  5.0

编辑:一般情况下,按天汇总并映射回来:

s = df.groupby(pd.Grouper(freq='D')).sum().rolling('3D').sum()
df.index.floor('D').to_series().map(s['a'])

输出:

t
2017-01-01    1.0
2017-01-02    2.0
2017-01-03    3.0
2017-01-04    3.0
2017-01-05    5.0
2017-01-05    5.0
2017-01-05    5.0
2017-01-06    6.0
2017-01-06    6.0
2017-01-07    7.0
2017-01-07    7.0
2017-01-08    5.0
Name: t, dtype: float64