我正在尝试根据移动的2个工作日窗口对分区数据进行滚动求和。它感觉应该既简单又广泛使用,但解决方案超出了我的范围。
#generate sample data
import pandas as pd
import numpy as np
import datetime
vals = [-4,17,-4,-16,2,20,3,10,-17,-8,-21,2,0,-11,16,-24,-10,-21,5,12,14,9,-15,-15]
grp = ['X']*6 + ['Y'] * 6 + ['X']*6 + ['Y'] * 6
typ = ['foo']*12+['bar']*12
dat = ['19/01/18','19/01/18','22/01/18','22/01/18','23/01/18','24/01/18'] * 4
#create dataframe with sample data
df = pd.DataFrame({'group': grp,'type':typ,'value':vals,'date':dat})
df.date = pd.to_datetime(df.date)
df.head(12)
给出以下内容(注意这只是头12行):
date group type value
0 19/01/2018 X foo -4
1 19/01/2018 X foo 17
2 22/01/2018 X foo -4
3 22/01/2018 X foo -16
4 23/01/2018 X foo 2
5 24/01/2018 X foo 20
6 19/01/2018 Y foo 3
7 19/01/2018 Y foo 10
8 22/01/2018 Y foo -17
9 22/01/2018 Y foo -8
10 23/01/2018 Y foo -21
11 24/01/2018 Y foo 2
所需的结果是(此处显示的所有行):
date group type 2BD Sum
1 19/01/2018 X foo 13
2 22/01/2018 X foo -7
3 23/01/2018 X foo -18
4 24/01/2018 X foo 22
5 19/01/2018 Y foo 13
6 22/01/2018 Y foo -12
7 23/01/2018 Y foo -46
8 24/01/2018 Y foo -19
9 19/01/2018 X bar -11
10 22/01/2018 X bar -19
11 23/01/2018 X bar -18
12 24/01/2018 X bar -31
13 19/01/2018 Y bar 17
14 22/01/2018 Y bar 40
15 23/01/2018 Y bar 8
16 24/01/2018 Y bar -30
我已查看此question并尝试了
df.groupby(['group','type']).rolling('2d',on='date').agg({'value':'sum'}
).reset_index().groupby(['group','type','date']).agg({'value':'sum'}).reset_index()
如果'值'哪个会正常工作?总是积极的,但这不是这里的情况。我已经尝试了许多导致错误的其他方法,如果它有价值,我可以列出。有人可以帮忙吗?
答案 0 :(得分:0)
IIUC,从您的代码开始
import pandas as pd
import numpy as np
import datetime
vals = [-4,17,-4,-16,2,20,3,10,-17,-8,-21,2,0,-11,16,-24,-10,-21,5,12,14,9,-15,-15]
grp = ['X']*6 + ['Y'] * 6 + ['X']*6 + ['Y'] * 6
typ = ['foo']*12+['bar']*12
dat = ['19/01/18','19/01/18','22/01/18','22/01/18','23/01/18','24/01/18'] * 4
df = pd.DataFrame({'group': grp,'type':typ,'value':vals,'date':dat})
df.date = pd.to_datetime(df.date)
我们首先按group
,type
和date
进行分组,然后在每天内总结:
df2 = df.groupby(["group", "type", "date"]).sum().reset_index().sort_values("date")
现在,您只需使用rolling
执行min_periods=1
和(),这样您的第一个值就不是NaN
。但是,你不会
k = df2.groupby(["group", "type"]).value.rolling(window=2, min_periods=1).sum()
这会产生
group type
X bar 0 -11.0
1 -19.0
2 -18.0
3 -31.0
foo 4 13.0
5 -7.0
6 -18.0
7 22.0
Y bar 8 17.0
9 40.0
10 8.0
11 -30.0
foo 12 13.0
13 -12.0
14 -46.0
15 -19.0
这已经是您想要的,但没有您的date
值。为了得到日期,我们可以在这里做一个技巧,这只是改变你的这个多指数obj的第三级,你的date
值在类似的df中以相同的方式分组。因此,我们可以做到
aux = df2.groupby(["group", "type", "date"]).date.rolling(2).count().index.get_level_values(2)
并替换索引:
k.index = pd.MultiIndex.from_tuples([(k.index[x][0], k.index[x][1], aux[x]) for x in range(len(k.index))])
最后,您有预期的输出:
k.to_frame()
group type date value
0 X bar 2018-01-19 -11.0
1 X bar 2018-01-22 -19.0
2 X bar 2018-01-23 -18.0
3 X bar 2018-01-24 -31.0
4 X foo 2018-01-19 13.0
5 X foo 2018-01-22 -7.0
6 X foo 2018-01-23 -18.0
7 X foo 2018-01-24 22.0
8 Y bar 2018-01-19 17.0
9 Y bar 2018-01-22 40.0
10 Y bar 2018-01-23 8.0
11 Y bar 2018-01-24 -30.0
12 Y foo 2018-01-19 13.0
13 Y foo 2018-01-22 -12.0
14 Y foo 2018-01-23 -46.0
15 Y foo 2018-01-24 -19.0
答案 1 :(得分:0)
我希望以下方法能起作用:
g = lambda ts: ts.rolling('2B', on='date')['value'].sum()
df.groupby(['group', 'type']).apply(g)
但是,由于工作日的频率不是固定的,因此出现错误。
这使我提出了以下丑陋的解决方案:
value_per_bday = lambda df: df.resample('B', on='date')['value'].sum()
df = df.groupby(['group', 'type']).apply(value_per_bday).stack()
value_2_bdays = lambda x: x.rolling(2, min_periods=1).sum()
df = df.groupby(axis=0, level=['group', 'type']).apply(value_2_bdays)
也许您可以选择使用某个功能听起来更好。
def resample_and_sum(x):
x = x.resample('B', on='date')['value'].sum()
x = x.rolling(2, min_periods=1).sum()
return x
df = df.groupby(['group', 'type']).apply(resample_and_sum).stack()