Дата публикации
ai_products

Polars против Pandas: когда пора менять любимую библиотеку для анализа данных

Что нового

Polars — относительно свежий игрок в мире датафреймов, но уже с довольно зрелым набором возможностей:

  • Полная реализация на Rust, без внешних зависимостей. Установка через pip install polars не тянет за собой ни NumPy, ни PyArrow, ни другие библиотеки.
  • Поддержка двух режимов работы:
    • Pandas-like: сразу выполняет операции и возвращает результат.
    • Ленивый режим (Lazy API): сначала строит план вычислений, оптимизирует его, а потом выполняет одной пачкой по команде collect().
  • Опора на формат Apache Arrow: колоночное хранение, совместимость с Arrow-данными, в том числе с операциями без копирования.
  • Потоковый API: можно обрабатывать данные по частям, не загружая весь датасет в память.
  • Автоматическая параллельная обработка: Polars сам распределяет вычисления по ядрам CPU.
  • Векторизованное исполнение запросов.
  • Возможность выполнять запросы на GPU с CUDA (NVIDIA), если инфраструктура это позволяет.
  • Простая конвертация между Pandas и Polars:
    • pl.from_pandas(pandas_df)
    • polars_df.to_pandas()

Автор исходного текста — Senior Data Scientist из Яндекса — подчёркивает, что Polars уже удобно использовать в реальных пайплайнах и при этом он заметно устойчивее к падениям ядра при работе с большими датасетами по сравнению с привычным стеком на Pandas.

Как это работает

Архитектура и формат данных

Polars опирается на колоночное представление данных, совместимое с Apache Arrow:

  • Данные в памяти лежат по столбцам, а не по строкам.
  • Это ускоряет операции по столбцам (агрегации, фильтры, вычисления признаков) и уменьшает объём данных, которые нужно читать из памяти.
  • Polars умеет принимать и отдавать Arrow-данные, часто без копирования.

При этом Polars не использует PyArrow как движок вычислений. Вся работа с памятью и исполнение запросов реализованы внутри Polars на Rust.

Типы данных и объекты

Polars предлагает знакомые по Pandas сущности и добавляет свои:

  • DataFrame — основной табличный объект.
  • Series — столбец данных.
  • LazyFrame — ленивый датафрейм, который хранит не сами данные, а план вычислений.
  • Schema — структура датафрейма: названия столбцов и их типы.

Примеры перехода между форматами:

polars_df = pl.from_pandas(pandas_df)  # Polars DataFrame
pandas_df = polars_df.to_pandas()      # Pandas DataFrame

Переход к ленивому режиму и обратно:

lazy_polars_df = polars_df.lazy()      # LazyFrame
polars_df = lazy_polars_df.collect()   # DataFrame

Проверка схемы:

print(polars_df.schema)
# Schema({'name': String, 'birthdate': Date, 'weight': Float64, 'height': Float64})

Lazy API и оптимизатор запросов

Главная техническая фишка Polars — Lazy API. Когда вы пишете цепочку операций, библиотека не выполняет их по шагам. Она собирает:

  1. План вычислений (LazyFrame).
  2. Прогоняет его через оптимизатор запросов.
  3. Выполняет уже оптимизированный план при вызове collect().

Пример:

q = (
    pl.scan_csv("../data/iris.csv")
    .filter(pl.col("sepal_length") > 5)
    .group_by("species")
    .agg(pl.col("sepal_width").mean())
)

df = q.collect()

Polars позволяет заглянуть внутрь плана и понять, что он собирается делать:

print(q.explain())

Оптимизатор делает несколько важных вещей:

  • Раннее применение фильтров — по возможности уже на этапе чтения файла.
  • Projection pushdown — читает только нужные столбцы с диска.
  • Срез на уровне сканирования — загружает только необходимую часть данных.
  • Оптимизация порядка join-ов — уменьшает пиковое потребление памяти.
  • Автоматическое приведение типов — подбирает совместимые типы с минимальным расходом памяти.

Вместе с параллельным исполнением и векторизацией это даёт серьёзный выигрыш по скорости и устойчивости на больших объёмах данных.

Что это значит для вас

Когда Pandas уже не тянет

Если вы видели в Jupyter надпись Kernel crashed после попытки прочитать или агрегировать большой CSV — вы целевая аудитория Polars.

Polars особенно полезен, когда:

  • Датасеты не помещаются целиком в память или находятся на грани по размеру.
  • Вы строите сложные пайплайны с большим количеством фильтров, join-ов и агрегаций.
  • Нужна максимальная скорость обработки на одном сервере без разворачивания кластера Spark.
  • Важна простая установка без конфликта зависимостей.

Типичные сценарии, где Polars помогает

  • Разведочный анализ данных (EDA) по большим логам, кликам, телеметрии.
  • Подготовка фичей для моделей машинного обучения, когда датасеты уже не игрушечные.
  • Обработка данных из data lake (S3, облачные хранилища, базы данных) с минимальными затратами памяти.
  • Построение аналитических пайплайнов, где важна повторяемость и понятный план выполнения.

Где можно остаться на Pandas

Pandas по‑прежнему удобен, если:

  • Вы работаете с небольшими датасетами, которые уверенно помещаются в память.
  • Важна экосистема вокруг Pandas: специфичные плагины, редкие типы индексов, плотная интеграция с существующим кодом.
  • Команда уже глубоко завязана на Pandas, а переезд на Polars сейчас не окупает время.

Хороший практический подход:

  • Не выбрасывать Pandas, а добавить Polars в стек.
  • Использовать Polars там, где вы уже упёрлись в производительность или память.
  • Спокойно конвертировать датафреймы туда‑обратно, когда нужно использовать сторонние библиотеки только с Pandas.

Ограничения и реалии использования

  • Polars написан на Rust, но для Python-разработчика это прозрачно: API очень похож на Pandas, но местами более декларативный.
  • Для полноценной работы на GPU нужны NVIDIA и CUDA. Без этого Polars будет работать только на CPU — но уже с серьёзным выигрышем за счёт Rust и оптимизатора.
  • Библиотека активно развивается, поэтому иногда меняются детали API. Это плюс по скорости развития, но минус, если нужен «замороженный» интерфейс на годы.

Polars распространяется как обычный Python-пакет. Ограничений по региону использования нет, VPN не нужен.

Место на рынке

Если смотреть на Polars через призму привычных инструментов анализа данных, картинка выглядит так:

  • Pandas — стандарт де-факто для Python-аналитики, с огромной экосистемой и документацией. Но он исторически ориентирован на работу в памяти и не оптимизирован под ленивые вычисления и сложную оптимизацию планов запросов.
  • Polars — альтернатива для тех же задач, но с другим приоритетом: скорость, экономия памяти, параллельность и ленивое исполнение.

Ключевые отличия Polars от Pandas:

  • Реализация на Rust, а не на Python + C.
  • Колонночное хранение и совместимость с Apache Arrow.
  • Lazy API с оптимизатором запросов.
  • Возможность стриминга данных без загрузки всего датасета в память.
  • Автоматическая параллельная обработка без ручной настройки.

Экосистема вокруг Pandas пока шире, но Polars закрывает другой класс проблем: он помогает там, где Pandas начинает тормозить или падать при росте объёма данных.

Установка

Polars ставится одной командой и не требует дополнительных библиотек:

pip install polars

Импорт по соглашению:

import polars as pl

Технически вы можете написать и так:

import polars as pandas

Но это только запутает код и коллег. Логичнее придерживаться import polars as pl.

Как запустить: базовые примеры

Переход между Pandas и Polars

import pandas as pd
import polars as pl

# Pandas DataFrame
pandas_df = pd.DataFrame({
    "name": ["Alice", "Bob"],
    "age": [25, 30]
})

# В Polars
polars_df = pl.from_pandas(pandas_df)  # Polars DataFrame

# Обратно в Pandas
pandas_df_back = polars_df.to_pandas()  # Pandas DataFrame

Lazy API: чтение, фильтрация, агрегация

import polars as pl

q = (
    pl.scan_csv("../data/iris.csv")
    .filter(pl.col("sepal_length") > 5)
    .group_by("species")
    .agg(pl.col("sepal_width").mean())
)

# Выполнить запрос и получить DataFrame
df = q.collect()

# Посмотреть план выполнения и оптимизации
print(q.explain())

Работа со схемой

polars_df = pl.DataFrame({
    "name": ["Alice", "Bob"],
    "birthdate": [
        pl.date(1990, 1, 1),
        pl.date(1985, 6, 15)
    ],
    "weight": [55.5, 80.2],
    "height": [165.0, 180.5]
})

print(polars_df.schema)
# Schema({'name': String, 'birthdate': Date, 'weight': Float64, 'height': Float64})

Итоговый совет

Если вы делаете аналитику или Data Science и уже ловили падения ядра или мучительно ждали, пока Pandas «переварит» большой CSV, имеет смысл поставить Polars и попробовать перенести типичный пайплайн на Lazy API. Порог входа для тех, кто знает Pandas, низкий, а выигрыш по скорости и памяти на больших данных может быть критичным для продуктивной работы.


Читайте также