Как уменьшить размер служебной информации 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) существенно сокращаются накладные расходы на память. В более реалистичных ситуациях эти накладные расходы станут менее значительными при больших объемах данных. Хранилище фиксированного формата позволяет выполнять быстрые операции чтения / записи, а формат таблицы более гибкий ( подробности см. В документации ). Например,
table
format может обрабатывать смешанные типы данных (для каждого столбца ) лучше, чем фиксированный формат. Посмотрите, например, что произойдет, если вы используете
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, зависит от вашего приложения.