Привет, Хабр!

Меня зовут Вадим Москаленко и я разработчик инновационных технологий Страхового Дома ВСК. В этой статье хочу поделится с вами информацией в области хранения данных.

На сегодняшний день существует огромное количество форматов для хранения данных, и, используя библиотеку Pandas при обработке большого объёма данных, возникает вопрос – а какой формат, с которыми Pandas работает «из коробки», даст наибольшую производительность, при дальнейшем использовании, обработанного DataFrame?

Ремарка: поиск информации по этой теме, привёл меня к репозиторию, за авторством Devforfu (ссылка), но так как информация в нём датируется 2019 годом, а за этот период вышло множество обновлений, я решил написать «свежий» бенчмарк, основываясь на принципах автора – ссылка на обновленный бенчмарк. Отмечу, что из-за слишком большой разницы в полученных результатах, я склоняюсь к тому, что мог совершить ошибку, поэтому далее в статье будет указана информация по оригиналу.

В качестве тестируемых форматов использовались следующие варианты: CSV (как самый популярный текстовый формат), Pickle, Feather, Parquet, Msgpack, HDF. Для сравнения будем использовать следующие метрики: размер сериализованного файла, время загрузки DataFrame из файла, время сохранения DataFrame в файл, потребление оперативной памяти при сохранении и загрузке DataFrame.

Тестовые данные – сгенерированный DataFrame с 1 миллионом строк, 15 столбцами цифр и 15 столбцами строковых значений. Генерация численных данных проводилась с помощью numpy. random.normal, в качестве строчных данных использовались UUID. С появлением в Pandas, категориального типа данных (Categorical data), который использует гораздо меньше памяти и более производительней в обработке (обширный материал для другой статьи), интересно также сравнить насколько изменится производительность форматов, поэтому ещё одним этапом сравнения в тестовых данных стал перевод формата «object» к формату «category».

Бенчмарк

Метрики собирались в течении 20 раундов, после чего группировались в результирующий DataFrame по среднему значению. Посмотрим на результаты:

Формат

RAM, при загрузки файла, Мбайт

Время загрузки, с

RAM, при сохранении файла, Мбайт

Время сохранения, с

Размер файла, Мбайт

csv

385.174219

7.179108

-0.166406

27.588694

771.4420

feather

850.572461

1.333151

635.453125

1.966192

665.0205

hdf

2602.573047

9.296356

1337.336523

8.668205

1644.7400

msgpack

618.167383

3.164023

1231.050391

4.245394

637.7340

parquet

883.852148

0.634647

662.311523

2.439488

129.1415

pickle

1211.571289

2.853154

1543.474805

5.329675

651.4410

Результаты:

  • Лидером по скорости сохранения и загрузки является Parquet, за ним на втором месте Feather, аутсайдером выступил формат CSV.

  • По росту потребления памяти лидирует текстовый формат CVS, хорошая дельта во время загрузки файла у Msgpack, но высокая при сохранении, поэтому второе место занимает Feather, а на третьем месте Parquet.

  • По размеру сериализованного файла, с огромным отрывом побеждает Parquet.


Далее, посмотрим на результаты с категориальным типом данных:

Формат

RAM, при загрузки файла, Мбайт

Время загрузки, с

RAM, при сохранении файла, Мбайт

Время сохранения, с

Размер файла, Мбайт

csv

385.174219

7.179108

-0.166406

27.588694

771.4420

feather

10.669531

0.044231

0.652148

0.179261

130.5660

hdf

327.377148

1.134490

8.731445

0.909780

1269.0565

msgpack

195.321094

0.250950

175.532813

0.332355

128.7790

parquet

920.664258

0.617414

83.697852

1.936816

128.8640

pickle

135.969922

0.118571

198.686523

0.286379

128.7785

Так как CSV, на фоне остальных, сильно проигрывает, приведём график без него, для наглядности.

Результаты:

  • Лидер по скорости изменился и им стал Feather, за ним на втором месте Pickle.

  • По росту потребления памяти также есть изменения: на первом месте feather, второе делят между собой Pickle/Msgpack и аутсайдером при загрузке файла выступил Parquet.

  • По размеру сериализованного файла, у Parquet уже нет безоговорочного лидерства.

Файл или База данных?

Получив данные по форматам, стало интересно сравнение производительности с базами данных (далее по тексту – БД). Тут нужно учесть, что основное преимущество хранения в БД — это конкурентный доступ. В случаях, когда он не требуется, хранение данных в файлах обеспечит более прямой и очевидный доступ.

Такое сравнение, с использованием Microsoft SQL Server, привелось в статье – architecture-performance. Краткая выжимка результатов: по скорости чтения БД отстаёт от файлового хранения, а самым быстрым драйвером является Turbodbc.

Итоги

Так как, в одной из первых строк документации Pickle, указано предупреждение о том, что формат небезопасен, можно выделить двух лидеров бенчмарка: Feather и Parquet.

Тип данных

Object

Category

Формат

feather

parquet

%

feather

parquet

%

Время сохранения, с

1,97 

2,44

24,07%

0,18 

1,94

980,44%

Время загрузки, с

1,33

0,63 

52,39%

0,04 

0,62

1295,89%

Рост потребления памяти при загрузки, Мбайт

850,57 

883,85

3,91%

10,67 

920,66

8528,91%

Рост потребления памяти при сохранении, Мбайт

635,45 

662,31

4,23%

0,65 

83,70

12734,18%

Размер сериализованного файла, Мбайт

665,02

129,14 

80,58%

130,57

128,86 

1,30%

Если в DataFrame не используется категориальный тип данных Pandas, то для долгосрочного хранения больших данных, лучше всего подойдёт формат «Parquet», за счёт минимального размера сериализованного файла. В остальных случаях, формат «Feather» будет самым оптимальным вариантом и позволит с большей скоростью обрабатывать данные, потребляя при этом меньше ресурсов.

Комментарии (13)


  1. 7voprosov
    16.01.2023 12:22

    Классная статья: минимум воды, понятный вывод


    1. V-Moskalenko Автор
      19.01.2023 11:26

      Спасибо, очень приятно, рад что понравилась :)


  1. lea
    16.01.2023 12:37

    Как интерпретировать отрицательное значение расхода памяти при сохранении в csv?


    1. MentalBlood
      16.01.2023 13:02
      +2

      Как околонулевой расход памяти при сохранении в csv + погрешность (сборщик мусора сработал, например)


    1. V-Moskalenko Автор
      19.01.2023 11:32
      +1

      Как верно отметил @MentalBloodтам околонулевой расход текстового формата и погрешность


  1. economist75
    16.01.2023 13:54
    +1

    Полезно. Из "итогов" как-то легко убрали неплохой вариант, который можно встретить у каждого второго датасайентиста. Pickle (со сжатием) все-таки очень близок к parquet и feather по всем параметрам, и эта троица в целом неплоха и во многом равнозначна.

    Единственным заметным минусом pickle назову несовместимость версий для разных сочетаний pandas+python. То есть он плохо пригоден для архивного хранения и редкого обращения. Спустя пару лет старый pkl-файл придется открывать с приключениями.

    Минусы есть и у parquet - не на каждую старую ОС или платформу легко его поставить. Но все проблемы имеют решения, в этом экосистема Python сильна, практически нет тропинок, по которым кто-то не прошел (и не оставил след на stackoverflow).


    1. MentalBlood
      16.01.2023 14:04
      +1

      как-то легко убрали

      ACE это не шутки. Впрочем, можно подписывать получаемый файл (но это замедлит загрузку и выгрузку)


  1. MentalBlood
    16.01.2023 14:04

    del


  1. CrazyElf
    17.01.2023 19:42

    Я наверное лет 5 назад пробовал разные форматы и остановился тогда на feather в плане скорости записи и чтения. Удивительно, что с тех пор особо ничего не поменялось.


  1. davletlinar
    18.01.2023 15:52

    Отличная статья!


    1. V-Moskalenko Автор
      19.01.2023 11:37

      Спасибо, очень приятно! :)


  1. danSamara
    19.01.2023 07:19

    Народ потихоньку переходит на polars. Интересно посмотреть работу с форматами у него.


    1. V-Moskalenko Автор
      19.01.2023 11:52

      Код бенчмарка здесь - ссылка, вы можете попробовать перевести его на Polars, корректировки потребуются в utils.py и main.py. Правда у Polars, не все перечисленные форматы поддерживаются "из коробки".

      Беглым запуском (не ручаюсь за точность) у меня получились такие данные, для Parquet и CSV: