Polars — работа с большими данными в Python

22 сентября 2026
Автор

Антон Ларичев

Polars — это библиотека для обработки данных на Python, написанная на Rust. Она значительно быстрее pandas при работе с большими датасетами и поддерживает параллельные вычисления из коробки. В этой статье разберём основные концепции Polars и научимся эффективно применять их на практике.

Почему Polars быстрее pandas

Pandas хранит данные в формате NumPy-массивов и выполняет операции последовательно в один поток. Polars использует:

  • Apache Arrow — колоночный формат хранения данных в памяти
  • Многопоточность — операции выполняются параллельно на всех ядрах процессора
  • Ленивые вычисления (Lazy API) — план запроса оптимизируется перед выполнением
  • Потоковая обработка — данные, не помещающиеся в RAM, обрабатываются по частям

На датасетах от 1 млн строк Polars обгоняет pandas в 5–20 раз в зависимости от типа операции.

Курс по теме

Основы Python — курс

40 000+ студентов · рейтинг 4.8 · гарантия возврата 30 дней

Установка

pip install polars

Для работы с файлами CSV, Parquet, Excel дополнительных зависимостей не нужно — они включены в базовый пакет.

Создание DataFrame

Основная структура данных в Polars — DataFrame. Создать его можно из словаря, списка или внешнего файла.

import polars as pl

# Из словаря
df = pl.DataFrame({
    "name": ["Alice", "Bob", "Charlie", "Diana"],
    "age": [25, 30, 35, 28],
    "salary": [80000, 95000, 110000, 72000],
    "department": ["Engineering", "Marketing", "Engineering", "HR"],
})

print(df)
shape: (4, 4)
┌─────────┬─────┬────────┬─────────────┐
│ name    ┆ age ┆ salary ┆ department  │
│ ---     ┆ --- ┆ ---    ┆ ---         │
│ str     ┆ i64 ┆ i64    ┆ str         │
╞═════════╪═════╪════════╪═════════════╡
│ Alice   ┆ 25  ┆ 80000  ┆ Engineering │
│ Bob     ┆ 30  ┆ 95000  ┆ Marketing   │
│ Charlie ┆ 35  ┆ 110000 ┆ Engineering │
│ Diana   ┆ 28  ┆ 72000  ┆ HR          │
└─────────┴─────┴────────┴─────────────┘

Polars автоматически определяет типы данных. В отличие от pandas, здесь нет типа object — строки всегда имеют тип str, а целые числа — i32, i64 и т.д.

Чтение данных из файлов

# CSV
df = pl.read_csv("data.csv")

# Parquet — рекомендуемый формат для больших данных
df = pl.read_parquet("data.parquet")

# JSON
df = pl.read_json("data.json")

# Excel
df = pl.read_excel("data.xlsx")

Parquet — предпочтительный формат при работе с большими объёмами данных: он сжимает данные и хранит их колоночно, что ускоряет чтение конкретных колонок.

Выражения (Expressions)

Главная концепция Polars — выражения (pl.Expr). Выражение описывает операцию над колонкой, но не выполняет её немедленно. Это позволяет Polars оптимизировать вычисления.

# Выражение — это описание, а не результат
expr = pl.col("salary") * 1.1

# Выражение применяется внутри методов DataFrame
df.with_columns([
    (pl.col("salary") * 1.1).alias("salary_with_raise"),
    (pl.col("age") - 18).alias("years_of_adulthood"),
])

pl.col("name") — обращение к колонке по имени. alias() задаёт имя результирующей колонки.

Фильтрация данных

# Простой фильтр
senior = df.filter(pl.col("age") > 28)

# Несколько условий
engineers = df.filter(
    (pl.col("department") == "Engineering") & (pl.col("salary") > 85000)
)

# Фильтр по списку значений
selected_depts = df.filter(pl.col("department").is_in(["Engineering", "HR"]))

# Исключение null-значений
df_clean = df.filter(pl.col("salary").is_not_null())

Операторы в Polars: & (и), | (или), ~ (не). Использование and/or на уровне выражений не поддерживается — только побитовые операторы.

Выбор и преобразование колонок

# Выбор конкретных колонок
df.select(["name", "salary"])

# Выбор через выражения с преобразованием
df.select([
    pl.col("name").str.to_uppercase(),
    pl.col("salary") / 12,
    pl.col("age").cast(pl.Float64),
])

# Добавление новых колонок
df.with_columns([
    (pl.col("salary") / 12).round(2).alias("monthly_salary"),
    pl.lit("Russia").alias("country"),  # Константа
])

pl.lit() создаёт выражение из литерального значения — константы, которая будет одинакова для всех строк.

Агрегация и группировка

# Группировка с агрегацией
stats = df.group_by("department").agg([
    pl.col("salary").mean().alias("avg_salary"),
    pl.col("salary").max().alias("max_salary"),
    pl.col("salary").min().alias("min_salary"),
    pl.len().alias("count"),
])

print(stats)
shape: (3, 5)
┌─────────────┬────────────┬────────────┬────────────┬───────┐
│ department  ┆ avg_salary ┆ max_salary ┆ min_salary ┆ count │
│ ---         ┆ ---        ┆ ---        ┆ ---        ┆ ---   │
│ str         ┆ f64        ┆ i64        ┆ i64        ┆ u32   │
╞═════════════╪════════════╪════════════╪════════════╪═══════╡
│ Engineering ┆ 95000.0    ┆ 110000     ┆ 80000      ┆ 2     │
│ Marketing   ┆ 95000.0    ┆ 95000      ┆ 95000      ┆ 1     │
│ HR          ┆ 72000.0    ┆ 72000      ┆ 72000      ┆ 1     │
└─────────────┴────────────┴────────────┴────────────┴───────┘
# Группировка по нескольким колонкам
df.group_by(["department", "age"]).agg(
    pl.col("salary").sum().alias("total_salary")
)

Lazy API — ленивые вычисления

Lazy API — ключевая функция Polars для работы с большими данными. Вместо немедленного выполнения каждой операции Polars строит план запроса и оптимизирует его перед выполнением.

# Переключение в ленивый режим
lazy_df = df.lazy()

# Построение плана запроса — вычислений пока нет
result = (
    lazy_df
    .filter(pl.col("age") > 25)
    .with_columns(
        (pl.col("salary") * 1.2).alias("bonus_salary")
    )
    .group_by("department")
    .agg(pl.col("bonus_salary").mean())
    .sort("bonus_salary", descending=True)
)

# Просмотр плана выполнения
result.explain()

# Выполнение запроса
final_df = result.collect()

Polars при вызове collect() оптимизирует план: убирает лишние колонки, переставляет фильтры вверх (predicate pushdown), объединяет операции.

Потоковая обработка для датасетов больше RAM

# Обработка файла по частям без загрузки всего в память
result = (
    pl.scan_csv("huge_file.csv")  # scan вместо read
    .filter(pl.col("value") > 1000)
    .group_by("category")
    .agg(pl.col("value").sum())
    .collect(streaming=True)  # потоковый режим
)

pl.scan_csv() / pl.scan_parquet() — ленивые аналоги read_*. Они не читают файл сразу, а планируют чтение. В сочетании с streaming=True это позволяет обрабатывать файлы размером в сотни гигабайт.

Работа со строками

df = pl.DataFrame({
    "email": ["alice@example.com", "BOB@GMAIL.COM", "charlie@work.org"],
    "full_name": ["Alice Smith", "Bob Jones", "Charlie Brown"],
})

result = df.with_columns([
    pl.col("email").str.to_lowercase().alias("email_lower"),
    pl.col("email").str.split("@").list.get(1).alias("domain"),
    pl.col("full_name").str.split(" ").list.get(0).alias("first_name"),
    pl.col("email").str.contains("gmail").alias("is_gmail"),
    pl.col("full_name").str.len_chars().alias("name_length"),
])

Строковые методы доступны через namespace .str.. Polars поддерживает регулярные выражения через .str.extract(), .str.replace(), .str.contains().

Работа с датами и временем

df = pl.DataFrame({
    "date": ["2024-01-15", "2024-03-22", "2024-07-08"],
    "revenue": [15000, 23000, 31000],
})

result = df.with_columns([
    pl.col("date").str.to_date().alias("parsed_date"),
]).with_columns([
    pl.col("parsed_date").dt.year().alias("year"),
    pl.col("parsed_date").dt.month().alias("month"),
    pl.col("parsed_date").dt.day_of_week().alias("weekday"),
])

# Фильтрация по диапазону дат
from datetime import date

filtered = result.filter(
    pl.col("parsed_date").is_between(date(2024, 1, 1), date(2024, 6, 30))
)

Методы работы с датами доступны через namespace .dt..

Объединение DataFrame (Join)

employees = pl.DataFrame({
    "emp_id": [1, 2, 3, 4],
    "name": ["Alice", "Bob", "Charlie", "Diana"],
    "dept_id": [10, 20, 10, 30],
})

departments = pl.DataFrame({
    "dept_id": [10, 20, 30],
    "dept_name": ["Engineering", "Marketing", "HR"],
    "budget": [500000, 200000, 150000],
})

# Inner join
inner = employees.join(departments, on="dept_id", how="inner")

# Left join
left = employees.join(departments, on="dept_id", how="left")

# Join по разным именам колонок
result = employees.join(
    departments,
    left_on="dept_id",
    right_on="dept_id",
    how="inner"
)

Polars поддерживает все стандартные типы join: inner, left, right, full, cross, semi, anti.

Оконные функции

Оконные функции применяют агрегацию в контексте группы, не схлопывая строки.

df = pl.DataFrame({
    "name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
    "department": ["Eng", "Eng", "Marketing", "Marketing", "Eng"],
    "salary": [80000, 95000, 72000, 68000, 110000],
})

result = df.with_columns([
    pl.col("salary").mean().over("department").alias("dept_avg_salary"),
    pl.col("salary").rank(descending=True).over("department").alias("salary_rank"),
    (pl.col("salary") / pl.col("salary").sum().over("department")).alias("salary_share"),
])

over() — аналог PARTITION BY в SQL. Вычисляет агрегат внутри каждой группы и добавляет его как отдельную колонку.

Производительность: практические советы

Используйте Parquet вместо CSV

# Запись в Parquet
df.write_parquet("data.parquet", compression="zstd")

# Чтение только нужных колонок
df = pl.read_parquet("data.parquet", columns=["name", "salary"])

Parquet сжимает данные колоночно — чтение 2 колонок из 100-колоночного файла читает только 2% данных с диска.

Правильно выбирайте типы данных

# Явное указание типов при чтении CSV
df = pl.read_csv("data.csv", schema={
    "id": pl.UInt32,
    "price": pl.Float32,
    "category": pl.Categorical,  # Строки с малым числом уникальных значений
})

pl.Categorical для строковых колонок с повторяющимися значениями (статусы, категории) — экономит память и ускоряет group_by.

Предпочитайте Lazy API для цепочек операций

# Неэффективно — каждая операция создаёт промежуточный DataFrame
result = df.filter(pl.col("age") > 20)
result = result.with_columns(pl.col("salary") * 1.1)
result = result.group_by("department").agg(pl.col("salary").mean())

# Эффективно — одна оптимизированная операция
result = (
    df.lazy()
    .filter(pl.col("age") > 20)
    .with_columns(pl.col("salary") * 1.1)
    .group_by("department")
    .agg(pl.col("salary").mean())
    .collect()
)

Сравнение с pandas

Задача pandas Polars
Синтаксис фильтра df[df['age'] > 25] df.filter(pl.col('age') > 25)
Новая колонка df['new'] = df['a'] + 1 df.with_columns((pl.col('a') + 1).alias('new'))
Группировка df.groupby('dept').agg({'salary': 'mean'}) df.group_by('dept').agg(pl.col('salary').mean())
Чтение CSV pd.read_csv('f.csv') pl.read_csv('f.csv')
Ленивый режим нет df.lazy() / pl.scan_csv()

Главное отличие — в Polars нет изменения DataFrame на месте. Все операции возвращают новый объект. Это предотвращает ошибки с непредвиденными изменениями данных.

Экспорт данных

# В pandas DataFrame (для совместимости)
pandas_df = df.to_pandas()

# В словарь
data_dict = df.to_dict(as_series=False)

# Запись в файлы
df.write_csv("output.csv")
df.write_parquet("output.parquet")
df.write_json("output.json")
df.write_excel("output.xlsx")

Polars хорошо интегрируется с экосистемой Python: можно конвертировать в pandas для использования с matplotlib, scikit-learn и другими библиотеками.

Итог

Polars — мощный инструмент для обработки данных в Python, который существенно превосходит pandas по скорости на больших датасетах. Ключевые преимущества:

  • Lazy API оптимизирует план выполнения и позволяет работать с данными, не помещающимися в RAM
  • Многопоточность задействует все ядра процессора автоматически
  • Выражения — единый декларативный способ описания любых трансформаций
  • Строгая типизация предотвращает ошибки и ускоряет вычисления

Для новых проектов с объёмами данных от нескольких миллионов строк Polars — выбор по умолчанию. Для небольших датасетов (до 100k строк) разница незначительна и выбор между pandas и Polars — вопрос привычки.

Чтобы глубже освоить Python и научиться работать с данными профессионально, пройдите курс на PurpleSchool: https://purpleschool.ru/course/python?utm_source=knowledgebase&utm_medium=text&utm_campaign=polars-big-data

Стрелочка влевоPython collections — Counter, defaultdict, OrderedDictNamedTuple в PythonСтрелочка вправо

Постройте личный план изучения Python до уровня Middle — бесплатно!

Python — часть карты развития Backend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Все гайды по Python

Как отправлять запросы с помощью requests в PythonПочему Python выводит значение без команды printКак работает команда print в PythonВозможности Python для автоматизации задачРабота с JSON в Python на примерахPython get — методы получения данныхКак находить и исправлять ошибки в PythonРабота с данными через API и внешние сервисыСтруктура и оформление кода PythonОсновы Django с PythonПолезные приёмы в Python для повседневной работыИспользование locals в Python для отладкиИнтеграция PHP и PythonКак выполнять HTTPS-запросы в PythonFastAPI Python — быстрый старт: создание REST API с нуляКак работать с API в Python
Ввод целого числа в PythonВедение логов в PythonУдаление данных в Python с помощью removeОбработка исключений с помощью try/except в PythonФункция super() в Python — как вызвать метод родителяСоздание собственных контекстных менеджеров в PythonРабота с переменной X в PythonРабота с символами программирования PythonРабота с классами в PythonКак скачать Python на компьютерПростая программа на Python для начинающихОсновы Python для тех, кто начинаетЧто нового в Python 3Поддерживается ли Python 2 и стоит ли его использоватьPython 1 — с чего начиналась история языкаКоманда python print - полное руководство по выводу данныхПравила именования переменных в PythonПользовательские исключения в PythonОсновы Python coreОписание объектов PythonНаследование классов в Python — основы и примерыМножественное наследование в Python — примеры и MROКонтекстный менеджер with в Python — как работает и зачем нуженКомментарии в Python — однострочные, многострочные и docstringКакой Python выбрать для установкиКак вывести целое число с помощью print в PythonКак установить Python на Windows macOS и LinuxКак пользоваться консолью PythonКак получить последний элемент в PythonКак найти значение в PythonКак настроить PythonКак использовать print для строк в PythonКак работает интерпретатор PythonИнструкция по работе с PythonБлок finally в обработке исключений PythonЦелые числа в PythonАбстрактные классы в Python — ABC и abstractmethod
Загрузка данных PythonУправление проектами на GitHub с PythonСоздание веб-приложений на Flask PythonСоздание бота на PythonСоздание интерфейсов Python QTСоздание игр с PygameСоздание GUI в PythonКак работать со словарями в PythonРабота с библиотеками через Python PackagingРабота со временем в Python при помощи модуля timePython name — особенности переменнойМатематические операции в Python с модулем mathPython listing — что это и как использоватьPytest — тестирование на Python: полное руководствоОбработка изображений с OpenCV PythonNumPy в Python — основы и применение в задачахМашинное обучение с PythonИспользование Anaconda с PythonМодуль contextlib в Python — утилиты для контекстных менеджеровБиблиотеки Python и их применение в проектах
Возврат значений из функции в PythonВложенные функции в PythonСоздание собственных декораторов в PythonЦикл while в Python и примеры использованияРабота с функцией map в PythonОбработка чисел, введённых через input в PythonОсновные операторы в Python с примерамиУсловные выражения if else в Python для начинающихКак выполняется вызов функций call в PythonПродвинутые генераторы в Python — send, throw, close и корутиныПозиционные и именованные аргументы в PythonОбъявление переменных и управление областью видимости в PythonПередача аргументов по ссылке и по значению в PythonПередача аргументов через args и kwargs в PythonОсновные методы Python и примеры их использованияОператор match/case в Python 3.10+ — основы структурного сопоставленияПаттерны match/case в Python — деструктуризация, guard и вложенные шаблоныПрактические примеры match/case в Python — реальные сценарии примененияЛокальные и глобальные переменные в PythonЧасто используемые команды PythonКлючевые слова global и nonlocal в PythonКак создавать функции в PythonКак работает сборщик мусора в PythonКак работает область видимости переменных в PythonКак работает функция callable в PythonКак работает функция any и all в PythonКак проверить тип переменной в PythonКак передать функцию как аргумент в PythonКак использовать функцию isinstance в PythonКак использовать функцию filter в PythonКак использовать функцию filter в PythonКак использовать функцию eval безопасно в PythonКак использовать декораторы в PythonИзменяемые и неизменяемые типы данных в PythonГенераторы и yield в Python — как создавать и использоватьГенераторные выражения в Python — синтаксис и примерыФункции в Python и способы их вызоваФункции как объекты в PythonЧто такое замыкания в PythonЧто делает функция reduce в PythonЧто делает функция id в PythonАргументы по умолчанию в PythonАнонимные функции и lambda в PythonАлгоритмы на Python — примеры и объяснение
Запись данных в PythonУстановка pip в PythonУправление зависимостями requirement в PythonУправление библиотеками с помощью Python PackagingУдаление пробелов с помощью strip в PythonСтруктурирование кода в PythonСоздание исполняемого файла Python в exeРазбор traceback в модуле PythonРазбор site-packages в PythonРазбор Program Files в PythonРабота с Unicode кодировками в PythonРабота с системными функциями Python sysРабота с папкой AppData в PythonРабота с модулем logging в PythonРабота с каталогами в PythonРабота с CSV в PythonВиртуальная среда venv в Python — создание и настройкаКак создать простое приложение на PythonИспользование pip в Python для установки пакетовМодули в Python и организация кода в проектеИмпорт модулей в Python и правила подключенияРабота с файлами в Python пошаговоЧто делает компилятор Python и как он работаетПолучение строки из модуля PythonПодключение файлов в Python с includeПеременные среды в PythonСборка проекта с помощью packaging в PythonНастройка Python сервераИспользование Python на UbuntuИспользование консоли PythonИспользование кодировок в PythonИнициализация пакетов PythonИмпорт модулей PythonИмпорт имен в PythonСреда IDLE Python и базовые возможностиЧтение и запись TXT в PythonЧтение файлов в Python с помощью open file
Удаление элементов из списка PythonТипы данных в Python — обзор и рекомендацииОсновные операции со строками в PythonМетоды str в Python и обработка текстаСписки в Python и их ключевые методыСоздание списков данных в PythonРабота со строками и символами в PythonРабота со столбцами в PythonРабота со списком значений в PythonРабота с таблицами в Python с помощью DataFrameРабота с RFR в PythonРабота с пробелами в PythonРабота с кортежами tuple PythonРабота с массивами в PythonРабота с координатами X и Y в PythonРабота с ключами в PythonРабота с элементами данных PythonРабота с двоичными числами PythonРабота с данными в PythonРабота с данными NumPy PythonРабота с большими числами в PythonРабота с битами в PythonРабота с байтами в PythonЧто такое значение в Python и как его определитьМножества в Python и операции с нимиИспользование range в Python для цикловПроверка на четность в PythonПроверка числа в PythonПреобразование типов в PythonПреобразование списка в строку PythonПреобразование числа в строку в PythonПостроение графиков в PythonОпределение индекса элемента в PythonОкругление чисел в PythonОбъединение списков в Python с помощью zipМножества в PythonМассивы в Python и отличие от списковМассив чисел в PythonКортежи данных в PythonКак вычислить сумму чисел в PythonКак получить остаток от деления в PythonКак найти следующее число в PythonИспользование Unicode в PythonТип int в Python и его особенностиИндекс списка в PythonФункции для работы со строками в PythonЭлементы Python и способы доступа к нимДоступ к элементам массива в PythonДеление чисел в PythonРабота с данными в Python на практикеКак работать с числами в Python
Открыть базу знаний

Лучшие курсы по теме

Иконка молнииНовый
изображение курса

Основы Python

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий