Pandas: чтение файлов Parquet / Feather

Parquet и Feather — это два эффективных колоночных формата хранения данных, предназначенных для анализа больших данных и сценариев быстрого чтения/записи. По сравнению с CSV они обеспечивают лучший коэффициент сжатия и производительность запросов.


Почему стоит использовать Parquet и Feather

Основные преимущества колоночных форматов хранения:

Характеристика CSV Parquet Feather
Формат хранения Строчный Колоночный Колоночный
Скорость чтения Медленная Очень быстро Чрезвычайно быстро
Скорость записи Средняя Высокая Чрезвычайно быстро
Коэффициент сжатия Низкая Высокая Средняя
Кроссязыковая поддержка Общие Java/Python/R Python/R

Parquet — это проект Apache Foundation, широко используемый в экосистеме больших данных (Hadoop, Spark, DuckDB и т. д.). Feather — это нативная реализация проекта Arrow, ориентированная на максимальную скорость чтения/записи.


Операции с файлами Parquet

Установка зависимостей

pip install pyarrow fastparquet

PyArrow и FastParquet — это реализации Parquet на Python. PyArrow используется по умолчанию, а FastParquet быстрее в некоторых сценариях.

Чтение файлов Parquet

Пример

import pandas as pd

# Чтение файла Parquet (по умолчанию используется pyarrow)
df = pd.read_parquet("data.parquet")

# Указать конкретный движок
df = pd.read_parquet("data.parquet", engine="pyarrow")
df = pd.read_parquet("data.parquet", engine="fastparquet")

# Чтение удалённого файла Parquet
df = pd.read_parquet("s3://bucket/data.parquet")

# Чтение определённых столбцов файла (прореживание столбцов, повышает производительность)
df = pd.read_parquet("data.parquet", columns=["name", "age", "city"])
print(df.head())

Запись файлов Parquet

Пример

import pandas as pd

# Подготовка тестовых данных
df = pd.DataFrame({
    "id": range(1, 10001),
    "name": ["User" + str(i) for i in range(1, 10001)],
    "age": [20, 25, 30, 35] * 2500,
    "city": ["Beijing", "Shanghai", "Guangzhou", "Шэньчжэнь"] * 2500,
    "score": [round(i * 0.1, 2) for i in range(1, 10001)]
})

# Запись файла Parquet (по умолчанию используется движок pyarrow)
df.to_parquet("data.parquet", index=False)

# Укажите метод сжатия (snappy — быстрый, gzip — высокая степень сжатия)
df.to_parquet("data_snappy.parquet", compression="snappy", index=False)
df.to_parquet("data_gzip.parquet", compression="gzip", index=False)
df.to_parquet("data_none.parquet", compression=None, index=False)  # Без сжатия

# Просмотр размера файла
import os
print("Сравнение размера файлов:")
print(f"Примерный размер исходного CSV: {len(df) * 50 / 1024 / 1024:.2f} MB")
print(f"сжатие snappy: {os.path.getsize('data_snappy.parquet') / 1024 / 1024:.2f} MB")
print(f"сжатие gzip: {os.path.getsize('data_gzip.parquet') / 1024 / 1024:.2f} MB")
print(f"Без сжатия: {os.path.getsize('data_none.parquet') / 1024 / 1024:.2f} MB")

Использование движка FastParquet

Пример

import pandas as pd
import time

# Тест производительности записи разных движков
df = pd.DataFrame({
    "id": range(1, 100001),
    "value": range(1, 100001)
})

# Запись с помощью движка pyarrow
start = time.time()
df.to_parquet("test_pyarrow.parquet", engine="pyarrow", compression="snappy")
print(f"время записи pyarrow: {time.time() - start:.3f}s")

# запись с использованием движка fastparquet
start = time.time()
df.to_parquet("test_fastparquet.parquet", engine="fastparquet", compression="snappy")
print(f"время записи fastparquet: {time.time() - start:.3f}s")

Операции с файлами Feather

Feather — это Python-реализация проекта Arrow, ориентированная на максимальную скорость чтения/записи в памяти.

Установка зависимостей

pip install pyarrow

Чтение файлов Feather

Пример

import pandas as pd

# Чтение файла Feather
df = pd.read_feather("data.feather")

# Чтение версии v2 файла Feather (более универсальной)
df = pd.read_feather("data.feather", version="2.0")

# Чтение определённых столбцов
df = pd.read_feather("data.feather", columns=["name", "age"])
print(df.head())

Запись файлов Feather

Пример

import pandas as pd

# Подготовка тестовых данных
df = pd.DataFrame({
    "id": range(1, 10001),
    "name": ["User" + str(i) for i in range(1, 10001)],
    "value": [round(i * 0.1, 2) for i in range(1, 10001)]
})

# Запись файла Feather
df.to_feather("data.feather")

# Сжатие LZ4 (быстрее)
df.to_feather("data_lz4.feather", compression="lz4")

# Сжатие ZSTD (более высокий коэффициент сжатия)
df.to_feather("data_zstd.feather", compression="zstd")

# Просмотр размера файла
import os
print(f"Без сжатия: {os.path.getsize('data.feather') / 1024:.2f} KB")
print(f"LZ4: {os.path.getsize('data_lz4.feather') / 1024:.2f} KB")
print(f"ZSTD: {os.path.getsize('data_zstd.feather') / 1024:.2f} KB")

Тест сравнения производительности

Пример

import pandas as pd
import numpy as np
import time
import os
import tempfile

# Создание тестовых данных
np.random.seed(42)
n_rows = 1000000
df = pd.DataFrame({
    "id": range(n_rows),
    "category": np.random.choice(["A", "B", "C", "D"], n_rows),
    "value": np.random.randn(n_rows),
    "flag": np.random.choice([True, False], n_rows),
    "date": pd.date_range("2020-01-01", periods=n_rows, freq="1min")
})

# Создание временного каталога
with tempfile.TemporaryDirectory() as tmpdir:
    # Запись CSV
    start = time.time()
    df.to_csv(f"{tmpdir}/data.csv", index=False)
    csv_write = time.time() - start

    start = time.time()
    df_csv = pd.read_csv(f"{tmpdir}/data.csv")
    csv_read = time.time() - start

    # Запись Parquet
    start = time.time()
    df.to_parquet(f"{tmpdir}/data.parquet", index=False)
    pq_write = time.time() - start

    start = time.time()
    df_pq = pd.read_parquet(f"{tmpdir}/data.parquet")
    pq_read = time.time() - start

    # Запись Feather
    start = time.time()
    df.to_feather(f"{tmpdir}/data.feather")
    feather_write = time.time() - start

    start = time.time()
    df_feather = pd.read_feather(f"{tmpdir}/data.feather")
    feather_read = time.time() - start

    # Вывод результатов
    print(f"{'Формат':<10} {'Время записи':<12} {'Время чтения':<12} {'Размер файла':<12}")
    print("-" * 50)
    print(f"{'CSV':<10} {csv_write:.3f}s{'':<5} {csv_read:.3f}s{'':<5} {os.path.getsize(f'{tmpdir}/data.csv')/1024/1024:.2f}MB")
    print(f"{'Parquet':<10} {pq_write:.3f}s{'':<5} {pq_read:.3f}s{'':<5} {os.path.getsize(f'{tmpdir}/data.parquet')/1024/1024:.2f}MB")
    print(f"{'Feather':<10} {feather_write:.3f}s{'':<5} {feather_read:.3f}s{'':<5} {os.path.getsize(f'{tmpdir}/data.feather')/1024/1024:.2f}MB")

Сценарии использования и рекомендации по выбору

Сценарий Рекомендуемый формат Причина
Анализ больших данных Parquet Высокая степень сжатия, быстрые колоночные запросы, широкая экосистема
Передача данных Python/R Feather Чрезвычайно быстрое чтение/запись, нативная поддержка Arrow
Интеграция со Spark/Hadoop Parquet Стандартный формат в экосистеме больших данных
Резервное копирование/архивирование данных Parquet Высокая степень сжатия, поддерживает эволюцию схемы
Кэш временных данных Feather Самое быстрое чтение/запись

Часто задаваемые вопросы

1. Ошибка чтения Parquet

Убедитесь, что установлен pyarrow или fastparquet:pip install pyarrow

2. Повреждение файла

При записи убедитесь, что данные полностью записаны на диск. После записи рекомендуется проверить, что файл читается.

3. Совместимость версий

Разные версии Parquet могут иметь проблемы совместимости. Рекомендуется использовать фиксированную версию в вашем проекте.

Другие расширения