2013-04-03 49 views
21

我有見底到時間序列數據的一些分層數據看起來是這樣的:重採樣在一個多指標的熊貓

df = pandas.DataFrame(
    {'value_a': values_a, 'value_b': values_b}, 
    index=[states, cities, dates]) 
df.index.names = ['State', 'City', 'Date'] 
df 

           value_a value_b 
State City  Date       
Georgia Atlanta 2012-01-01  0  10 
        2012-01-02  1  11 
        2012-01-03  2  12 
        2012-01-04  3  13 
     Savanna 2012-01-01  4  14 
        2012-01-02  5  15 
        2012-01-03  6  16 
        2012-01-04  7  17 
Alabama Mobile  2012-01-01  8  18 
        2012-01-02  9  19 
        2012-01-03  10  20 
        2012-01-04  11  21 
     Montgomery 2012-01-01  12  22 
        2012-01-02  13  23 
        2012-01-03  14  24 
        2012-01-04  15  25 

我想執行每個城市的時間重新取樣,所以像

df.resample("2D", how="sum") 

將輸出

       value_a value_b 
State City  Date       
Georgia Atlanta 2012-01-01  1  21 
        2012-01-03  5  25 
     Savanna 2012-01-01  9  29 
        2012-01-03  13  33 
Alabama Mobile  2012-01-01  17  37 
        2012-01-03  21  41 
     Montgomery 2012-01-01  25  45 
        2012-01-03  29  49 

原樣,df.resample('2D', how='sum')讓我

TypeError: Only valid with DatetimeIndex or PeriodIndex 

不夠公平,但我有點期待這個工作:

>>> df.swaplevel('Date', 'State').resample('2D', how='sum') 
TypeError: Only valid with DatetimeIndex or PeriodIndex 

在這一點我真的很運行的想法......是有一些方法棧和出棧的威力能夠幫助我嗎?

回答

20

pd.Grouper 允許您指定「目標對象的groupby指令」。在 特別是,你可以通過日期,即使df.index不是DatetimeIndex用它來組:

df.groupby(pd.Grouper(freq='2D', level=-1)) 

level=-1告訴pd.Grouper尋找在多指標的最後一個級別的日期。 此外,你可以從指數等水平值一起使用:

level_values = df.index.get_level_values 
result = (df.groupby([level_values(i) for i in [0,1]] 
         +[pd.Grouper(freq='2D', level=-1)]).sum()) 

它看起來有點笨拙,但是using_Grouper原來是要比我原來 建議更快,using_reset_index

import numpy as np 
import pandas as pd 
import datetime as DT 

def using_Grouper(df): 
    level_values = df.index.get_level_values 
    return (df.groupby([level_values(i) for i in [0,1]] 
         +[pd.Grouper(freq='2D', level=-1)]).sum()) 

def using_reset_index(df): 
    df = df.reset_index(level=[0, 1]) 
    return df.groupby(['State','City']).resample('2D').sum() 

def using_stack(df): 
    # http://stackoverflow.com/a/15813787/190597 
    return (df.unstack(level=[0,1]) 
       .resample('2D').sum() 
       .stack(level=[2,1]) 
       .swaplevel(2,0)) 

def make_orig(): 
    values_a = range(16) 
    values_b = range(10, 26) 
    states = ['Georgia']*8 + ['Alabama']*8 
    cities = ['Atlanta']*4 + ['Savanna']*4 + ['Mobile']*4 + ['Montgomery']*4 
    dates = pd.DatetimeIndex([DT.date(2012,1,1)+DT.timedelta(days = i) for i in range(4)]*4) 
    df = pd.DataFrame(
     {'value_a': values_a, 'value_b': values_b}, 
     index = [states, cities, dates]) 
    df.index.names = ['State', 'City', 'Date'] 
    return df 

def make_df(N): 
    dates = pd.date_range('2000-1-1', periods=N) 
    states = np.arange(50) 
    cities = np.arange(10) 
    index = pd.MultiIndex.from_product([states, cities, dates], 
             names=['State', 'City', 'Date']) 
    df = pd.DataFrame(np.random.randint(10, size=(len(index),2)), index=index, 
         columns=['value_a', 'value_b']) 
    return df 

df = make_orig() 
print(using_Grouper(df)) 

產量

       value_a value_b 
State City  Date       
Alabama Mobile  2012-01-01  17  37 
        2012-01-03  21  41 
     Montgomery 2012-01-01  25  45 
        2012-01-03  29  49 
Georgia Atlanta 2012-01-01  1  21 
        2012-01-03  5  25 
     Savanna 2012-01-01  9  29 
        2012-01-03  13  33 

這裏是一個有5000行數據幀比較using_Grouperusing_reset_indexusing_stack基準:

In [30]: df = make_df(10) 

In [34]: len(df) 
Out[34]: 5000 

In [32]: %timeit using_Grouper(df) 
100 loops, best of 3: 6.03 ms per loop 

In [33]: %timeit using_stack(df) 
10 loops, best of 3: 22.3 ms per loop 

In [31]: %timeit using_reset_index(df) 
1 loop, best of 3: 659 ms per loop 
+0

謝謝 - 那當然可以做這個工作,但是那個groupby逼着我們重新計算我們在分級索引中已經建立的關係。 有沒有辦法做到這一點,我們已經在我們的分層索引建立的分組,或者是層次索引只是不打算用於這種事情? –

+1

對不起,我沒有足夠的經驗與熊貓說。以上是比解決方案更多的解決方法。 'df.reset_index'可能是一個緩慢的操作,如果沒有它,這可能會更好。 – unutbu

+0

另一種方法是在重新採樣之前拆除州和城市列,但我懷疑這是否更有效。 –

11

使用堆棧的替代/拆散

df.unstack(level=[0,1]).resample('2D', how='sum').stack(level=[2,1]).swaplevel(2,0) 

           value_a value_b 
State City  Date 
Georgia Atlanta 2012-01-01  1  21 
Alabama Mobile  2012-01-01  17  37 
     Montgomery 2012-01-01  25  45 
Georgia Savanna 2012-01-01  9  29 
     Atlanta 2012-01-03  5  25 
Alabama Mobile  2012-01-03  21  41 
     Montgomery 2012-01-03  29  49 
Georgia Savanna 2012-01-03  13  33 

注:

  1. 不知道有關性能比較
  2. 可能的熊貓bug - 堆棧(水平= [2,1])的工作,但堆棧(水平= [1,2])失敗
+0

這真的很有幫助! – jarandaf

+0

在這之後,我遇到了計算'pct_change'的麻煩。與[here]類似的問題(https://stackoverflow.com/questions/23790415/how-to-groupby-multiple-columns在熊貓數據框在pct-change-calculation)。我結束了無線日執行下列操作:'reset_index,sort_values,GROUPBY,pct_change'(如鏈接) – shadi

9

這工作:

df.groupby(level=[0,1]).apply(lambda x: x.set_index('Date').resample('2D', how='sum')) 

           value_a value_b 
State City  Date 
Alabama Mobile  2012-01-01  17  37 
        2012-01-03  21  41 
     Montgomery 2012-01-01  25  45 
        2012-01-03  29  49 
Georgia Atlanta 2012-01-01  1  21 
        2012-01-03  5  25 
     Savanna 2012-01-01  9  29 
        2012-01-03  13  33 

如果日期列是一個字符串,然後轉換成日期時間提前:

df['Date'] = pd.to_datetime(df['Date']) 
+1

這應該是公認的答案 –

1

我知道這個問題是幾年的歷史,但我有同樣的問題,來到一個需要1線簡單的解決方案:

>>> import pandas as pd 
>>> ts = pd.read_pickle('time_series.pickle') 
>>> ts 
xxxxxx1 yyyyyyyyyyyyyyyyyyyyyy1 2012-07-01  1 
            2012-07-02 13 
            2012-07-03  1 
            2012-07-04  1 
            2012-07-05 10 
            2012-07-06  4 
            2012-07-07 47 
            2012-07-08  0 
            2012-07-09  3 
            2012-07-10 22 
            2012-07-11  3 
            2012-07-12  0 
            2012-07-13 22 
            2012-07-14  1 
            2012-07-15  2 
            2012-07-16  2 
            2012-07-17  8 
            2012-07-18  0 
            2012-07-19  1 
            2012-07-20 10 
            2012-07-21  0 
            2012-07-22  3 
            2012-07-23  0 
            2012-07-24 35 
            2012-07-25  6 
            2012-07-26  1 
            2012-07-27  0 
            2012-07-28  6 
            2012-07-29 23 
            2012-07-30  0 
               .. 
xxxxxxN yyyyyyyyyyyyyyyyyyyyyyN 2014-06-02  0 
            2014-06-03  1 
            2014-06-04  0 
            2014-06-05  0 
            2014-06-06  0 
            2014-06-07  0 
            2014-06-08  2 
            2014-06-09  0 
            2014-06-10  0 
            2014-06-11  0 
            2014-06-12  0 
            2014-06-13  0 
            2014-06-14  0 
            2014-06-15  0 
            2014-06-16  0 
            2014-06-17  0 
            2014-06-18  0 
            2014-06-19  0 
            2014-06-20  0 
            2014-06-21  0 
            2014-06-22  0 
            2014-06-23  0 
            2014-06-24  0 
            2014-06-25  4 
            2014-06-26  0 
            2014-06-27  1 
            2014-06-28  0 
            2014-06-29  0 
            2014-06-30  1 
            2014-07-01  0 
dtype: int64 
>>> ts.unstack().T.resample('W', how='sum').T.stack() 
xxxxxx1 yyyyyyyyyyyyyyyyyyyyyy1 2012-06-25/2012-07-01  1 
            2012-07-02/2012-07-08  76 
            2012-07-09/2012-07-15  53 
            2012-07-16/2012-07-22  24 
            2012-07-23/2012-07-29  71 
            2012-07-30/2012-08-05  38 
            2012-08-06/2012-08-12 258 
            2012-08-13/2012-08-19 144 
            2012-08-20/2012-08-26 184 
            2012-08-27/2012-09-02 323 
            2012-09-03/2012-09-09 198 
            2012-09-10/2012-09-16 348 
            2012-09-17/2012-09-23 404 
            2012-09-24/2012-09-30 380 
            2012-10-01/2012-10-07 367 
            2012-10-08/2012-10-14 163 
            2012-10-15/2012-10-21 338 
            2012-10-22/2012-10-28 252 
            2012-10-29/2012-11-04 197 
            2012-11-05/2012-11-11 336 
            2012-11-12/2012-11-18 234 
            2012-11-19/2012-11-25 143 
            2012-11-26/2012-12-02 204 
            2012-12-03/2012-12-09 296 
            2012-12-10/2012-12-16 146 
            2012-12-17/2012-12-23  85 
            2012-12-24/2012-12-30 198 
            2012-12-31/2013-01-06 214 
            2013-01-07/2013-01-13 229 
            2013-01-14/2013-01-20 192 
                  ... 
xxxxxxN yyyyyyyyyyyyyyyyyyyyyyN 2013-12-09/2013-12-15  3 
            2013-12-16/2013-12-22  0 
            2013-12-23/2013-12-29  0 
            2013-12-30/2014-01-05  1 
            2014-01-06/2014-01-12  3 
            2014-01-13/2014-01-19  6 
            2014-01-20/2014-01-26  11 
            2014-01-27/2014-02-02  0 
            2014-02-03/2014-02-09  1 
            2014-02-10/2014-02-16  4 
            2014-02-17/2014-02-23  3 
            2014-02-24/2014-03-02  1 
            2014-03-03/2014-03-09  4 
            2014-03-10/2014-03-16  0 
            2014-03-17/2014-03-23  0 
            2014-03-24/2014-03-30  9 
            2014-03-31/2014-04-06  1 
            2014-04-07/2014-04-13  1 
            2014-04-14/2014-04-20  1 
            2014-04-21/2014-04-27  2 
            2014-04-28/2014-05-04  8 
            2014-05-05/2014-05-11  7 
            2014-05-12/2014-05-18  5 
            2014-05-19/2014-05-25  2 
            2014-05-26/2014-06-01  8 
            2014-06-02/2014-06-08  3 
            2014-06-09/2014-06-15  0 
            2014-06-16/2014-06-22  0 
            2014-06-23/2014-06-29  5 
            2014-06-30/2014-07-06  1 
dtype: int64 

ts.unstack().T.resample('W', how='sum').T.stack()就是這一切!非常簡單,看起來非常高效。我正在閱讀的泡菜是331M,所以這是一個相當健壯的數據結構;我的MacBook Pro上重新採樣只需幾秒鐘。

+0

不錯,但這只是作品,如果你有一列。 –

-1

我有同樣的問題,是打破我的頭一會兒,後來我在0.19.2 docs閱讀.resample函數的文檔,我看到有一個新的kwarg稱爲「級別」,您可以使用指定級別在MultiIndex中。

編輯:在"What's New"部分的更多詳細信息。

+0

沒有真正回答關於何時需要重新取樣而保留多個索引的問題。在文檔中,kwarg級別必須是類似日期時間的參數,問題是非日期時間次級分組列 – nachonachoman

0

我還沒有檢查過這個效率,但是我對多索引執行日期時間操作的本能方式是通過一種使用字典理解的手動「拆分應用組合」過程。

假設您的DataFrame是未索引的。(你可以做.reset_index()第一),這個工作原理如下:使用

  1. 集團由非日期欄
  2. 集「日期」爲指標,並重新取樣每個塊
  3. 重新組裝pd.concat

最終的代碼如下所示:

pd.concat({g: x.set_index("Date").resample("2D").mean() 
        for g, x in house.groupby(["State", "City"])})