Pandas apply и векторизация: как писать быстрее и понятнее
Когда использовать apply, почему векторные операции быстрее и как переписать медленный построчный расчёт в pandas.

В pandas почти всегда можно написать расчёт через `apply`, и это удобно для первого прототипа. Но функция, вызываемая для каждой строки, часто становится медленным местом и скрывает типы данных. Векторизация переносит операцию на целый столбец и обычно делает код короче, быстрее и легче для проверки.
Коротко
`apply(axis=1)` — хороший инструмент для сложного правила, которое трудно выразить иначе. Для арифметики, строковых методов, условий и дат сначала ищи операцию над всей Series. `map` и `replace` удобны для словаря значений, `np.select` — для нескольких условий.
- Начни с векторной операции и переходи к apply только при необходимости.
- Не используй `axis=1`, если условие зависит от одной колонки.
- Замеряй время на репрезентативном объёме данных.
- После переписывания сравни результат старой и новой версии на выборке.
Простая арифметика не требует apply
Построчный код выглядит привычно, но pandas уже умеет выполнять операцию над всей колонкой. Векторная версия лучше показывает формулу и не создаёт Python-вызов на каждую строку.
# Медленнее и сложнее читать на больших таблицах
orders['net_revenue'] = orders.apply(
lambda row: row['revenue'] - row['discount'], axis=1
)
# Векторная версия
orders['net_revenue'] = orders['revenue'] - orders['discount']Условия: np.select вместо вложенных if
Когда сегмент зависит от нескольких условий, `np.select` делает порядок правил явным. Условия проверяются сверху вниз, поэтому сначала ставь более специфичное правило. Значение `default` обязательно: иначе неизвестный случай легко потеряется.
import numpy as np
conditions = [
orders['revenue'].ge(5000),
orders['revenue'].ge(1500),
orders['revenue'].ge(0),
]
choices = ['high', 'medium', 'low']
orders['order_segment'] = np.select(conditions, choices, default='invalid')map и str работают над колонкой
Словарь каналов, нормализация регистра и поиск части строки не требуют построчной функции. Такие операции проще покрыть тестами и легче заметить, если неизвестное значение превратилось в пропуск.
channel_names = {'paid_social': 'paid', 'paid_search': 'paid'}
orders['channel_group'] = orders['channel'].map(channel_names)
orders['channel_group'] = orders['channel_group'].fillna('other')
orders['campaign'] = (
orders['campaign'].astype('string').str.strip().str.lower()
)Когда apply оправдан
Если правило использует несколько значений строки, вызывает сложную доменную функцию или строит небольшой текстовый объект, `apply` может быть самым понятным решением. Не нужно переписывать всё ради скорости. Сначала измерь узкое место и зафиксируй ожидаемый результат.
| Задача | Первый кандидат |
|---|---|
| арифметика колонок | векторные операции |
| словарь категорий | map / replace |
| несколько независимых условий | np.select |
| дата и строка | dt / str accessor |
| правило использует всю строку | apply(axis=1), затем замерить |
Векторный код, который никто не понимает, может быть хуже медленного, но проверяемого правила. Сначала сохраняй бизнес-смысл, затем оптимизируй подтверждённое узкое место.
Материалы по теме
Как тестировать аналитические расчёты на Python и pandas
Практический гайд по тестам для аналитика: проверить метрики на маленьком датасете, поймать регрессию и защитить расчёт от тихих изменений.
Читать материал
Как ускорить pandas: память, типы и обработка больших файлов
Что делать, если pandas медленно работает или не помещает файл в память: категории, downcast, chunksize, Parquet и контроль размера данных.
Читать материал
Как загружать Excel, JSON и Parquet в pandas
Практический разбор источников в pandas: прочитать Excel и JSON, выбрать лист, сохранить типы и перейти с CSV на Parquet без сюрпризов.
Читать материал