Pandas 滚动总和,可变长度

Pandas rolling sum, variating length

我将尝试解释我目前遇到的关于 Python 中 DataFrames 的累积和的问题,希望你能理解它!

给定一个 pandas DataFrame df 和一个 returns 列:

              returns
Date                                                          
2014-12-10    0.0000
2014-12-11    0.0200
2014-12-12    0.0500
2014-12-15    -0.0200
2014-12-16    0.0000

在此 DataFrame 上应用累加和很容易,只需使用例如df.cumsum()。但是是否有可能每隔 X 天(或数据点)应用一个累积总和,只产生最后 Y 天(数据点)的累积总和。

澄清:给定上述每日数据,我如何获得最近 Y 天的累计总和,每 X 天重新评估(从零开始)?

希望它够清楚,

谢谢, N

我不确定是否有内置方法,但编写一个似乎并不难。 例如,这是 pandas 系列的一个。

def cum(df, interval):
    all = []
    quotient = len(df)//interval
    intervals = range(quotient)
    for i in intervals:
        all.append(df[0:(i+1)*interval].sum())
    return pd.Series(all)
>>>s1 = pd.Series(range(20))
>>>print(cum(s1, 4))
0     6
1    28
2    66
3   120
4   190
dtype: int64

我的方法是使用辅助列。有点笨拙,但应该可以用:

numgroups = int(len(df)/(x-1))
df['groupby'] = sorted(list(range(numgroups))*x)[:len(df)]
df['mask'] = (([0]*(x-y)+[1]*(y))*numgroups)[:len(df)]
df['masked'] = df.returns*df['mask']
df.groupby('groupby').masked.cumsum()

"Every X days"和"every X data points"是非常不同的;以下假设您真正指的是第一个,因为您提到它的频率更高。

如果索引是DatetimeIndex,你可以resample to a daily frequency, take a rolling_sum,然后select只有原始日期:

>>> pd.rolling_sum(df.resample("1d"), 2, min_periods=1).loc[df.index]
            returns
Date               
2014-12-10     0.00
2014-12-11     0.02
2014-12-12     0.07
2014-12-15    -0.02
2014-12-16    -0.02

或者,一步一步:

>>> df.resample("1d")
            returns
Date               
2014-12-10     0.00
2014-12-11     0.02
2014-12-12     0.05
2014-12-13      NaN
2014-12-14      NaN
2014-12-15    -0.02
2014-12-16     0.00
>>> pd.rolling_sum(df.resample("1d"), 2, min_periods=1)
            returns
Date               
2014-12-10     0.00
2014-12-11     0.02
2014-12-12     0.07
2014-12-13     0.05
2014-12-14      NaN
2014-12-15    -0.02
2014-12-16    -0.02

感谢@DSM,我设法想出了他的解决方案的一个变体,实际上它几乎可以满足我的需求:

import numpy as np
import pandas as pd

df.resample("1w"), how={'A': np.sum})

为下面的示例生成我想要的结果:

rng = range(1,29)
dates = pd.date_range('1/1/2000', periods=len(rng))
r = pd.DataFrame(rng, index=dates, columns=['A'])
r2 = r.resample("1w", how={'A': np.sum})

输出:

>> print r
             A
2000-01-01   1
2000-01-02   2
2000-01-03   3
2000-01-04   4
2000-01-05   5
2000-01-06   6
2000-01-07   7
2000-01-08   8
2000-01-09   9
2000-01-10  10
2000-01-11  11
...
2000-01-25  25
2000-01-26  26
2000-01-27  27
2000-01-28  28

>> print r2
              A
2000-01-02    3
2000-01-09   42
2000-01-16   91
2000-01-23  140
2000-01-30  130

即使在这种情况下它没有开始 "one week in"(在第一种情况下总和为 3),它总是会得到正确的滚动总和,从前一个日期开始并具有初始值为零。