Как уменьшить размер служебной информации HDFStore?

Я экспериментирую с различными схемами хранения данных для тиков. До сих пор самым быстрым (с точки зрения чтения и записи) было использование хранилища HDFS с blosc-сжатием и "фиксированным" форматом.

store = pd.HDFStore(path, complevel=9, complib='blosc')
store.put(symbol, df)
store.close()

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

Есть ли способ сохранить преимущества производительности в формате blosc/fixed, но уменьшить размер? Я пробовал формат "таблицы", который требует около 285 КБ на символ.

store.append(symbol, df, data_columns=True)

Однако этот формат значительно медленнее для чтения и записи.

Если это помогает, вот как выглядит мой фрейм данных:

exchtime     datetime64[ns]
localtime    datetime64[ns]
symbol               object
country               int64
exch                 object
currency              int64
indicator             int64
bid                 float64
bidsize               int64
bidexch              object
ask                 float64
asksize               int64
askexch              object

Сжатие Blosc само по себе работает довольно хорошо, так как в результате .h5 файл требует только 30--35 байт на строку. Поэтому сейчас моя главная задача - уменьшить размер штрафа за узел в HDFStore.

2 ответа

Решение

AFAIK существует определенный минимум для размера блока в PyTables.

Вот некоторые предложения:

  • Вы можете ptrepack файл, используя опцию chunkshape='auto', Это позволит упаковать его, используя chunkshape, который рассчитывается на основе просмотра всех данных, и может упаковать данные в более эффективный размер блока, что приведет к уменьшению размера файла. Причина в том, что PyTables необходимо информировать об ожидаемом количестве строк в окончательном размере массива / таблицы.

  • Вы можете достичь оптимального размера в Table форматирование путем передачи expectedrows= (и только делает одно добавление). Тем не мение, ptrepacking будет все еще иметь выгоду здесь.

  • Вы также можете попробовать писать в формате таблицы, вместо того, чтобы устанавливать все data_columns=Trueпросто пройти format='table'; он запишет формат таблицы (но вы не сможете делать запросы, кроме как по индексу); но он хранится как один блок и поэтому должен быть почти таким же быстрым, как исправлено (но несколько более экономно)

  • В PyTables 3.1 (только что выпущен), есть новый blosc фильтр. Что может уменьшить размеры файлов. Смотрите здесь

Это дополняет предыдущий ответ некоторыми примерами и пояснениями. Для моей версии Pandas (1.2.3) и PyTables (3.6.1) я вижу следующее поведение при записи в хранилище HDF:

      import pandas as pd
df = pd.DataFrame([[1, "a"], [2, "b"], [3, "c"]])

# Create a store with fixed format: creates considerable memory overhead!
# File size store1.h5: 1.1MB
store = pd.HDFStore("store1.h5")
store.put(key="some/key", value=df, format="fixed")
store.close()

# Better: create a store with table format.
# File size store1.h5: 86kB!
store = pd.HDFStore("store2.h5")
store.put(key="some/key", value=df, format="table")
store.close()

Примечание . Вместо использования магазина используйте напрямую DataFrame.to_hdf():

      df = pd.DataFrame([[1, "a"], [2, "b"], [3, "c"]])
df.to_hdf("store1.h5", key="some/key", format="fixed")
df.to_hdf("store2.h5", key="some/key", format="table")

В этом примере при втором подходе (store2.h5) существенно сокращаются накладные расходы на память. В более реалистичных ситуациях эти накладные расходы станут менее значительными при больших объемах данных. Хранилище фиксированного формата позволяет выполнять быстрые операции чтения / записи, а формат таблицы более гибкий ( подробности см. В документации ). Например, tableformat может обрабатывать смешанные типы данных (для каждого столбца ) лучше, чем фиксированный формат. Посмотрите, например, что произойдет, если вы используете df.T.to_hdf(...)в приведенных выше примерах. Фиксированный формат выдаст следующее предупреждение о производительности (см. Этот пост по SO или этой проблеме с пандами), в то время как формат таблицы работает нормально.

      PerformanceWarning: your performance may suffer as PyTables will pickle 
object types that it cannot map directly to c-types

ptrepack- это утилита командной строки, которая поставляется с PyTables (пакет называется tables). Чтобы увидеть текущую версию PyTables: python -m pip show tables.

Используя ptrepack, я могу еще больше уменьшить размеры файлов для своих фиктивных примеров, применив некоторое сжатие. (Используя опцию --chunkshape=auto не дало заметного эффекта.)

      # store1.repack.h5: 1.1MB -> 22kB
ptrepack --complevel=9 --complib=blosc "store1.h5" "store1.repack.h5"
# store2.repack.h5: 86kB -> 9kB
ptrepack --complevel=9 --complib=blosc "store2.h5" "store2.repack.h5"

Таким образом, сохранение фрейма данных в табличном формате и переупаковка полученного хранилища со сжатием позволяет уменьшить объем памяти, занимаемый хранилищем. Разумно ли минимизировать накладные расходы на хранилище хранилища HDF, зависит от вашего приложения.

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