2017-05-29 40 views
2

我想將滾動函數應用於由兩列重複日期條目分組的數據框。具體來說,將「freq」和「window」作爲日期時間值,而不是簡單地整數。將滾動函數應用於groupby多列

原則上,我試圖結合How to apply rolling functions in a group by object in pandaspandas rolling sum of last five minutes中的方法。

輸入

下面是數據的樣本,一個ID = 33,雖然我們預計幾個ID的。

X = [{'date': '2017-02-05', 'id': 33, 'item': 'A', 'points': 20}, 
{'date': '2017-02-05', 'id': 33, 'item': 'B', 'points': 10}, 
{'date': '2017-02-06', 'id': 33, 'item': 'B', 'points': 10}, 
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1}, 
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1}, 
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1}, 
{'date': '2017-02-13', 'id': 33, 'item': 'A', 'points': 4}] 

# df = pd.DataFrame(X) and reindex df to pd.to_datetime(df['date']) 

df 

      id item points 
date      
2017-02-05 33 A  20 
2017-02-05 33 B  10 
2017-02-06 33 B  10 
2017-02-11 33 A  1 
2017-02-11 33 A  1 
2017-02-11 33 A  1 
2017-02-13 33 A  4 

目標

樣品每個的 'id' 每2天(FREQ = '2D')和在所述前三天返回總點數的總和爲每個項目(窗口= '3D' ),結束日期包容

所需的輸出

  id A B 
date      
2017-02-05 33 20 10 
2017-02-07 33 20 30  
2017-02-09 33 0 10 
2017-02-11 33 3 0 
2017-02-13 33 7 0 

例如在包含權利的結束日期2017-02-13中,我們會將2017-02-11的3天期間抽樣爲2017-02-13。在此期間,ID = 33具有A點的等於1 + 1 + 1 + 4 = 7

嘗試

GROUPBY的與pd.rolling_sum試圖如下沒有工作的總和,由於反覆日期

df.groupby(['id', 'item'])['points'].apply(pd.rolling_sum, freq='4D', window=3) 
ValueError: cannot reindex from a duplicate axis 

還請注意,從文檔http://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.rolling_apply.html「窗口」是表示大小採樣週期一個int,而不是幾天採樣數。

我們也可以嘗試重新採樣並使用最後,然而3天所需的外觀,背部也不會被使用

df.groupby(['id', 'item'])['points'].resample('2D', label='right', closed='right').\ 
apply(lambda x: x.last('3D').sum()) 

id item date  
33 A  2017-02-05 20 
      2017-02-07  0 
      2017-02-09  0 
      2017-02-11  3 
      2017-02-13  4 
    B  2017-02-05 10 
      2017-02-07 10 

當然,設立了唯一的ID號循環,選擇df_id = df [df ['id'] == ID],並且對這些時間段進行求和可以工作,但是計算量很大,並且不會利用groupby的良好矢量化。

感謝@jezrael對於好的建議,到目前爲止

注意

熊貓版= 0.20.1

我有點困惑,爲什麼在滾動的文檔()這裏:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rolling.html 建議「窗口」參數可以在一個int或偏移量,但在嘗試df.rolling(window ='3D',...)我得到raise ValueError("window must be an integer") 看來,上述文件是不符合最新C從./core/window開始滾動窗口。潘岳: https://github.com/pandas-dev/pandas/blob/master/pandas/core/window.py

elif not is_integer(self.window): 
      raise ValueError("window must be an integer") 

回答

2
  • 這是最容易操作resamplerolling與日期的頻率,當我們有一個單級日期時間指數。
  • 但是,我不能pivot/unstack適當無需處理重複A/B這麼我groupbysum
  • unstack一個水平date這樣我就可以fill_value=0。目前,我不能fill_value=0當我unstack一次超過一個級別。我彌補它與轉置T
  • 現在,我已經得到了在指數單級,我重新編制一個日期範圍從最小到最大值在指數
  • 最後,我做了滾動3每天總結並重新抽樣,結果每2天resample
  • 我清理了一些重命名索引和一個更多的關鍵。

s = df.set_index(['id', 'item'], append=True).points 
s = s.groupby(level=['date', 'id', 'item']).sum() 

d = s.unstack('date', fill_value=0).T 
tidx = pd.date_range(d.index.min(), d.index.max()) 
d = d.reindex(tidx, fill_value=0) 

d1 = d.rolling('3D').sum().resample('2D').first().astype(d.dtypes).stack(0) 
d1 = d1.rename_axis(['date', 'id']).rename_axis(None, 1) 
print(d1) 

       A B 
date  id   
2017-02-05 33 20 10 
2017-02-07 33 20 20 
2017-02-09 33 0 0 
2017-02-11 33 3 0 
2017-02-13 33 7 0 
+0

感謝解釋。有關使用滾動方法訪問日期時間值的任何提示(例如,給定窗口中最近一次非零輸入的時間)?目前,似乎只有浮點數X可以在像d.rolling('3D')這樣的調用中訪問。apply(lambda X:func(X))。resample('2D') – Quetzalcoatl

+0

聽起來像它應該是一個單獨的問題。提示將在屏蔽零作爲「np.nan」後使用'pd.Series.first_valid_index'或'pd.Series.last_valid_index'。你也可以在'numpy'中做一些其他的技巧。 – piRSquared

0
df = pd.DataFrame(X) 

# group sum by day 
df = df.groupby(['date', 'id', 'item'])['points'].sum().reset_index().sort_values(['date', 'id', 'item']) 

# convert index to datetime index 
df = df.set_index('date') 
df.index = DatetimeIndex(df.index) 

# rolloing sum by 3D 
df['pointsum'] = df.groupby(['id', 'item']).transform(lambda x: x.rolling(window='3D').sum()) 

# reshape dataframe 
df = df.reset_index().set_index(['date', 'id', 'item'])['pointsum'].unstack().reset_index().set_index('date').fillna(0) 

df 
+0

這似乎沒有解決'2D'採樣頻率? – Quetzalcoatl

+0

可以加入「x.rolling(window ='3D')」嗎?樣本數據太少,我無法理解整個問題。 – xmduhan

+0

看到piRsquared的回答:-) – Quetzalcoatl