簡體   English   中英

Pandas groupby 具有滾動日期偏移的多列 - 如何?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM