pivot_table в Pandas: шпаргалка
Зачем аналитику pivot_table
pivot_table — pandas-аналог Excel сводной таблицы. Превращает длинные (long) данные в широкие (wide) для анализа и визуализации.
Базовый синтаксис
df.pivot_table(
index='строка',
columns='столбец',
values='значение',
aggfunc='mean', # или 'sum', 'count', ...
fill_value=0 # чем заполнить NaN
)Пример
import pandas as pd
df = pd.DataFrame({
'city': ['M', 'SPb', 'M', 'SPb', 'M'],
'month': ['Apr', 'Apr', 'May', 'May', 'Apr'],
'revenue': [100, 50, 200, 80, 150]
})
df.pivot_table(index='city', columns='month', values='revenue', aggfunc='sum')
# Apr May
# city
# M 250 200
# SPb 50 80pivot vs pivot_table
| Метод | Агрегация | Дубликаты ключей |
|---|---|---|
pivot |
❌ нет | ошибка |
pivot_table |
✅ есть (aggfunc) | агрегирует |
pivot_table — универсальный выбор.
# pivot — только reshape, без агрегации
df.pivot(index='city', columns='month', values='revenue')
# pivot_table — универсальный
df.pivot_table(index='city', columns='month', values='revenue', aggfunc='sum')Попробовать силы на подобных вопросах проще всего в тренажёре Карьерник — прямо в Telegram, без регистрации через сайт.
aggfunc — разные агрегаты
# Несколько агрегатов на одном поле
df.pivot_table(index='city', columns='month', values='revenue',
aggfunc=['sum', 'mean', 'count'])
# Разные агрегаты для разных полей
df.pivot_table(index='city', columns='month',
values=['revenue', 'users'],
aggfunc={'revenue': 'sum', 'users': 'nunique'})Multi-index
В index
df.pivot_table(index=['city', 'device'], columns='month', values='revenue')Результат имеет двойной индекс (city, device).
В columns
df.pivot_table(index='city', columns=['month', 'device'], values='revenue')Двухуровневые столбцы.
fill_value и margins
df.pivot_table(index='city', columns='month', values='revenue',
aggfunc='sum',
fill_value=0, # NaN → 0
margins=True, # добавить итоги
margins_name='Total')Итоги по строкам и столбцам — как в Excel.
crosstab — частный случай
Если не хотите агрегировать произвольные значения, а нужны просто counts:
pd.crosstab(df['city'], df['month'])
# Количество записей в каждой комбинации
# С процентами
pd.crosstab(df['city'], df['month'], normalize='index') * 100crosstab проще, чем pivot_table с aggfunc='count'.
Melt — обратный pivot
Превратить wide обратно в long:
wide = df.pivot_table(index='city', columns='month', values='revenue')
long = wide.reset_index().melt(id_vars='city', value_name='revenue')
# Возвращает к исходной структуреПройти 30–50 задач по теме за вечер можно в Telegram-тренажёре. Это то, что отличает «знаю» от «уверенно отвечу на собесе».
Типичные задачи
1. Heatmap по месяцам и категориям
pivot = df.pivot_table(index='category', columns='month',
values='revenue', aggfunc='sum', fill_value=0)
import seaborn as sns
sns.heatmap(pivot, annot=True, fmt='.0f')2. Когортная таблица retention
df['cohort'] = df.groupby('user_id')['date'].transform('min').dt.to_period('M')
df['period'] = df['date'].dt.to_period('M')
df['period_num'] = (df['period'] - df['cohort']).apply(lambda x: x.n)
retention = df.pivot_table(
index='cohort', columns='period_num',
values='user_id', aggfunc='nunique', fill_value=0
)
retention = retention.divide(retention[0], axis=0)3. Сравнение по сегментам
df.pivot_table(
index='channel', columns='segment', values='conversion', aggfunc='mean'
)4. Топ-5 категорий по продажам в каждом месяце
pivot = df.pivot_table(index='category', columns='month',
values='revenue', aggfunc='sum')
for month in pivot.columns:
print(pivot[month].sort_values(ascending=False).head(5))5. Подсчёт уникальных пользователей по дням недели и гео
pd.crosstab(df['day_of_week'], df['country'],
values=df['user_id'], aggfunc='nunique')6. Среднее и медиана одновременно
df.pivot_table(index='city', values='amount',
aggfunc=['mean', 'median', 'std'])7. Доля каждой категории
# Через crosstab с normalize
pd.crosstab(df['city'], df['category'], normalize='index') * 1008. Сохранить NaN вместо fill
df.pivot_table(index='city', columns='month', values='revenue')
# Оставит NaN там, где нет данных — полезно для визуализации9. Несколько values и aggregate разные
df.pivot_table(
index='city',
values=['revenue', 'orders', 'users'],
aggfunc={'revenue': 'sum', 'orders': 'count', 'users': 'nunique'}
)10. Reset index для export в BI
pivot.reset_index().to_csv('pivot.csv', index=False)10 вопросов с собесов
1. Чем pivot отличается от pivot_table?
pivot — только reshape, без агрегации (ошибка при дубликатах). pivot_table — с aggfunc, работает всегда.
2. Как заменить NaN в pivot на 0?
fill_value=0 в аргументах.
3. Что такое margins?
Добавляет строку/столбец с итогами (sum/mean/... в зависимости от aggfunc).
4. crosstab vs pivot_table?
crosstab — удобный wrapper над pivot_table для счётчиков и нормализации.
5. Как сделать пивот с несколькими агрегатами?
aggfunc=['sum', 'mean', 'count'] — список функций.
6. Какой aggfunc по умолчанию?
mean.
7. Multi-index в pivot?
Да — index=['a', 'b'] или columns=['c', 'd'].
8. Как превратить wide обратно в long?
Через melt().
9. pivot_table на 10M строк тормозит?
Нормально. Для таких объёмов лучше SQL-агрегация + pivot на результате.
10. Как визуализировать пивот?
heatmap из seaborn / plotly — стандарт для матричных данных.
Как тренироваться
pivot_table — must-have для аналитика. На Kaggle-датасетах постройте 3-4 пивот-таблицы разных типов.
Совет: на собесе, когда просят «построить когортную таблицу» — сразу думайте pivot_table + unstack + divide. Это стандартный паттерн.
Читайте также
FAQ
pivot_table или groupby + unstack?
Функционально эквивалентно. pivot_table читабельнее для простых случаев. groupby+unstack гибче для сложных.
Что быстрее?
На больших данных — groupby обычно. Но разница незаметна на <100k строк.
Можно ли в pivot использовать функцию?
Да: aggfunc=lambda x: x.quantile(0.9) или любая функция, возвращающая скаляр.
Multi-index тяжело читается — что делать?
reset_index() или .unstack(level=) чтобы развернуть нужный уровень в столбцы.