1年滚动平均值 pandas 列日期

14

我希望计算这个数据框 test中每一行的1年滚动平均值:

index   id      date        variation
2313    7034    2018-03-14  4.139148e-06
2314    7034    2018-03-13  4.953194e-07
2315    7034    2018-03-12  2.854749e-06
2316    7034    2018-03-09  3.907458e-06
2317    7034    2018-03-08  1.662412e-06
2318    7034    2018-03-07  1.346433e-06
2319    7034    2018-03-06  8.731700e-06
2320    7034    2018-03-05  7.145597e-06
2321    7034    2018-03-02  4.893283e-06
...
例如,我需要计算:
  • 2018年03月14日至2017年08月14日之间id为7034的变化平均值
  • 2018年03月13日至2017年08月13日之间id为7034的变化平均值
  • 等等
  • 我尝试过:

    test.groupby(['id','date'])['variation'].rolling(window=1,freq='Y',on='date').mean()
    

    但我收到了错误信息:

    ValueError: invalid on specified as date, must be a column (if DataFrame) or None
    

    在这种情况下,我该如何使用 pandas 的 rolling() 函数?


    [编辑 1] [感谢 Sacul]

    我已经进行了测试:

    df['date'] = pd.to_datetime(df['date'])
    
    df.set_index('date').groupby('id').rolling(window=1, freq='Y').mean()['variation']
    

    但是freq='Y'无法正常工作(我得到了:ValueError:Invalid frequency: Y)。然后我使用了window = 365,freq ='D'

    但是还有一个问题:因为每个组合的id-date从未连续出现365个日期,所以结果总是为空。即使存在缺失的日期,我也希望忽略它们并考虑当前日期和(当前日期-365)之间的所有日期来计算滚动均值。例如,假设我有:

    index   id      date        variation
    2313    7034    2018-03-14  4.139148e-06
    2314    7034    2018-03-13  4.953194e-07
    2315    7034    2017-03-13  2.854749e-06
    

    那么,

    • 对于7034 2018-03-14:我想计算MEAN(4.139148e-06,4.953194e-07, 2.854749e-06)
    • 对于7034 2018-03-13:我也想计算MEAN(4.139148e-06,4.953194e-07, 2.854749e-06)

    我该怎么做?


    [EDIT 2]

    最后,我使用以下公式来计算1年内的滚动中位数、平均值和标准差,并忽略缺失值:

    pd.rolling_median(df.set_index('date').groupby('id')['variation'],window=365, freq='D',min_periods=1)
    
    pd.rolling_mean(df.set_index('date').groupby('id')['variation'],window=365, freq='D',min_periods=1)
    
    pd.rolling_std(df.set_index('date').groupby('id')['variation'],window=365, freq='D',min_periods=1)
    

    7
    格式良好,表现出一定的尝试,并明确给出了错误。欢迎来到stackoverflow! - Drise
    2个回答

    4

    我相信这个对你有用:

    # First make sure that `date` is a datetime object:
    
    df['date'] = pd.to_datetime(df['date'])
    
    df.set_index('date').groupby('id').rolling(window=1, freq='A').mean()['variation']
    

    当日期作为索引时,使用pd.DataFrame.rolling和日期时间一起使用效果很好,这就是我使用df.set_index('date')的原因(如文档示例所示)。

    在您的示例数据帧上,我无法真正测试它是否适用于年平均值,因为只有一年和一个ID,但它应该可以工作。

    更好的解决方案:

    [编辑]正如Mihai-Andrei Dinculescu所指出的,freq现在是一个已弃用的参数。以下是一个替代方案(可能更具未来性),可以实现您想要的功能:

    df.set_index('date').groupby('id')['variation'].resample('A').mean()
    

    您可以查看resample文档以获取更多详细信息,以及有关频率参数的此链接


    1
    ValueError: Invalid frequency: Y - Mihai Dinculescu
    1
    可能与 freq 被弃用有关。https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rolling.html - Mihai Dinculescu
    很奇怪,这对我有效。根据此链接,当您尝试使用频率“'A'”时,它是否有效?应该做同样的事情。 - sacuL
    A运行正常。你使用的pandas版本是什么? - Mihai Dinculescu
    那我就不知道了 :\ - sacuL
    显示剩余2条评论

    0
    首先,您需要将日期设置为索引。
    df['date'] = pd.to_datetime(df['date'])
    df.index = df['date']
    

    然后,定义窗口最简单的方法是使用一个字符串,其中包含偏移别名之一。
    df.groupby('id').rolling('365D')['variation'].mean()
    

    或者,为了更灵活,您也可以使用timedelta:
    from datetime import timedelta
    one_year = timedelta(days=365)
    df.groupby('id').rolling(one_year)['variation'].mean()
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接