Прикольный трюк: сжатие csv файлов 'на лету' в pandas
Tags: python, beginners, tutorial, linux
Published: 2022-12-06 16:12:18

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

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

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

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



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

```
user@d14 /tmp # ls -la data.csv
-rw-r--r-- 1 datascience datascience 226M Dec  5 16:07 data.csv
```


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

```
import pandas

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

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.pydata.org](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)

> 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'). Даже включать никакой флаг не нужно, **это дефолтное поведение**.

Пробуем!

```
exts = '', '.gz', '.bz2', '.zip', '.xz'

for ext in exts: df.to_csv(f'test_compression.csv{ext}')
```

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

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

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

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

```
df = pandas.read_csv('test_compression.csv.xz', index_col=0)
```
## А как же время открытия?

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

```
%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)

%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)

%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)

%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)

%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 файлов, и все будет сразу хорошо. Это лучшая практика.


Лучший способ не пропустить новые материалы - оформить подписку на [телеграм канал](https://t.me/traceback_ru)!