Улучшение панд (PyTables?) Таблица HDF5 записи

я использую панд для исследований уже около двух месяцев с большим эффектом. С большим количеством наборов данных событий трассировки среднего размера pandas + PyTables (интерфейс HDF5) делает огромную работу, позволяя мне обрабатывать гетерогенные данные, используя все инструменты Python, которые я знаю и люблю.

вообще говоря, я использую фиксированный (ранее "Storer") формат в PyTables, так как мой рабочий процесс записывается один раз, читается много, и многие из моих наборов данных имеют такой размер, что я могу загрузить 50-100 их в память за один раз без серьезных недостатков. (NB: я делаю большую часть своей работы на машинах серверного класса Opteron с системной памятью 128GB+.)

однако для больших наборов данных (500 МБ и выше) я хотел бы иметь возможность использовать более масштабируемые возможности произвольного доступа и запросов формата "таблицы" PyTables, чтобы я мог выполнять свои запросы из памяти, а затем загружать гораздо меньший набор результатов в память для обработки. Самой большой проблемой здесь, однако, писать спектакль. Да, как я уже сказал, мой рабочий процесс-писать один раз, читать-много, но относительное время по-прежнему неприемлемо.

например, недавно я запустил большую факторизацию Cholesky, которая заняла 3 минуты 8 секунд (188 секунд) на моей 48-ядерном компьютере. При этом генерируется файл трассировки ~2.2 Гб-трассировка генерируется параллельно с программой, поэтому дополнительного "времени создания трассировки" нет."

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

мои тесты были первоначально запущены с pandas 0.12, numpy 1.7.1, PyTables 2.4.0 и numexpr 0.20.1. Моя 48-ядерная машина работает на 2.8 GHz на ядро, и я пишу в файловую систему ext3, которая, вероятно (но не обязательно) на SSD.

я могу записать весь набор данных в файл формата HDF5 хранилища (результирующий размер файла: 3,3 ГБ) за 7,1 секунды. Тот же набор данных, записанный в формат таблицы (размер результирующего файла также 3,3 ГБ), занимает 178,7 секунды для записи.

код выглядит следующим образом:

with Timer() as t:
    store = pd.HDFStore('test_storer.h5', 'w')
    store.put('events', events_dataset, table=False, append=False)
print('Fixed format write took ' + str(t.interval))
with Timer() as t:
    store = pd.HDFStore('test_table.h5', 'w')
    store.put('events', events_dataset, table=True, append=False)
print('Table format write took ' + str(t.interval))

и выход просто

Fixed format write took 7.1
Table format write took 178.7

мой набор данных имеет 28,880,943 строки, а столбцы являются основными типами данных:

node_id           int64
thread_id         int64
handle_id         int64
type              int64
begin             int64
end               int64
duration          int64
flags             int64
unique_id         int64
id                int64
DSTL_LS_FULL    float64
L2_DMISS        float64
L3_MISS         float64
kernel_type     float64
dtype: object

...так что я не думаю, что должны быть какие-либо проблемы с данными со скоростью записи.

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

теперь я понимаю, что документация pandas говорит, что формат хранилища предлагает значительно быстрее пишет и немного быстрее читает. (Я действительно испытываю более быстрые чтения, как чтение хранилища формат, кажется, занимает около 2,5 секунд, в то время как чтение формата таблицы занимает около 10 секунд.) Но действительно кажется чрезмерным, что запись в формате таблицы должна занимать в 25 раз больше времени, чем запись в формате хранилища.

может ли кто-либо из людей, связанных с PyTables или pandas объяснить архитектурные (или иначе) причины, почему запись в запрашиваемый формат (который явно требует очень мало дополнительных данных) должна занять на порядок больше времени? И есть ли надежда на улучшение это в будущем? Я бы хотел внести свой вклад в тот или иной проект, поскольку моя область-высокопроизводительные вычисления, и я вижу значительный вариант использования для обоих проектов в этой области.... но было бы полезно, чтобы получить некоторые разъяснения по вопросам первого, и/или некоторые советы о том, как ускорить от тех, кто знает, как построена система.

EDIT:

запуск предыдущих тестов с %prun в IPython дает следующее (Несколько уменьшенное для удобства чтения) вывод профиля для хранилища / фиксированный формат:

%prun -l 20 profile.events.to_hdf('test.h5', 'events', table=False, append=False)

3223 function calls (3222 primitive calls) in 7.385 seconds

Ordered by: internal time
List reduced from 208 to 20 due to restriction <20>

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    6    7.127    1.188    7.128    1.188 {method '_createArray' of 'tables.hdf5Extension.Array' objects}
    1    0.242    0.242    0.242    0.242 {method '_closeFile' of 'tables.hdf5Extension.File' objects}
    1    0.003    0.003    0.003    0.003 {method '_g_new' of 'tables.hdf5Extension.File' objects}
   46    0.001    0.000    0.001    0.000 {method 'reduce' of 'numpy.ufunc' objects}

и следующее для формата таблиц:

   %prun -l 40 profile.events.to_hdf('test.h5', 'events', table=True, append=False, chunksize=1000000)

   499082 function calls (499040 primitive calls) in 188.981 seconds

   Ordered by: internal time
   List reduced from 526 to 40 due to restriction <40>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       29   92.018    3.173   92.018    3.173 {pandas.lib.create_hdf_rows_2d}
      640   20.987    0.033   20.987    0.033 {method '_append' of 'tables.hdf5Extension.Array' objects}
       29   19.256    0.664   19.256    0.664 {method '_append_records' of 'tables.tableExtension.Table' objects}
      406   19.182    0.047   19.182    0.047 {method '_g_writeSlice' of 'tables.hdf5Extension.Array' objects}
    14244   10.646    0.001   10.646    0.001 {method '_g_readSlice' of 'tables.hdf5Extension.Array' objects}
      472   10.359    0.022   10.359    0.022 {method 'copy' of 'numpy.ndarray' objects}
       80    3.409    0.043    3.409    0.043 {tables.indexesExtension.keysort}
        2    3.023    1.512    3.023    1.512 common.py:134(_isnull_ndarraylike)
       41    2.489    0.061    2.533    0.062 {method '_fillCol' of 'tables.tableExtension.Row' objects}
       87    2.401    0.028    2.401    0.028 {method 'astype' of 'numpy.ndarray' objects}
       30    1.880    0.063    1.880    0.063 {method '_g_flush' of 'tables.hdf5Extension.Leaf' objects}
      282    0.824    0.003    0.824    0.003 {method 'reduce' of 'numpy.ufunc' objects}
       41    0.537    0.013    0.668    0.016 index.py:607(final_idx32)
    14490    0.385    0.000    0.712    0.000 array.py:342(_interpret_indexing)
       39    0.279    0.007   19.635    0.503 index.py:1219(reorder_slice)
        2    0.256    0.128   10.063    5.031 index.py:1099(get_neworder)
        1    0.090    0.090  119.392  119.392 pytables.py:3016(write_data)
    57842    0.087    0.000    0.087    0.000 {numpy.core.multiarray.empty}
    28570    0.062    0.000    0.107    0.000 utils.py:42(is_idx)
    14164    0.062    0.000    7.181    0.001 array.py:711(_readSlice)

EDIT 2:

запуск снова с предварительной версией pandas 0.13 (вытащил 20 ноября 2013 года около 11:00 EST), время записи для формата таблиц значительно улучшилось, но все еще не сравнивается "разумно" со скоростью записи в формате Storer/Fixed.

%prun -l 40 profile.events.to_hdf('test.h5', 'events', table=True, append=False, chunksize=1000000)

         499748 function calls (499720 primitive calls) in 117.187 seconds

   Ordered by: internal time
   List reduced from 539 to 20 due to restriction <20>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      640   22.010    0.034   22.010    0.034 {method '_append' of 'tables.hdf5Extension.Array' objects}
       29   20.782    0.717   20.782    0.717 {method '_append_records' of 'tables.tableExtension.Table' objects}
      406   19.248    0.047   19.248    0.047 {method '_g_writeSlice' of 'tables.hdf5Extension.Array' objects}
    14244   10.685    0.001   10.685    0.001 {method '_g_readSlice' of 'tables.hdf5Extension.Array' objects}
      472   10.439    0.022   10.439    0.022 {method 'copy' of 'numpy.ndarray' objects}
       30    7.356    0.245    7.356    0.245 {method '_g_flush' of 'tables.hdf5Extension.Leaf' objects}
       29    7.161    0.247   37.609    1.297 pytables.py:3498(write_data_chunk)
        2    3.888    1.944    3.888    1.944 common.py:197(_isnull_ndarraylike)
       80    3.581    0.045    3.581    0.045 {tables.indexesExtension.keysort}
       41    3.248    0.079    3.294    0.080 {method '_fillCol' of 'tables.tableExtension.Row' objects}
       34    2.744    0.081    2.744    0.081 {method 'ravel' of 'numpy.ndarray' objects}
      115    2.591    0.023    2.591    0.023 {method 'astype' of 'numpy.ndarray' objects}
      270    0.875    0.003    0.875    0.003 {method 'reduce' of 'numpy.ufunc' objects}
       41    0.560    0.014    0.732    0.018 index.py:607(final_idx32)
    14490    0.387    0.000    0.712    0.000 array.py:342(_interpret_indexing)
       39    0.303    0.008   19.617    0.503 index.py:1219(reorder_slice)
        2    0.288    0.144   10.299    5.149 index.py:1099(get_neworder)
    57871    0.087    0.000    0.087    0.000 {numpy.core.multiarray.empty}
        1    0.084    0.084   45.266   45.266 pytables.py:3424(write_data)
        1    0.080    0.080   55.542   55.542 pytables.py:3385(write)

я заметил во время выполнения этих тестов, что там длительные периоды, когда запись кажется "паузой" (файл на диске не активно растет), и все же есть также низкое использование процессора в течение некоторых из этих периодов.

я начинаю подозревать, что некоторые известные ограничения ext3 могут плохо взаимодействовать с панд или PyTables. Ext3 и другие файловые системы, не основанные на экстенте, иногда пытаются быстро разорвать связь с большими файлами, и аналогичная производительность системы (низкое использование процессора, но долгое время ожидания) очевидна даже во время простой " rm " файла 1GB, например.

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

однако при повторном запуске этого теста с index=None производительность резко улучшается (~50s против ~120 при индексировании). Таким образом, казалось бы, либо этот процесс по-прежнему привязан к процессору (моя система имеет относительно старые процессоры AMD Opteron Istanbul под управлением @ 2.8 GHz, хотя это так также есть 8 сокетов с 6 основными процессорами в каждом, все, кроме одного из которых, конечно, сидят без дела во время записи), или что существует некоторый конфликт между тем, как PyTables или pandas пытается манипулировать/читать/анализировать файл, когда уже частично или полностью в файловой системе, что вызывает патологически плохое поведение ввода-вывода при индексировании.

EDIT 3:

@Jeff предложил тесты на меньшем наборе данных (1.3 Гб на диске) после обновления PyTables с 2.4 до 3.0.0, привели меня сюда:

In [7]: %timeit f(df)
1 loops, best of 3: 3.7 s per loop

In [8]: %timeit f2(df) # where chunksize= 2 000 000
1 loops, best of 3: 13.8 s per loop

In [9]: %timeit f3(df) # where chunksize= 2 000 000
1 loops, best of 3: 43.4 s per loop

на самом деле, моя производительность, похоже, превосходит его во всех сценариях, за исключением случаев, когда индексирование включено (по умолчанию). Однако индексирование по-прежнему кажется убийцей, и если я интерпретирую вывод из top и ls когда я запускаю эти тесты, остаются периоды времени, когда не происходит существенной обработки или записи файлов (т. е. использование ЦП для процесса Python близко к 0, а размер файла остается постоянный.) Я могу только предположить, что это чтение файлов. Почему чтение файлов вызывает замедление, мне трудно понять, так как я могу надежно загрузить весь файл 3+ GB с этого диска в память менее чем за 3 секунды. Если они не читают файлы, то что система "ждет"? (Никто больше не входит в систему, и нет никакой другой активности файловой системы.)

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

In [28]: %time f(profile.events)
CPU times: user 0 ns, sys: 7.16 s, total: 7.16 s
Wall time: 7.51 s

In [29]: %time f2(profile.events)
CPU times: user 18.7 s, sys: 14 s, total: 32.7 s
Wall time: 47.2 s

In [31]: %time f3(profile.events)
CPU times: user 1min 18s, sys: 14.4 s, total: 1min 32s
Wall time: 2min 5s

тем не менее, похоже, что индексирование вызывает значительное замедление для моего варианта использования. Возможно, я должен попытаться ограничить индексированные поля, а не просто выполнять случай по умолчанию (который вполне может быть индексирование всех полей в фрейме данных)? Я не уверен, как это может повлиять на время запроса, особенно в случаях, когда запрос выбирает на основе неиндексированного поля.

по запросу Джеффа, ptdump результирующего файла.

ptdump -av test.h5
/ (RootGroup) ''
  /._v_attrs (AttributeSet), 4 attributes:
   [CLASS := 'GROUP',
    PYTABLES_FORMAT_VERSION := '2.1',
    TITLE := '',
    VERSION := '1.0']
/df (Group) ''
  /df._v_attrs (AttributeSet), 14 attributes:
   [CLASS := 'GROUP',
    TITLE := '',
    VERSION := '1.0',
    data_columns := [],
    encoding := None,
    index_cols := [(0, 'index')],
    info := {1: {'type': 'Index', 'names': [None]}, 'index': {}},
    levels := 1,
    nan_rep := 'nan',
    non_index_axes := 
    [(1, ['node_id', 'thread_id', 'handle_id', 'type', 'begin', 'end', 'duration', 'flags', 'unique_id', 'id', 'DSTL_LS_FULL', 'L2_DMISS', 'L3_MISS', 'kernel_type'])],
    pandas_type := 'frame_table',
    pandas_version := '0.10.1',
    table_type := 'appendable_frame',
    values_cols := ['values_block_0', 'values_block_1']]
/df/table (Table(28880943,)) ''
  description := {
  "index": Int64Col(shape=(), dflt=0, pos=0),
  "values_block_0": Int64Col(shape=(10,), dflt=0, pos=1),
  "values_block_1": Float64Col(shape=(4,), dflt=0.0, pos=2)}
  byteorder := 'little'
  chunkshape := (4369,)
  autoindex := True
  colindexes := {
    "index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
  /df/table._v_attrs (AttributeSet), 15 attributes:
   [CLASS := 'TABLE',
    FIELD_0_FILL := 0,
    FIELD_0_NAME := 'index',
    FIELD_1_FILL := 0,
    FIELD_1_NAME := 'values_block_0',
    FIELD_2_FILL := 0.0,
    FIELD_2_NAME := 'values_block_1',
    NROWS := 28880943,
    TITLE := '',
    VERSION := '2.7',
    index_kind := 'integer',
    values_block_0_dtype := 'int64',
    values_block_0_kind := ['node_id', 'thread_id', 'handle_id', 'type', 'begin', 'end', 'duration', 'flags', 'unique_id', 'id'],
    values_block_1_dtype := 'float64',
    values_block_1_kind := ['DSTL_LS_FULL', 'L2_DMISS', 'L3_MISS', 'kernel_type']]

и еще %prun с обновленными модулями и полным набором данных:

%prun -l 25  %time f3(profile.events)
CPU times: user 1min 14s, sys: 16.2 s, total: 1min 30s
Wall time: 1min 48s

        542678 function calls (542650 primitive calls) in 108.678 seconds

   Ordered by: internal time
   List reduced from 629 to 25 due to restriction <25>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      640   23.633    0.037   23.633    0.037 {method '_append' of 'tables.hdf5extension.Array' objects}
       15   20.852    1.390   20.852    1.390 {method '_append_records' of 'tables.tableextension.Table' objects}
      406   19.584    0.048   19.584    0.048 {method '_g_write_slice' of 'tables.hdf5extension.Array' objects}
    14244   10.591    0.001   10.591    0.001 {method '_g_read_slice' of 'tables.hdf5extension.Array' objects}
      458    9.693    0.021    9.693    0.021 {method 'copy' of 'numpy.ndarray' objects}
       15    6.350    0.423   30.989    2.066 pytables.py:3498(write_data_chunk)
       80    3.496    0.044    3.496    0.044 {tables.indexesextension.keysort}
       41    3.335    0.081    3.376    0.082 {method '_fill_col' of 'tables.tableextension.Row' objects}
       20    2.551    0.128    2.551    0.128 {method 'ravel' of 'numpy.ndarray' objects}
      101    2.449    0.024    2.449    0.024 {method 'astype' of 'numpy.ndarray' objects}
       16    1.789    0.112    1.789    0.112 {method '_g_flush' of 'tables.hdf5extension.Leaf' objects}
        2    1.728    0.864    1.728    0.864 common.py:197(_isnull_ndarraylike)
       41    0.586    0.014    0.842    0.021 index.py:637(final_idx32)
    14490    0.292    0.000    0.616    0.000 array.py:368(_interpret_indexing)
        2    0.283    0.142   10.267    5.134 index.py:1158(get_neworder)
      274    0.251    0.001    0.251    0.001 {method 'reduce' of 'numpy.ufunc' objects}
       39    0.174    0.004   19.373    0.497 index.py:1280(reorder_slice)
    57857    0.085    0.000    0.085    0.000 {numpy.core.multiarray.empty}
        1    0.083    0.083   35.657   35.657 pytables.py:3424(write_data)
        1    0.065    0.065   45.338   45.338 pytables.py:3385(write)
    14164    0.065    0.000    7.831    0.001 array.py:615(__getitem__)
    28570    0.062    0.000    0.108    0.000 utils.py:47(is_idx)
       47    0.055    0.001    0.055    0.001 {numpy.core.multiarray.arange}
    28570    0.050    0.000    0.090    0.000 leaf.py:397(_process_range)
    87797    0.048    0.000    0.048    0.000 {isinstance}

2 ответов


Это интересная дискуссия. Я думаю, что Питер получает потрясающую производительность для фиксированного формата, потому что формат пишет в одном кадре, а также что у него действительно хороший SSD (он может писать более 450 МБ/с).

добавление в таблицу является более сложной операцией (набор данных должен быть увеличен, и новые записи должны быть проверены, чтобы мы могли убедиться, что они следуют схеме таблицы). Вот почему добавление строк в таблицы обычно медленнее (но все же, Джефф получает ~ 70 МБ/с, что довольно хорошо). То, что Джефф получает больше скорости, чем Питер, вероятно, связано с тем, что у него лучший процессор.

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


вот аналогичное сравнение, которое я только что сделал. Его около 1/3 строк данных 10M. Окончательный размер abou 1.3 GB

Я определяю 3 функции времени:

Проверьте фиксированный формат (называемый Storer в 0.12). Это пишет в формате массива PyTables

def f(df):
    store = pd.HDFStore('test.h5','w')
    store['df'] = df
    store.close()

запись в формате таблицы, используя формат таблицы PyTables. Не создавайте индекс.

def f2(df):
    store = pd.HDFStore('test.h5','w')
    store.append('df',df,index=False)
    store.close()

то же, что и f2, но создайте индекс (который обычно готово)

def f3(df):
    store = pd.HDFStore('test.h5','w')
    store.append('df',df)
    store.close()

создать рамки

In [25]: df = concat([DataFrame(np.random.randn(10000000,10)),DataFrame(np.random.randint(0,10,size=50000000).reshape(10000000,5))],axis=1)

In [26]: df
Out[26]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 10000000 entries, 0 to 9999999
Columns: 15 entries, 0 to 4
dtypes: float64(10), int64(5)


v0.12.0

In [27]: %timeit f(df)
1 loops, best of 3: 14.7 s per loop

In [28]: %timeit f2(df)
1 loops, best of 3: 32 s per loop

In [29]: %timeit f3(df)
1 loops, best of 3: 40.1 s per loop

master/v0.13.0

In [5]: %timeit f(df)
1 loops, best of 3: 12.9 s per loop

In [6]: %timeit f2(df)
1 loops, best of 3: 17.5 s per loop

In [7]: %timeit f3(df)
1 loops, best of 3: 24.3 s per loop

Timing работает с тем же файлом, что и OP (ссылка ниже)

In [4]: df = pd.read_hdf('test.h5','df')

In [5]: df
Out[5]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 28880943 entries, 0 to 28880942
Columns: 14 entries, node_id to kernel_type
dtypes: float64(4), int64(10)

как f1, фиксированный формат

In [6]: %timeit df.to_hdf('test.hdf','df',mode='w')
1 loops, best of 3: 36.2 s per loop

как f2, формат таблицы, без индекса

In [7]: %timeit df.to_hdf('test.hdf','df',mode='w',format='table',index=False)
1 loops, best of 3: 45 s per loop

In [8]: %timeit df.to_hdf('test.hdf','df',mode='w',format='table',index=False,chunksize=2000000)
1 loops, best of 3: 44.5 s per loop

как f3, формат таблицы с индексом

In [9]: %timeit df.to_hdf('test.hdf','df',mode='w',format='table',chunksize=2000000)
1 loops, best of 3: 1min 36s per loop

как f3, формат таблицы с индексом, сжатый с blosc

In [10]: %timeit df.to_hdf('test.hdf','df',mode='w',format='table',chunksize=2000000,complib='blosc')
1 loops, best of 3: 46.5 s per loop

In [11]: %timeit pd.read_hdf('test.hdf','df')
1 loops, best of 3: 10.8 s per loop

показать исходный файл (тест.H5, и сжатый, тест.hdf)

In [13]: !ls -ltr test.h*
-rw-r--r-- 1 jreback users 3471518282 Nov 20 18:20 test.h5
-rw-rw-r-- 1 jreback users  649327780 Nov 20 21:17 test.hdf

несколько моментов, чтобы отметить.

  • не создание индекса может сделать нетривиальную разницу во времени. Я тоже считаю, что если у вас есть строковый индекс, это может существенно ухудшить время. Тем не менее, вы всегда хотите создать индекс, чтобы сделать поиск очень быстрым.

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

  • штраф за запись в моих примерах примерно 2x (хотя я видел, что он несколько больше, включая время индекса). Таким образом, ваши 7s (1/2 моего времени), для 3x число, которое я пишу, довольно подозрительно. Я использую достаточно быстрый дисковый массив. Если вы использовали флэш-диск на основе, то это возможно, хотя.

  • master / v0.13.0 (выпуск очень скоро), улучшает время записи в таблицах по существу.

  • вы можете попробовать задание chunksize параметр на большее число при записи данных (по умолчанию 100000). Целью "относительно" низкого числа является постоянное использование памяти. (например, если больше, вы будете использовать больше памяти, теоретически она должна писать быстрее).

  • таблицы предлагаем 2 преимущества над фиксированном формате: 1) получение запроса и 2) appendability. Чтение всей таблицы не занимает преимущество любого из них, поэтому, если вы хотите прочитать только всю таблицу, рекомендуется фиксированный формат. (По моему опыту, гибкость таблиц значительно перевешивает штраф за запись, но YMMV)

суть в том, чтобы повторить тайминги (используйте ipython, поскольку он будет запускать несколько тестов). Если вы можете воспроизвести свои результаты, то PLS опубликует %prun, и я посмотрю.

обновление:

таким образом, рекомендуемый способ для таблицы такого размера-сжатие с blosc и используйте pandas master / 0.13.0 вместе с PyTables 3.0.0