GroupBy 对象的 Python 滚动函数

我有一个类型为 <pandas.core.groupby.SeriesGroupBy object at 0x03F1A9F0>的时间序列物体 groupedgrouped.sum()给出了所需的结果,但是我无法使 roll _ sum 与 groupby对象一起工作。有什么方法可以将滚动函数应用到 groupby对象上吗?例如:

x = range(0, 6)
id = ['a', 'a', 'a', 'b', 'b', 'b']
df = DataFrame(zip(id, x), columns = ['id', 'x'])
df.groupby('id').sum()
id    x
a    3
b   12

不过,我希望有这样的东西:

  id  x
0  a  0
1  a  1
2  a  3
3  b  3
4  b  7
5  b  12
127759 次浏览

我不知道机械原理,但这个可以用。注意,返回的值只是一个 ndarray。我认为你可以用这种方式应用任何累积或“滚动”函数,它应该有相同的结果。

我已经测试了它与 cumprodcummaxcummin,他们都返回一个 ndarray。我认为熊猫很聪明,知道这些函数返回一个序列,所以这个函数是作为一个转换而不是聚合来应用的。

In [35]: df.groupby('id')['x'].cumsum()
Out[35]:
0     0
1     1
2     3
3     3
4     7
5    12

编辑: 我觉得奇怪的是,这个语法确实返回了一个 Series:

In [54]: df.groupby('id')['x'].transform('cumsum')
Out[54]:
0     0
1     1
2     3
3     3
4     7
5    12
Name: x

累计金额

为了直接回答这个问题,累积法将产生所期望的数列:

In [17]: df
Out[17]:
id  x
0  a  0
1  a  1
2  a  2
3  b  3
4  b  4
5  b  5


In [18]: df.groupby('id').x.cumsum()
Out[18]:
0     0
1     1
2     3
3     3
4     7
5    12
Name: x, dtype: int64

每组大熊猫滚动函数

更一般地说,任何滚动函数都可以应用于每个组,如下所示(使用新的。如@kekert 所注释的滚动方法)。注意,返回类型是一个多索引系列,它不同于以前(不推荐的) pd.rolling _ * 方法。

In [10]: df.groupby('id')['x'].rolling(2, min_periods=1).sum()
Out[10]:
id
a   0   0.00
1   1.00
2   3.00
b   3   3.00
4   7.00
5   9.00
Name: x, dtype: float64

为了应用每组滚动函数并接收原始数据帧顺序的结果,应改用转换:

In [16]: df.groupby('id')['x'].transform(lambda s: s.rolling(2, min_periods=1).sum())
Out[16]:
0    0
1    1
2    3
3    3
4    7
5    9
Name: x, dtype: int64

不赞成的做法

作为参考,以下是现在已经被废弃的 Pandas.roll _ mean 的表现:

In [16]: df.groupby('id')['x'].apply(pd.rolling_mean, 2, min_periods=1)
Out[16]:
0    0.0
1    0.5
2    1.5
3    3.0
4    3.5
5    4.5

对于遇到这个老问题的谷歌人来说:

关于@kekert 对@Garrett 使用新

df.groupby('id')['x'].rolling(2).mean()

而不是现在被贬低的

df.groupby('id')['x'].apply(pd.rolling_mean, 2, min_periods=1)

奇怪的是,似乎新的。滚动()。Mean ()方法返回一个多索引序列,首先由 group _ by 列索引,然后是索引。然而,旧的方法只是返回一个由原始 df 索引单一索引的序列,这可能没什么意义,但是它使得将该序列作为新列添加到原始数据框架中变得非常方便。

因此,我想我已经找到了一个解决方案,它使用了新的 roll ()方法,并且工作原理仍然相同:

df.groupby('id')['x'].rolling(2).mean().reset_index(0,drop=True)

这样你就能看到这个系列了

0    0.0
1    0.5
2    1.5
3    3.0
4    3.5
5    4.5

您可以将其添加为一列:

df['x'] = df.groupby('id')['x'].rolling(2).mean().reset_index(0,drop=True)

这里有另一种方法,可以很好地推广和使用熊猫的 扩张方法。

这是非常有效的,也完美地为 滚动窗口计算滚动窗口计算与固定的窗口,如时间序列。

# Import pandas library
import pandas as pd


# Prepare columns
x = range(0, 6)
id = ['a', 'a', 'a', 'b', 'b', 'b']


# Create dataframe from columns above
df = pd.DataFrame({'id':id, 'x':x})


# Calculate rolling sum with infinite window size (i.e. all rows in group) using "expanding"
df['rolling_sum'] = df.groupby('id')['x'].transform(lambda x: x.expanding().sum())


# Output as desired by original poster
print(df)
id  x  rolling_sum
0  a  0            0
1  a  1            1
2  a  2            3
3  b  3            3
4  b  4            7
5  b  5           12

如果需要将分组滚动函数重新分配回原始的 Dataframe,同时保持顺序和分组,则可以使用 transform函数。

df.sort_values(by='date', inplace=True)
grpd = df.groupby('group_key')
#using center=false to assign values on window's last row
df['val_rolling_7_mean'] = grpd['val'].transform(lambda x: x.rolling(7, center=False).mean())