有没有办法对分组进行加权滚动求和?
我想对一个数据表(DataFrame)应用加权求和。在过去,我使用过
for sec_id, sec_df_unidx in grouped:
if sec_df_unidx.shape[0] > 3:
pd.rolling_sum(sec_df[added_cols], 4)
我想对求和应用加权平均,其中最新的值乘以0.6,第二个值乘以0.2,第三个和第四个值各乘以0.1。
数据表(DF):
DATE ID VALUE
2012-12-31 A 100
2013-03-31 A 120
2013-06-30 A 140
2013-09-30 A 160
2013-12-31 A 180
2013-03-31 B 0
2013-06-30 B 5
2013-09-30 B 1
2013-12-31 B 3
2012-12-31 C 45
2013-03-31 C 46
2013-06-30 C 42
2013-09-30 C 30
2013-12-31 C 11
2012-12-31 D 18
2013-03-31 D 9
2013-06-30 D 13
2013-09-30 D 5
2013-12-31 D 11
2012-12-31 E 0
添加新列后的数据表(DF):
DATE ID VALUE Weight_Sum
2012-12-31 A 100 NaN
2013-03-31 A 120 NaN
2013-06-30 A 140 NaN
2013-09-30 A 160 146
2013-12-31 A 180 166
2013-03-31 B 0 NaN
2013-06-30 B 5 NaN
2013-09-30 B 1 NaN
2013-12-31 B 3 2.5
2012-12-31 C 45 NaN
2013-03-31 C 46 NaN
2013-06-30 C 42 NaN
2013-09-30 C 30 35.5
2013-12-31 C 11 21.4
2012-12-31 D 18 NaN
2013-03-31 D 9 NaN
2013-06-30 D 13 NaN
2013-09-30 D 5 8.3
2013-12-31 D 11 9.8
2012-12-31 E 0 NaN
我可以用滚动应用(rolling_apply)或滚动求和(rolling_sum)来实现吗?还是说我必须使用循环(for loop)?
谢谢。
1 个回答
2
我觉得你可以通过一个叫做 rolling_apply
的功能,在正常的 groupby/apply
中使用它来实现。所以可以像下面这样做:
def roll_wsum(g,w,p):
rsum = pd.rolling_apply(g.values,p,lambda x: np.dot(w,x),min_periods=p)
return pd.Series(rsum,index=g.index)
weights = np.array([0.1,0.1,0.2,0.6])
df['wsum'] = df.groupby('ID')['VALUE'].apply(roll_wsum,weights,4)
print df
输出结果:
DATE ID VALUE wsum
0 2012-12-31 A 100 NaN
1 2013-03-31 A 120 NaN
2 2013-06-30 A 140 NaN
3 2013-09-30 A 160 146.0
4 2013-12-31 A 180 166.0
5 2013-03-31 B 0 NaN
6 2013-06-30 B 5 NaN
7 2013-09-30 B 1 NaN
8 2013-12-31 B 3 2.5
9 2012-12-31 C 45 NaN
10 2013-03-31 C 46 NaN
11 2013-06-30 C 42 NaN
12 2013-09-30 C 30 35.5
13 2013-12-31 C 11 21.4
14 2012-12-31 D 18 NaN
15 2013-03-31 D 9 NaN
16 2013-06-30 D 13 NaN
17 2013-09-30 D 5 8.3
18 2013-12-31 D 11 9.8
19 2012-12-31 E 0 NaN
这里,我是先按照 'ID' 来对数据进行分组,然后把每组的 'VALUE' 列传给我的 roll_wsum
函数(同时还传入加权和的权重和周期)。这个 roll_wsum
函数会调用 rolling_apply
,并给它一个简单的 lambda 函数:就是 'VALUE' 和权重的点积。此外,这里设置 min_periods=4
是很重要的,因为我们需要确保权重和 df['VALUE'].values 的长度是一样的。
由于我使用点积来计算加权和,这可能不会按照你想要的方式处理缺失值。所以,比如说,你可能更喜欢下面的方式(虽然对于示例数据来说没有区别):
def roll_wsum(g,w,p):
rsum = pd.rolling_apply(g.values,p,lambda x: np.nansum(w*x),min_periods=p)
return pd.Series(rsum,index=g.index)
weights = np.array([0.1,0.1,0.2,0.6])
df['wsum'] = df.groupby('ID')['VALUE'].apply(roll_wsum,weights,4)