2013-04-03 3 views
21

У меня есть некоторые иерархические данные, которые прилегал в данных временных рядов, которая выглядит примерно так:Resampling В пределах Панды мультииндексных

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 позволяет указать «групповую инструкцию для целевого объекта». В частности, вы можете использовать его в группу по датам, даже если 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 

Вот тест сравнения using_Grouper, using_reset_index, using_stack на 5000-рядный DataFrame:

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

Спасибо, что, безусловно, выполняет эту работу, но эта группа принуждает нас чтобы перекомментировать отношения, которые мы уже установили в нашем иерархическом индексе. Нет ли способа сделать это с помощью группировок, которые мы уже построили в нашем иерархическом индексе, или иерархические индексы, которые просто не предназначены для использования в таких вещах? –

+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. Возможная ошибка панды - стек (уровень = [2,1]) работал, но стек (уровень = [1,2]) не
+0

Это было действительно полезно! – jarandaf

+0

Я столкнулся с проблемой расчета 'pct_change' сразу после этого. Аналогичная проблема с [здесь] (https://stackoverflow.com/questions/23790415/how-to-groupby-multiple-columns -in-pandas-dataframe-in-pct-change-расчет). Я закончил wi th делает следующее: '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

Nice, но это работает только в том случае, если у вас есть один столбец. –

-1

Я была такая же проблема, ломал голову на некоторое время, но потом я прочитал документацию функции .resample в 0.19.2 docs, и я вижу, что есть новый kwarg называемый «уровень», который вы можете использовать, чтобы указать уровня в MultiIndex.

Редактировать: Подробнее в разделе "What's New".

+0

На самом деле не отвечает на вопрос о необходимости повторной выборки при сохранении нескольких индексов. В документах уровень kwarg должен быть параметром типа datetime, и вопрос касался столбцов вторичной группировки не-datetime – nachonachoman

0

Я не проверял эффективность этого, но мой инстинктивный способ выполнения операций datetime в мультииндексе был каким-то ручным процессом split-apply-comb, используя понимание словаря.

Предполагая, что ваш DataFrame не проиндексирован.(Вы можете сделать .reset_index() первый), это работает следующим образом:

  1. Группа по без даты столбцов
  2. Set «Дата» в качестве индекса и ресэмплировать каждый кусок
  3. пересобираться использованием pd.concat

Окончательный код выглядит так:

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