Pandas - великолепный инструмент для работы с данными в python, а csv - де-факто стандартный формат хранения данных в Data Science (да и много где еще).

Однако, csv файлы могут занимать ооочень много места. Если Вы сохраняете какие-то промежуточные данные или регулярно делаете выгрузки из СУБД, то и количество этих файлов может быстро расти.

Если Вам приходится часто двигать файлы через сеть между различными окружениями - сервера/рабочая станция/Google Colab/Kaggle, то этот процесс может превратиться в настоящую головную боль. Большие файлы долго передаются по сети, дисковое пространство в сервисах быстро заканчивается и они начинают требовать от Вас апгрейдить аккаунт и расширять лимиты.

Но есть решение, причем удивительно простое и удобное.

Итак, у нас есть относительно большой csv файл.

datascience@docker14 /tmp # ls -la 0.6417826138375177.csv
-rw-r--r-- 1 datascience datascience 226M Dec  5 16:07 0.6417826138375177.csv

Откроем наш файл на 226MB в pandas:

In [3]: import pandas

In [4]: df = pandas.read_csv('0.6417826138375177.csv', index_col=0)

In [5]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 42367 entries, 0 to 42429
Columns: 240 entries
dtypes: bool(4), float64(178), int64(25), object(33)
memory usage: 76.8+ MB

Как видно, данные тут очень разные: много интов, флоатов, есть также строки. Строки бывают как небольшие, так и приличные json объекты на несколько килобайт.

Теперь идем в документацию: pandas.read_csv? (или pandas.DataFrame.to_csv, если хотите) и скроллим вниз

compression : str or dict, default 'infer'
    If str, represents compression mode. If dict, value at 'method' is
    the compression mode. Compression mode may be any of the following
    possible values: {'infer', 'gzip', 'bz2', 'zip', 'xz', None}. If
    compression mode is 'infer' and `path_or_buf` is path-like, then
    detect compression mode from the following extensions: '.gz',
    '.bz2', '.zip' or '.xz'. (otherwise no compression). 

То есть можно на лету сжимать/разжимать csv файлы, и все что нужно - это всего лишь, чтобы файл имел правильное расширение (‘.gz’, ‘.bz2’, ‘.zip’ или ‘.xz’). Даже включать никакой флаг не нужно, это дефолтное поведение.

Пробуем!

In [11]: exts = '', '.gz', '.bz2', '.zip', '.xz'

In [12]: [ df.to_csv(f'test_compression.csv{ext}') for ext in exts ]

Да, на сжатие ушло какое-то время. Смотрим результат:

datascience@docker14 /tmp # ls -lh test_compression.csv*
-rw-r--r-- 1 datascience datascience 223M Dec  6 09:28 test_compression.csv
-rw-r--r-- 1 datascience datascience  38M Dec  6 09:29 test_compression.csv.bz2
-rw-r--r-- 1 datascience datascience  47M Dec  6 09:29 test_compression.csv.gz
-rw-r--r-- 1 datascience datascience  29M Dec  6 09:30 test_compression.csv.xz
-rw-r--r-- 1 datascience datascience  48M Dec  6 09:29 test_compression.csv.zip

Вау! Сжатие в 7.5 раз ! Сколько траффика, времени на скачивание/выкачивание, нервов и дискового пространства можно сэкономить!

Разумеется, открывается так же просто, как и сохраняется:

df = pandas.read_csv('test_compression.csv.xz', index_col=0)

А как же время открытия?

Должен же быть подвох! Может, надо ждать полчаса на каждое открытие? Давайте проверим:

In [5]: %timeit pandas.read_csv('test_compression.csv', index_col=0)
1.58 s ± 2.59 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [6]: %timeit pandas.read_csv('test_compression.csv.bz2', index_col=0)
6.16 s ± 5.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [7]: %timeit pandas.read_csv('test_compression.csv.gz', index_col=0)
2.18 s ± 4.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [8]: %timeit pandas.read_csv('test_compression.csv.xz', index_col=0)
3.14 s ± 6.34 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [9]: %timeit pandas.read_csv('test_compression.csv.zip', index_col=0)
2.16 s ± 3.71 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Ждать полчаса не придется:)

Кажется, нужно просто всегда дописывать .xz к названиям csv файлов, и все будет сразу хорошо. Это лучшая практика.

Что еще почитать?

Доки pandas