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

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

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

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

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

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

Мои тесты изначально выполнялись с пандами 0.12, numpy 1.7.1, PyTables 2.4.0 и Numberxpr 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 раз Пока формат Storer напишу.

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

РЕДАКТИРОВАТЬ:

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

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

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

РЕДАКТИРОВАТЬ 3:

@ Предлагаемые Джеффом тесты для меньшего набора данных (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 ГБ с этого диска в память менее чем за 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

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

По запросу Джеффа, 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 ответа

Решение

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

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

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

Вот похожее сравнение, которое я только что сделал. Это около 1/3 строк данных 10M. Окончательный размер - около 1,3 ГБ.

Я определяю 3 функции синхронизации:

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

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 и сжатый, 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

Несколько замечаний.

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

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

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

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

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

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

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

Обновить:

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

Другие вопросы по тегам