[英]Pandas groupby multiple columns with rolling date offset - How?
我正在嘗試根據移動的 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
我已經查看了這個問題並嘗試過
df.groupby(['group','type']).rolling('2d',on='date').agg({'value':'sum'}
).reset_index().groupby(['group','type','date']).agg({'value':'sum'}).reset_index()
如果 'value' 總是正數,這會很好用,但這里的情況並非如此。 我嘗試了許多其他導致錯誤的方法,如果它有價值,我可以列出。 任何人都可以幫忙嗎?
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
s和date
然后在每天內總結:
df2 = df.groupby(["group", "type", "date"]).sum().reset_index().sort_values("date")
現在你可以用min_periods=1
來執行rolling
求和(),這樣你的第一個值就不是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
我希望以下內容起作用:
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()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.