Подтвердить что ты не робот

Улучшить pandas (PyTables?) Производительность записи таблицы HDF5

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

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

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

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

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

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

Я могу записать весь набор данных в файл HDF5 формата Storer (итоговый размер файла: 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 гласит, что формат Storer обеспечивает значительно более быструю запись и немного быстрее читает. (У меня есть более быстрое чтение, так как чтение формата Storer, кажется, занимает около 2,5 секунд, в то время как чтение формата таблицы занимает около 10 секунд.) Но действительно кажется чрезмерным, что запись в формате таблицы должна занимать 25 раз, пока сохраняется формат хранилища.

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

EDIT:

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

%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)

ИЗМЕНИТЬ 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 могут плохо взаимодействовать с pandas или PyTables. Ext3 и другие файловые системы, не основанные на экстентах, иногда пытаются быстро развязать большие файлы, и подобная производительность системы (низкое использование ЦП, но длительное время ожидания) очевидна даже во время простого "rm" 1GB файла, например.

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

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

ИЗМЕНИТЬ 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, производительность для моего первоначального набора данных сводится к следующим рисункам. Особый интерес представляет системное время, которое, как я полагаю, является, по крайней мере, верхней границей времени, затрачиваемого на выполнение IO, и настенного времени, что, по-видимому, объясняет эти загадочные периоды отсутствия активности записи/отсутствия ЦП.

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

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

Per Jeff request, 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}
4b9b3361

Ответ 1

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

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

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

Ответ 2

Вот аналогичное сравнение, которое я только что сделал. Его около 1/3 из данных 10M строк. Конечный размер составляет 1,3 ГБ

Я определяю 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

Сроки выполнения с тем же файлом, который предоставляется 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

Показать исходный файл (test.h5 и compress, test.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) пригодность. Чтение всей таблицы также не дает преимуществ, поэтому, если вы ТОЛЬКО хотите прочитать всю таблицу, рекомендуется использовать фиксированный формат. (По моему опыту гибкость таблиц сильно перевешивает штраф за запись, но YMMV)

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

Update:

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