2017-08-03 94 views
2

我目前正在使用Python中的面板數據,並試圖計算給定組(ID)內每個時間序列觀察值的滾動平均值。將函數應用於Pandas Group by

由於我的數據集的大小(成千上萬個具有多個時間段的組),因此.groupby和.apply()函數花費的時間太長以至於無法計算(已經運行了一個多小時,而且還是一無所獲 - 整個數據集僅包含約300k個觀測值)。

我希望最終遍歷多列,執行下列操作:

  1. 計算在給定列中的每個時間步長的滾動平均值,每組ID
  2. 創建包含一個新列原始值與移動平均值之間的差異[x_t - (x_t-1 + x_t)/ 2]
  3. 將列存儲在新的DataFrame中,該列與原始數據集相同,但它具有來自#2的殘差而不是原來的價值。
  4. 重複並追加新的殘差df_resid(如下圖所示)

    df_resid 
    date  id rev_resid exp_resid 
    2005-09-01 1   NaN   NaN 
    2005-12-01 1  -10000  -5500 
    2006-03-01 1  -352584 -262058.5 
    2006-06-01 1  240000 190049.5 
    2006-09-01 1 82648.75 37724.25 
    2005-09-01 2   NaN   NaN 
    2005-12-01 2  4206.5  24353 
    2006-03-01 2  -302574  -331951 
    2006-06-01 2  103179 117405.5 
    2006-09-01 2  -52650 -72296.5 
    

這裏的原始數據的小樣本。

df 
date  id  rev  exp 
2005-09-01 1 745168.0 545168.0  
2005-12-01 1 725168.0 534168.0  
2006-03-01 1 20000.0 10051.0 
2006-06-01 1 500000.0 390150.0 
2006-09-01 1 665297.5 465598.5 
2005-09-01 2 956884.0 736987.0 
2005-12-01 2 965297.0 785693.0 
2006-03-01 2 360149.0 121791.0 
2006-06-01 2 566507.0 356602.0 
2006-09-01 2 461207.0 212009.0 

而且(很慢)代碼:

df['rev_resid'] = df.groupby('id')['rev'].apply(lambda x:x.rolling(center=False,window=2).mean()) 

我希望有一個更高效計算的方式來做到這一點(主要是相對於#1),並且可以擴展到多列。

任何幫助將被真正讚賞。

+0

希望該鏈接可以幫助https://stackoverflow.com/questions/13996302/python-rolling-functions-for-groupby-object – Wen

回答

2

爲了加快計算速度,如果數據幀已經排序在'id'那麼你不必在groupby內做rolling(如果它沒有排序...這樣做)。然後,由於您的窗口只有長度2,我們通過檢查其中的id == id.shift來驗證結果,因爲它已排序。

d1 = df[['rev', 'exp']] 
df.join(
    d1.rolling(2).mean().rsub(d1).add_suffix('_resid')[df.id.eq(df.id.shift())] 
) 

     date id  rev  exp rev_resid exp_resid 
0 2005-09-01 1 745168.0 545168.0  NaN  NaN 
1 2005-12-01 1 725168.0 534168.0 -10000.00 -5500.00 
2 2006-03-01 1 20000.0 10051.0 -352584.00 -262058.50 
3 2006-06-01 1 500000.0 390150.0 240000.00 190049.50 
4 2006-09-01 1 665297.5 465598.5 82648.75 37724.25 
5 2005-09-01 2 956884.0 736987.0  NaN  NaN 
6 2005-12-01 2 965297.0 785693.0 4206.50 24353.00 
7 2006-03-01 2 360149.0 121791.0 -302574.00 -331951.00 
8 2006-06-01 2 566507.0 356602.0 103179.00 117405.50 
9 2006-09-01 2 461207.0 212009.0 -52650.00 -72296.50 
+1

很好的解決方案,而不'groupby'要快〜 – Wen

+0

謝謝@Wen ! – piRSquared