Pandas & NumPy Academy · Урок

Parquet: быстрое столбцовое хранилище

Записывайте DataFrame Pandas в Parquet с помощью to_parquet(), читайте его быстрее, чем CSV, и используйте выбор столбцов, чтобы загружать только нужные поля.

Урок 4 из 413 шагов

«Parquet: быстрое столбцовое хранилище» — бесплатный урок Pandas & NumPy Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Pandas & NumPy Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Что такое Parquet

Apache Parquet — это двоичный столбцовый формат файла, предназначенный для аналитических задач. В отличие от CSV, который хранит данные построчно в виде текста, Parquet сохраняет каждый столбец в непрерывном блоке, эффективно сжимает его и кодирует метаданные. Поэтому запросы, читающие лишь несколько столбцов широкой таблицы, выполняются значительно быстрее. Parquet — фактически стандартный формат в озёрах данных (AWS S3, Google Cloud Storage); его изначально поддерживают Pandas, Dask, Spark и BigQuery.

Запись Parquet с помощью to_parquet()

Преобразование Pandas DataFrame в Parquet выполняется одним вызовом метода: df.to_parquet('output.parquet'). По умолчанию используется механизм pyarrow (установите его командой pip install pyarrow). Parquet точно сохраняет типы данных столбцов — даты больше не считываются обратно как строки. Формат также изначально поддерживает сжатие с помощью параметра compression; 'snappy' обеспечивает быстрое чтение и запись при умеренном сжатии, а 'gzip' даёт более высокую степень сжатия за счёт скорости.

import pandas as pd
import numpy as np

# Create a sample DataFrame
np.random.seed(0)
df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=100000, freq='T'),
    'value': np.random.randn(100000),
    'category': np.random.choice(['A', 'B', 'C'], 100000)
})

# Write to Parquet
df.to_parquet('data.parquet', index=False, compression='snappy')
print('Written to data.parquet')

Чтение Parquet с помощью read_parquet()

pd.read_parquet('output.parquet') считывает файл обратно в DataFrame. По сравнению с чтением эквивалентного CSV чтение Parquet обычно выполняется в 5–10 раз быстрее для широких таблиц с большим количеством столбцов. Типы данных сохраняются точно: даты остаются datetime64, категории — category, а целые числа — int32 или int64, как было сохранено. Выводить типы данных не требуется, поскольку метаданные встроены в файл.

import pandas as pd
import time

# Read Parquet
start = time.time()
df = pd.read_parquet('data.parquet')
print(f'Read Parquet: {time.time()-start:.3f}s')
print(df.dtypes)
print(df.shape)

Отбор столбцов: чтение только нужных столбцов

Главное преимущество столбцового хранения — отбор столбцов: можно прочитать только определённые столбцы, не сканируя остальную часть файла. Передайте список имён столбцов параметру columns. Если в таблице 100 столбцов и каждый занимает 100 MB, а Вам нужны только 3 столбца, Parquet прочитает 3 MB вместо 10 GB. CSV должен просмотреть каждый символ, чтобы извлечь любой столбец. Поэтому Parquet идеально подходит для широких таблиц в аналитических конвейерах.

import pandas as pd

# Only load the 2 columns needed for this analysis
df = pd.read_parquet('large_table.parquet',
                     columns=['date', 'revenue'])
print(df.columns.tolist())
print(df.shape)
print(df.memory_usage(deep=True).sum() / 1e6, 'MB loaded')

Фильтрация групп строк (проталкивание предикатов)

Parquet хранит статистику (минимальное и максимальное значения) для каждой группы строк (блока строк) в конце файла. Когда Вы применяете фильтр через параметр filters, средство чтения пропускает целые группы строк, в которых фильтр не может найти совпадение. Это называется проталкиванием предикатов. Например, при фильтрации дат в отсортированном по времени файле Parquet пропускаются целые блоки месяцев, не попадающие в диапазон, и читаются только нужные фрагменты. Механизм pyarrow изначально поддерживает эту возможность.

import pandas as pd

# Filter using predicate pushdown — row groups outside range are skipped
df = pd.read_parquet(
    'time_series.parquet',
    columns=['date', 'value'],
    filters=[('date', '>=', '2024-06-01'),
              ('date', '<', '2024-07-01')]
)
print(f'Loaded {len(df):,} rows (June only)')
print(df.head())

Parquet и CSV: сравнение

Ниже приведено практическое сравнение Parquet и CSV для набора данных из 10 миллионов строк и 20 столбцов:

  • Размер файла: CSV — около 2 GB, Parquet (snappy) — около 400 MB
  • Время чтения (все столбцы): CSV — около 15 с, Parquet — около 2 с
  • Время чтения (3 столбца): CSV — около 15 с (необходимо просканировать всё), Parquet — около 0,3 с
  • Сохранение типов данных: CSV теряет типы данных, Parquet сохраняет их
  • Удобочитаемость для человека: CSV — да, Parquet — нет (двоичный формат)

Для производственных конвейеров, где данные записываются один раз, а читаются много раз, Parquet почти всегда является лучшим выбором.

Разделённые наборы данных Parquet

Для очень больших наборов данных Parquet поддерживает разделённые наборы данных: данные распределяются по нескольким файлам, организованным в иерархии каталогов по значениям столбцов. Например, разделение по году и месяцу создаёт путь data/year=2024/month=01/part.parquet. При чтении разделённого набора данных каталоги, соответствующие запросу, фильтруются автоматически. Это стандартная структура для озёр данных, позволяющая эффективно выполнять запросы по диапазонам для миллиардов строк.

import pandas as pd

# Write a partitioned dataset (requires pyarrow)
df = pd.read_parquet('all_data.parquet')
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month

df.to_parquet(
    'partitioned_data/',
    partition_cols=['year', 'month'],
    index=False
)
# Creates: partitioned_data/year=2024/month=1/part-0.parquet etc.

Чтение разделённых наборов данных

Чтение каталога с разделённым Parquet выполняется так же, как чтение одного файла: Pandas (через pyarrow) автоматически обнаруживает все файлы разделов. Значения столбца, по которому выполнено разделение, включаются в результирующий DataFrame как столбцы. Также можно использовать filters для отбора разделов: целые поддеревья каталогов пропускаются на основе значений столбца разделения. Благодаря этому запрос к разделённому набору данных размером 1 TB выполняется почти так же, как чтение нескольких MB.

import pandas as pd

# Read the entire partitioned dataset
df_all = pd.read_parquet('partitioned_data/')
print('All years:', df_all['year'].unique())

# Read only 2024 data using partition pruning
df_2024 = pd.read_parquet(
    'partitioned_data/',
    filters=[('year', '==', 2024)]
)
print('2024 rows:', len(df_2024))

Parquet в Dask

Dask изначально поддерживает чтение и запись Parquet с помощью dd.read_parquet() и ddf.to_parquet(). Каждый файл в каталоге с разделённым Parquet становится одной партицией Dask, что обеспечивает полностью параллельное чтение. Dask также использует проталкивание предикатов, если указаны фильтры. Запись большого результата Dask в разделённый набор данных Parquet — стандартный способ формировать выходные данные в современных инженерных конвейерах данных.

import dask.dataframe as dd

# Read partitioned Parquet with Dask (each file = one partition)
ddf = dd.read_parquet('partitioned_data/',
                      columns=['date', 'revenue', 'region'],
                      filters=[('year', '==', 2024)])

# Compute aggregation in parallel
result = ddf.groupby('region')['revenue'].sum().compute()
print(result.sort_values(ascending=False))

Варианты сжатия и кодирования

Parquet поддерживает несколько алгоритмов сжатия и схем внутреннего кодирования. Snappy (по умолчанию) отдаёт приоритет скорости при умеренном сжатии. Gzip уменьшает размер файлов примерно на 30%, но замедляет чтение и запись. Zstd лучше сочетает скорость и сжатие, чем оба этих варианта. Для целочисленных столбцов Parquet автоматически применяет дельта-кодирование или словарное кодирование, дополнительно уменьшая размер без какой-либо дополнительной настройки.

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({'id': range(500000), 'val': np.random.randn(500000)})

for comp in ['snappy', 'gzip', 'zstd']:
    fname = f'data_{comp}.parquet'
    df.to_parquet(fname, compression=comp, index=False)
    import os
    size_mb = os.path.getsize(fname) / 1e6
    print(f'{comp}: {size_mb:.2f} MB')

Замена CSV в Вашем конвейере

Самый простой способ внедрить Parquet — добавить однократный этап преобразования в начале проекта: один раз прочитать CSV, очистить данные и преобразовать их типы, а затем сохранить результат в Parquet. При всех последующих запусках вместо CSV будет читаться файл Parquet. Это сразу даёт преимущества по скорости и объёму хранилища при минимальных изменениях кода. Для новых данных, поступающих в формате CSV (например, ежедневных экспортов), добавьте в конвейер этап преобразования, который записывает данные в Parquet до начала любого анализа.

import pandas as pd

# One-time conversion
df = pd.read_csv('raw_data.csv',
                 parse_dates=['date'],
                 dtype={'category': 'category',
                        'amount': 'float32'})
df.to_parquet('clean_data.parquet', index=False)

# All future reads use Parquet
df_fast = pd.read_parquet('clean_data.parquet')
print('Loaded from Parquet:', df_fast.dtypes.to_dict())

Быстрая проверка

Проверьте, насколько хорошо Вы усвоили концепции анализа данных из этого урока.

Повторение урока

В этом уроке Вы узнали, что to_parquet() и read_parquet() обеспечивают более быстрый и компактный ввод-вывод файлов с сохранением типов данных по сравнению с CSV, отбор столбцов с параметром columns позволяет читать только нужные столбцы, избегая полного сканирования файла, а разделённые наборы данных Parquet, организованные по значениям столбцов, обеспечивают отбор разделов для эффективных запросов по диапазонам в больших озёрах данных. Далее мы подключим Pandas к реляционным базам данных с помощью SQLAlchemy.

Можно начать бесплатно

Изучай Python с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
30
Уроки
120

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

Урок «Parquet: быстрое столбцовое хранилище» бесплатный?

Да — полный текст урока «Parquet: быстрое столбцовое хранилище» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Pandas & NumPy Academy, подпишись на CoddyKit PRO. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Чему я научусь в уроке «Parquet: быстрое столбцовое хранилище»?

Записывайте DataFrame Pandas в Parquet с помощью to_parquet(), читайте его быстрее, чем CSV, и используйте выбор столбцов, чтобы загружать только нужные поля. Ты практикуешь Pandas & NumPy Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Pandas & NumPy Academy?

Предыдущий опыт не требуется. Pandas & NumPy Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Parquet: быстрое столбцовое хранилище»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Pandas & NumPy Academy?

Да. Каждый урок Pandas & NumPy Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Потоковое чтение CSV с chunksize
  2. Постепенное агрегирование по частям
  3. Введение в Dask DataFrames
  4. Parquet: быстрое столбцовое хранилище
← Назад к Pandas & NumPy Academy