【问题标题】:Pandas - moving average for date with many measurements per datePandas - 日期的移动平均值,每个日期有许多测量值
【发布时间】:2021-08-12 06:03:47
【问题描述】:

我有一个包含日期和销售额的 DataFrame。我想计算过去 5 天的移动平均值并将其分配给每一天。问题是我每天都要进行多次测量(准确地说是 1115 - 对于单次测量,我知道该怎么做)。

我的数据如下所示:

    Date        Sales
0   2013-01-01  0
1   2013-01-01  0
2   2013-01-01  0
3   2013-01-01  0
4   2013-01-01  0
... ... ...
1017204 2015-07-31  9082
1017205 2015-07-31  10708
1017206 2015-07-31  7481
1017207 2015-07-31  10460
1017208 2015-07-31  5263

我想先计算过去 5 天的移动平均值(取过去 5 天所有 1115 * 5 = 5575 次测量的平均值),然后将其分配回每个单独的测量(每个测量都应分配此平均值)。我的数据将如下所示:

    Date        Sales       Last5DaysAvg
0   2013-01-01  0   NaN
1   2013-01-01  0   NaN
2   2013-01-01  0   NaN
3   2013-01-01  0   NaN
4   2013-01-01  0   NaN
... ... ...
5576    2013-01-06  (average from 2013-01-01 to 2013-01-06)
5577    2013-01-06  (average from 2013-01-01 to 2013-01-06)
5578    2013-01-06  (average from 2013-01-01 to 2013-01-06)
...
1017204 2015-07-31  9082    (average from 2015-07-26 to 2015-07-31)
1017205 2015-07-31  10708   (average from 2015-07-26 to 2015-07-31)
1017206 2015-07-31  7481    (average from 2015-07-26 to 2015-07-31)
1017207 2015-07-31  10460   (average from 2015-07-26 to 2015-07-31)
1017208 2015-07-31  5263    (average from 2015-07-26 to 2015-07-31)

我尝试使用 .count() 聚合作为初学者,因为它很容易验证 - 它应该在每行中返回 5575(除了前 5575 行,我当然会有 NaN):

df = df.rolling("5D", on="Date").count()

但我明白了:

    Date        Sales
0   2013-01-01  1.0
1   2013-01-01  2.0
2   2013-01-01  3.0
3   2013-01-01  4.0
4   2013-01-01  5.0
... ... ...
1017204 2015-07-31  5571.0
1017205 2015-07-31  5572.0
1017206 2015-07-31  5573.0

所以看起来每天都是分开计算的,根本没有计算移动窗口。

问题:我怎样才能达到上述结果?

数据:(前 30000 行)https://pastebin.com/5bQ4Zt3f

编辑:我设法让这个工作,但以相当丑陋的方式,我认为有更漂亮和更有效的方式。此外,下面的代码还硬编码了每天的测量次数,这不能总是得到保证。

df = df.groupby([pd.Grouper(key="Date", freq="D")]) \
             .sum() \
             .reset_index() \
             .sort_values("Date")
df = df.rolling(5, on="Date").sum()
df["Sales"] = df["Sales"] / (1115 * 5)
Date    Sales
0   2013-01-01  NaN
1   2013-01-02  NaN
2   2013-01-03  NaN
3   2013-01-04  NaN
4   2013-01-05  4661.063857
... ... ...
937 2015-07-27  5435.554439
938 2015-07-28  5871.071031
939 2015-07-29  6211.633722
940 2015-07-30  6709.784036
941 2015-07-31  8471.914439

【问题讨论】:

    标签: python pandas dataframe date rolling-computation


    【解决方案1】:

    不清楚为什么每个日期都有多行。我看到了两种可能的解释:

    • 您必须在星号处汇总这些值,然后生成单个滚动平均值:
    df.groupBy('Date').sum().rolling(5).mean().reset_index()
    
    • 或者这些是不同的产品 - 那么您仍然需要分组,但您可以计算每个产品的滚动平均值,而不是汇总:
    df.groupby('Product')['Date'].rolling(5).mean().reset_index()
    

    【讨论】:

    • 很抱歉,我不太了解“产品”列 - 我没有它(只有索引、日期和销售),我该怎么办?索引已经是默认索引,所以 reset_index() 并没有真正做任何事情。
    • 已编辑,如果需要进一步澄清,请告诉我
    • 我的澄清 - 我有 1115 家商店,所以每天有 1115 个销售价值,所以我只需要 1 个滚动平均值(它代表数据中的趋势)。出于这个原因,我想避免使用 groupby() 计算每天的总和/平均值。相反,我认为只取最近 5 天的值(来自所有商店,所以 1115 * 5 个值)并直接从中计算平均值会更合适。
    • 我不确定您是否会通过避免初始聚合来获得任何收益 - 这会降低您所有后续操作的复杂性。但是您可以简单地滚动1115*5 行,然后为每个日期选择第一个值,即df.rolling(1115*5).mean().groupby('Date').first().reset_index()
    • 你可能是对的,我可能想多了。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-11
    相关资源
    最近更新 更多