如何在pandas中进行滚动求和?

17

我有这个数据帧:

dates = pd.date_range(start='2016-01-01', periods=20, freq='d')
df = pd.DataFrame({'A': [1] * 20 + [2] * 12 + [3] * 8,
                   'B': np.concatenate((dates, dates)),
                   'C': np.arange(40)})

我按日期对数据框进行了排序:

df.sort_values('B',inplace=True)

我希望对日期进行前向滚动求和。然而,我只能使用向后滚动求和:

df.groupby('A').rolling(7, on='B',min_periods=0).C.sum()

A  B         
1  2016-01-01      0.0
   2016-01-02      1.0
   2016-01-03      3.0
   2016-01-04      6.0
   2016-01-05     10.0
   2016-01-06     15.0

我想要进行向前滚动求和。


1
请提供预期输出。 - galmeriol
6个回答

22

我认为需要通过 iloc[::-1] 进行排序更改:

df1 = (df.iloc[::-1]
        .groupby('A', sort=False)
        .rolling(7, on='B',min_periods=0).C
        .sum()
        .iloc[::-1])

嗨,Jez 我检查了你的解决方案 它完美地运行了 谢谢你,伙计 - Ahamed Moosa
@AhamedMoosa,如果你发现任何有用的答案,包括你刚才接受的答案,请随意点赞。 - piRSquared
@jezrael 恭敬不如从命 :) - Ahamed Moosa
1
使用df[::-1]代替df.iloc[::-1]更简单、更快。 - Attila the Fun

10

简单如:

df['B'] = df['A'].rolling(3).sum().shift(-3)

2
这将返回3个空行。 - Muhammad Usman
1
哇!我认为这是一个非常简单而优雅的解决方案,可以实现前向滚动操作,谢谢!对于那些希望使用这种方法的人,我想指出,如果滚动函数不包括该行的数据,则可能需要将移位值增加一(绝对值),例如,如果您在“.rolling()”中使用“left”或“neither”的“closed”参数,则同一行的数据不包括在滚动函数中;在这种情况下,您需要使用“.shift(-4)”将数据向上移动一行,以排除原始行。 - hekimgil

7

安装设置

dates = pd.date_range(start='2016-01-01', periods=20, freq='d')
df = pd.DataFrame({'A': [1] * 20 + [2] * 12 + [3] * 8,
                   'B': np.concatenate((dates, dates)),
                   'C': np.arange(40)})

'B'排序,然后当我们滚动时,使用iloc[::-1]进行反向滚动。
def rev_roll(x):
    return x.iloc[::-1].rolling(7, min_periods=0).sum().iloc[::-1]

df.assign(Roll=df.sort_values('B').groupby('A').C.transform(rev_roll))

输出


    A          B   C  Roll
0   1 2016-01-01   0    21
1   1 2016-01-02   1    28
2   1 2016-01-03   2    35
3   1 2016-01-04   3    42
4   1 2016-01-05   4    49
5   1 2016-01-06   5    56
6   1 2016-01-07   6    63
7   1 2016-01-08   7    70
8   1 2016-01-09   8    77
9   1 2016-01-10   9    84
10  1 2016-01-11  10    91
11  1 2016-01-12  11    98
12  1 2016-01-13  12   105
13  1 2016-01-14  13   112
14  1 2016-01-15  14    99
15  1 2016-01-16  15    85
16  1 2016-01-17  16    70
17  1 2016-01-18  17    54
18  1 2016-01-19  18    37
19  1 2016-01-20  19    19
20  2 2016-01-01  20   161
21  2 2016-01-02  21   168
22  2 2016-01-03  22   175
23  2 2016-01-04  23   182
24  2 2016-01-05  24   189
25  2 2016-01-06  25   196
26  2 2016-01-07  26   171
27  2 2016-01-08  27   145
28  2 2016-01-09  28   118
29  2 2016-01-10  29    90
30  2 2016-01-11  30    61
31  2 2016-01-12  31    31
32  3 2016-01-13  32   245
33  3 2016-01-14  33   252
34  3 2016-01-15  34   219
35  3 2016-01-16  35   185
36  3 2016-01-17  36   150
37  3 2016-01-18  37   114
38  3 2016-01-19  38    77
39  3 2016-01-20  39    39

如果您想将新列添加到原始数据框中,则使用transform是一个不错的选择。 - Jason Goal

3

我想你希望

df["C"] = df["A"].cumsum()

请参阅此处的文档。

2
indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=7)
df.groupby('A').rolling(window=indexer, on='B',min_periods=0).C.sum()

pandas文档


最佳答案! - undefined

1

如果您的日期不是完全连续的(比如有一两天缺失),并且您想要一个固定的N天窗口(而不是N个记录的窗口),则可以使用以下方法:

def forward_rolling_mean(sub_df, col='units', days_ahead=7):
    rolling_data = [sub_df[sub_df['date'].between(date+pd.Timedelta(days=1), date+pd.Timedelta(days=1+days_ahead-1))][col].mean() for date in sub_df['date']]
    return pd.DataFrame({'%s_next%idays_mean' % (col, days_ahead): rolling_data}, index=sub_df['date'])

你也可以将其更改为返回系列而不是数据帧。稍后,您可以将其与原始数据连接。


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