熊猫每月滚动窗口

时间:2020-01-02 21:01:55

标签: python pandas group-by offset rolling-computation

我正在寻找按类别分组的每日数据的“每月”滚动窗口。下面的代码无法按原样工作,它导致以下错误:

ValueError: <DateOffset: months=1> is a non-fixed frequency

我知道我可以使用'30D'偏移量,但这会随着时间的推移而改变日期。

我正在寻找一个窗口的总和,该窗口的范围从一个月的第x天到第J个月的同一x天。例如。 J = 1:7月4日至8月4日,7月5日至8月5日,7月6日至8月6日等

我已经尝试了好几天了。任何建议或小费将非常。新年快乐。

MRE:

import pandas as pd
from io import StringIO

data = StringIO(
"""\
date          logret       category
2014-03-25    -0.01           A
2014-04-05    -0.02           A
2014-04-15    -0.03           A
2014-04-25    0.01            B
2014-05-05    0.03            B
2014-05-15    -0.01           A
2014-05-25    0.04            B
"""
)

df = pd.read_csv(data,sep="\s+",parse_dates=True,index_col="date")

J=1

df.groupby(['category'])['logret'].rolling(pd.DateOffset(months=J),min_periods=J*20).sum() 

2 个答案:

答案 0 :(得分:1)

def MonthRollAvg(df, offset, avgColumn):
    #must have DateTimeIndex
    df2 = df.copy()
    df2.index = df2.index + pd.DateOffset(days = -offset)
    return df2.groupby([df2.index.year, df2.index.month])[avgColumn].mean()

MonthRollAvg(df, 5, 'logret')

我想到的最简单的方法是使用pd.DateOffset移动日期,然后找到均值。因此,如果您希望从第6天到第6天使用它,则可以使用5的偏移量来使该月的第6天成为该月的第1天,然后求出每个月的均值。这将保持月份长度不变。您只需要跟踪平均的日期即可。

答案 1 :(得分:1)

在一个中间步骤中,将您的时间戳“标准化”,以使每个月有31天,然后进行汇总,最后从结果中删除“插入”行。

只要您的聚合中性元素是有效的。

  1. 使用所有时间戳记作为字符串从原始df创建索引
  2. 使用表示时间戳的字符串创建另一个索引,其中所有月份都为31天
  3. 合并,汇总等
  4. 通过从原始df导出的索引
  5. 从聚合中选择
  6. 将新列添加到原始df
import pandas as pd
from io import StringIO

data = StringIO(
"""\
date          logret       category
2014-03-25    -0.01           A
2014-04-05    -0.02           A
2014-04-15    -0.03           A
2014-04-25    0.01            B
2014-05-05    0.03            B
2014-05-15    -0.01           A
2014-05-25    0.04            B
"""
)

df = pd.read_csv(data,sep="\s+",parse_dates=True,index_col="date")
idx = df.index.strftime('%Y-%m-%d')

y0 = df.index[0].year
y1 = df.index[-1].year

padded = pd.DataFrame(index=[f'{y}-{m:02}-{d:02}' 
                             for y in range(y0,y1+1) 
                             for m in range(1, 13)
                             for d in range(1, 32)])[idx[0]:idx[-1]]

# Note that the rolling interval is exclusive at start
df.assign(rolling_aggregate=padded.join(df.set_index(idx)).fillna(0).rolling(31).agg(sum).loc[idx])

产量:

            logret category  rolling_aggregate
date                                          
2014-03-25   -0.01        A                NaN
2014-04-05   -0.02        A                NaN
2014-04-15   -0.03        A                NaN
2014-04-25    0.01        B              -0.04
2014-05-05    0.03        B               0.01
2014-05-15   -0.01        A               0.03
2014-05-25    0.04        B               0.06