2013-11-27 4 views
1

Я пытаюсь понять идеальный способ организации данных в Pandas для достижения наилучшей совокупной производительности. Данные, которые я имею в виду, имеют форму yyyy-mm.csv, которую я только что прочитал_csv, а затем to_hdf. Как правило, он выглядит немного как это:Производительность агрегатов Pandas и HDF5

ObjectID Отметка парам ParamB -> ParamZ
1 2013-01-01 00:00:00 1 9
2 2013-01-01 00:00:00 3 2
1 2013-01-01 00:10:00 8 11
2 2013-01-01 00:10:00 6 14

Есть около 50 объектов идентификаторы и показания для каждой партии 10 минут для весь месяц. Конечным результатом, который я хочу достичь, являются агрегированные данные (например, среднее значение) для одного параметра, сгруппированного по месяцу (или потенциально более тонкого разрешения в конце концов), скажем, через 5 лет.

Что я обнаружил до сих пор, так это то, что HDFStore.select из одного столбца на самом деле не намного быстрее, чем приведение всех этих параметров в один кадр данных сразу. Поэтому он чувствует себя очень расточительно, и производительность невелика. Не зная точно, почему это так, я не могу решить, как лучше двигаться вперед. Кажется, что если данные были транспонированы так, что yyyy-mm был вдоль оси x с dd hh: mm: ss вниз по оси y, и был один из этих кадров данных на один параметр, что производительность будет значительно улучшаться, поскольку может привести к большему количеству данных за один удар. Группировка действительно быстрая, как только вещи были прочитаны с диска. Однако я совсем не убежден, что так оно и должно использоваться. Может ли кто-нибудь посоветовать лучший способ организовать и сохранить данные?

Благодаря

+0

pls показывают образец кадра с агрегацией, которую вы хотите сделать с исполняемым кодом (в небольшом размере, конечно). – Jeff

+0

также показывает код того, что вы сейчас делаете – Jeff

ответ

1

Pls обзор HDFStore документы here, и cookboo рецепты here

PyTables хранит данные в формате строки-ориентированный, так что приличествует вам, как правило, длинные и не очень широкие таблицы. Однако, если вы склонны запрашивать и нуждаться/хотите всю строку, тогда ширина не представляет проблемы.

С другой стороны, если вы, как правило, после небольшого подмножества столбцов, вы захотите очертить таблицу до краткости (возможно, с той же схемой индексирования), чтобы вы могли использовать таблицу «master» для запуска запрос, затем выберите «столбцы» (другие таблицы) по мере необходимости. Вы можете выполнить это с помощью методов append_to_multiple/select_from_multiple, например. В крайнем случае, вы можете сохранить один столбец в отдельной группе и сделать столбец-ориентированный стол. Однако это существенно замедлит работу, если вы хотите выбрать множество столбцов.

Кроме того, вы всегда хотите иметь запрашиваемые столбцы как indexes или data_columns, так как они разрешают запросы в первую очередь и индексируются.

Таким образом, это сводится к соотношению запросов, которые выбирают множество столбцов и выборок с одним столбцом.

Например

In [5]: df = DataFrame(np.random.randn(16,2), 
         columns=['A','B'], 
         index=MultiIndex.from_tuples(
          [ (i,j) for i in range(4) for j in date_range(
            '20130101 00:00:00',periods=4,freq='10T') ], 
          names=['id','date'])) 

In [6]: df 
Out[6]: 
           A   B 
id date         
0 2013-01-01 00:00:00 -0.247945 0.954260 
    2013-01-01 00:10:00 1.035678 -0.657710 
    2013-01-01 00:20:00 -2.399376 -0.188057 
    2013-01-01 00:30:00 -1.043764 0.510098 
1 2013-01-01 00:00:00 -0.009998 0.239947 
    2013-01-01 00:10:00 2.038563 0.640080 
    2013-01-01 00:20:00 1.123922 -0.944170 
    2013-01-01 00:30:00 -1.757766 -1.398392 
2 2013-01-01 00:00:00 -1.053324 -1.015211 
    2013-01-01 00:10:00 0.062408 -1.476484 
    2013-01-01 00:20:00 -1.202875 -0.747429 
    2013-01-01 00:30:00 -0.798126 -0.485392 
3 2013-01-01 00:00:00 0.496098 0.700073 
    2013-01-01 00:10:00 -0.042914 1.099115 
    2013-01-01 00:20:00 -1.762597 -0.239100 
    2013-01-01 00:30:00 -0.344125 -1.607524 

[16 rows x 2 columns] 

В 0.12, использовать table=True, а не format

In [7]: df.to_hdf('test.h5','df',mode='w',format='table') 

In [8]: store = pd.HDFStore('test.h5') 

In [9]: store 
Out[9]: 
<class 'pandas.io.pytables.HDFStore'> 
File path: test.h5 
/df   frame_table (typ->appendable_multi,nrows->16,ncols->4,indexers->[index],dc->[date,id]) 

In [10]: store.select('df',where='id=0') 
Out[10]: 
           A   B 
id date         
0 2013-01-01 00:00:00 -0.247945 0.954260 
    2013-01-01 00:10:00 1.035678 -0.657710 
    2013-01-01 00:20:00 -2.399376 -0.188057 
    2013-01-01 00:30:00 -1.043764 0.510098 

[4 rows x 2 columns] 

Это 0,13 синтаксис, это немного сложнее в 0.12

In [18]: store.select('df',where='date>"20130101 00:10:00" & date<"20130101 00:30:00"') 
Out[18]: 
           A   B 
id date         
0 2013-01-01 00:20:00 -2.399376 -0.188057 
1 2013-01-01 00:20:00 1.123922 -0.944170 
2 2013-01-01 00:20:00 -1.202875 -0.747429 
3 2013-01-01 00:20:00 -1.762597 -0.239100 

[4 rows x 2 columns] 

In [19]: store.close() 

Так, например, чтобы сделать GroupBy на идентификатор, вы можете выбрать все из уникальных идентификаторов (используется метод select_column. Затем перебирать эти, делая запрос и выполнять ваши функции по результатам. Это будет довольно быстро, и это индексированные столбцы Что-то вроде этого:.

In [24]: ids = store.select_column('df','id').unique() 

In [25]: ids 
Out[25]: array([0, 1, 2, 3]) 

In [27]: pd.concat([ store.select('df',where='id={0}'.format(i)).sum() for i in ids ],axis=1) 
Out[27]: 
      0   1   2   3 
A -2.655407 1.394721 -2.991917 -1.653539 
B 0.618590 -1.462535 -3.724516 -0.047436 

[2 rows x 4 columns] 

мульти-GroupBy это просто сочетание запрос, например id=1 & date>="20130101 00:10:00' & date<='20130101 00:30:00'

Вы можете найти этот пример поучителен, а here