Python-GroupBy对象的滚动函数
我有一个时间序列对象Python-GroupBy对象的滚动函数,python,pandas,pandas-groupby,rolling-computation,rolling-sum,Python,Pandas,Pandas Groupby,Rolling Computation,Rolling Sum,我有一个时间序列对象分组,类型为grouped.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
分组,类型为
grouped.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
我不确定机械原理,但这是可行的。注意,返回的值只是一个ndarray。我认为你可以用这种方式应用任何累积或“滚动”函数,它应该有相同的结果
我用cumprod
、cummax
和cummin
对它进行了测试,它们都返回了一个数据数组。我认为pandas足够聪明,知道这些函数返回一个序列,因此该函数被用作转换而不是聚合
In [35]: df.groupby('id')['x'].cumsum()
Out[35]:
0 0
1 1
2 3
3 3
4 7
5 12
编辑:我觉得奇怪的是,这种语法确实返回了一个系列:
In [54]: df.groupby('id')['x'].transform('cumsum')
Out[54]:
0 0
1 1
2 3
3 3
4 7
5 12
Name: x
累计金额
为了直接回答这个问题,cumsum方法将生成所需的序列:
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注释的新的.rolling方法)。请注意,返回类型是一个多索引系列,它不同于以前的(不推荐的)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.rolling_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)
奇怪的是,新的.rolling().mean()方法似乎返回一个多索引序列,首先由组按列索引,然后由索引索引。然而,旧的方法只是返回一个由原始df索引单独索引的序列,这可能没有什么意义,但它非常方便地将该序列作为新列添加到原始数据帧中
因此,我想我已经找到了一个使用新rolling()方法的解决方案,并且仍然可以使用相同的方法:
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)
这是另一种很好地概括并使用pandas方法的方法
它非常有效,而且对于固定窗口(如时间序列)也非常有效
# 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
如果需要将分组滚动函数重新分配回原始数据帧,同时保持顺序和分组,则可以使用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())
你到底希望滚动函数在分组对象上如何工作(我的意思是用符号写出你想做的数学)?对不起,我应该说得更清楚。所以你想在每个分组上做一个cumsum
,然后将整件事缝合回一个数据帧中?是的,理想情况下是cumsum和任何滚动函数(mean,sum,std).pd.rolling\u-mean现在不推荐用于Series,将被删除,请使用df.groupby('id')['x'].rolling(2).mean()
instead我认为您可以使用.transform
而不是重置\u-index?如果您按多个列进行分组,这实际上会失败。删除第一个参数(levels)可以解决这个问题,因为默认情况下它会删除所有级别。因此,该行变为df['x']=df.groupby('id')['x']].rolling(2).mean().reset_index(drop=True)
如果您的组变量尚未排序,则使用groupby(…,sort=False)
。当我将这个滚动平均值作为一个新列添加时,我得到了非常奇怪的结果,因为顺序与原始df不匹配。非常有用的信息。a) 他们应该将此添加到他们的b)你能提出一些关于功能更改的错误吗?在他们提出异议之前,他们应该更好地考虑后果。你能详细说明为什么我们应该把<代码>滚动(2)< /代码>,即为什么代码>窗口=2 < /代码>?是否因为有两组“a”和“b”?您是否有任何证据证明这是“非常有效的”?一般来说,与向量运算(内置的“.sum”、“.rolling”等)相比,使用pandas进行任何类型的迭代(例如“transform”或“apply”)都会对性能造成重大影响。我知道Pandas确实会对迭代循环进行一些预检查,看看它是否可以为您优化它,但一般来说,如果性能是一个问题,则应该避免迭代。很抱歉,我只能给您一票赞成票,我正在考虑创建新帐户,以便为这个答案提供更多的信任。这是唯一一个对我有效的多栏分组,谢谢!酷。这可以应用指数移动平均q['exponential_ave']=q.groupby('id')['x'].transform(lambda x:x.ewm(com=0.2).mean())