Я работал некоторое время с очень большими DataFrames, и я использовал формат csv для хранения входных данных и результатов. Я заметил, что много времени идет на чтение и запись этих файлов, что, например, резко замедляет пакетную обработку данных. Мне было интересно, действительно ли формат файла имеет значение. Есть ли предпочтительный формат файла для быстрого чтения/записи Pandas DataFrames и/или массивов Numpy?
Самый быстрый формат файла для операций чтения/записи с помощью Pandas и/или Numpy
Ответ 1
Используйте HDF5. Ударяет писать плоские файлы руками вниз. И вы можете запросить. Документы здесь
Здесь сравнение и SQL. Обновлен, чтобы показать SQL/HDF_fixed/HDF_table/CSV записи и чтения перф.
Документы теперь включают раздел производительности:
Смотрите здесь
Ответ 2
Всегда полезно запустить некоторые тесты для вашего варианта использования. У меня были хорошие результаты, хранящие необработанные структуры через numpy:
df.to_records().astype(mytype).tofile('mydata')
df = pd.DataFrame.from_records(np.fromfile('mydata', dtype=mytype))
Это довольно быстро и занимает меньше места на диске. Но: вам нужно будет отслеживать dtype для перезагрузки данных, он не переносится между архитектурами и не поддерживает расширенные функции HDF5. (numpy имеет более продвинутый двоичный формат, который предназначен для преодоления первых двух ограничений, но я не имел большого успеха, чтобы заставить его работать. )
Обновление: Спасибо, что нажимали на цифры. Мой контрольный показатель показывает, что действительно HDF5 выигрывает, по крайней мере, в моем случае. Это быстрее и меньше на диске! Здесь то, что я вижу с dataframe около 280k строк, 7 столбцов float и индекс строки:
In [15]: %timeit df.to_hdf('test_fixed.hdf', 'test', mode='w')
10 loops, best of 3: 172 ms per loop
In [17]: %timeit df.to_records().astype(mytype).tofile('raw_data')
1 loops, best of 3: 283 ms per loop
In [20]: %timeit pd.read_hdf('test_fixed.hdf', 'test')
10 loops, best of 3: 36.9 ms per loop
In [22]: %timeit pd.DataFrame.from_records(np.fromfile('raw_data', dtype=mytype))
10 loops, best of 3: 40.7 ms per loop
In [23]: ls -l raw_data test_fixed.hdf
-rw-r----- 1 altaurog altaurog 18167232 Apr 8 12:42 raw_data
-rw-r----- 1 altaurog altaurog 15537704 Apr 8 12:41 test_fixed.hdf
Ответ 3
HDF действительно очень хороший выбор, вы также можете использовать npy/npz с некоторыми оговорками:
Здесь приведен пример использования кадра данных из 25 тыс. строк и 1000 столбцов, заполненных случайными поплавками:
Saving to HDF took 0.49s
Saving to npy took 0.40s
Loading from HDF took 0.10s
Loading from npy took 0.061s
npy примерно на 20% быстрее писать и примерно на 40% быстрее читать, если вы не сжимаете данные.
Код, используемый для генерации вывода выше:
#!/usr/bin/python3
import pandas as pd
import random
import numpy as np
import time
start = time.time()
f = pd.DataFrame()
for i in range(1000):
f['col_{}'.format(i)] = np.random.rand(25000)
print('Generating data took {}s'.format(time.time() - start))
start = time.time()
f.to_hdf('frame.hdf', 'main', format='fixed')
print('Saving to HDF took {}s'.format(time.time() - start))
start = time.time()
np.savez('frame.npz', f.index, f.values)
print('Saving to npy took {}s'.format(time.time() - start))
start = time.time()
pd.read_hdf('frame.hdf')
print('Loading from HDF took {}s'.format(time.time() - start))
start = time.time()
index, values = np.load('frame.npz')
pd.DataFrame(values, index=index)
print('Loading from npy took {}s'.format(time.time() - start))
Ответ 4
Недавно pandas добавил поддержку формата паркета, используя в качестве бэкенда библиотеку pyarrow
(написанную самим Уэсом Маккинни, с его обычной страстью к производительности).
Вам нужно только установить библиотеку pyarrow
и использовать методы read_parquet
и to_parquet
. Parquet намного быстрее для чтения и записи для больших наборов данных (более нескольких сотен мегабайт или более), а также отслеживает метаданные dtype, поэтому вы не потеряете информацию о типе данных при записи и чтении с диска. На самом деле он может более эффективно хранить некоторые типы данных, с которыми HDF5 не очень эффективен (например, строки и временные метки: HDF5 не имеет собственного типа данных для них, поэтому он использует pickle для их сериализации, что замедляет работу для больших наборов данных).
Паркет также является столбчатым форматом, благодаря которому очень легко сделать две вещи:
Быстро отфильтруйте столбцы, которые вам не интересны. С CSV вы фактически должны прочитать весь файл, и только после этого вы можете выбросить ненужные столбцы. С паркетом вы можете читать только те колонки, которые вам интересны.
Делайте запросы, отфильтровывая строки и читая только то, что вам нужно.
Другой интересной недавней разработкой является формат файла Feather, который также разработан Уэсом Маккинни. По сути, это просто несжатый формат arrow
, записанный непосредственно на диск, поэтому он потенциально быстрее записывается, чем формат Parquet. Недостатком будут файлы, которые в 2-3 раза больше.