pivot_table в Pandas — полный гайд с примерами
Коротко
pivot_table — аналог сводной таблицы из Excel в pandas. Берёт «длинные» данные и разворачивает их в таблицу, где строки и столбцы — категории, а значения — агрегаты. На собеседованиях аналитиков встречается в задачах на трансформацию данных и часто идёт в паре с groupby.
Базовый синтаксис
import pandas as pd
df = pd.DataFrame({
'month': ['янв', 'янв', 'фев', 'фев', 'янв', 'фев'],
'category': ['еда', 'транспорт', 'еда', 'транспорт', 'еда', 'транспорт'],
'amount': [500, 150, 600, 200, 450, 180]
})
pd.pivot_table(
df,
values='amount', # что агрегируем
index='month', # строки
columns='category', # столбцы
aggfunc='sum' # функция агрегации
)
# category еда транспорт
# month
# фев 600 380
# янв 950 150Четыре ключевых параметра: values — столбец с числами, index — по чему группировать в строках, columns — по чему раскладывать в столбцы, aggfunc — как агрегировать.
aggfunc — функция агрегации
По умолчанию aggfunc='mean'. Это частый источник ошибок — многие ожидают сумму.
# Сумма
pd.pivot_table(df, values='amount', index='month', columns='category', aggfunc='sum')
# Количество
pd.pivot_table(df, values='amount', index='month', columns='category', aggfunc='count')
# Несколько функций сразу
pd.pivot_table(df, values='amount', index='month', columns='category',
aggfunc=['sum', 'mean', 'count'])Можно передать словарь, чтобы применить разные функции к разным столбцам:
pd.pivot_table(df, index='month',
aggfunc={'amount': 'sum', 'category': 'count'})Также принимает любую функцию: aggfunc=np.median, aggfunc=lambda x: x.quantile(0.9).
margins — итоговая строка и столбец
margins=True добавляет строку и столбец «All» с общими итогами — как в Excel.
pd.pivot_table(df, values='amount', index='month', columns='category',
aggfunc='sum', margins=True, margins_name='Итого')
# category еда транспорт Итого
# month
# фев 600 380 980
# янв 950 150 1100
# Итого 1550 530 2080fill_value — заполнение пропусков
Если для какой-то комбинации строка×столбец нет данных, в ячейке будет NaN. Параметр fill_value заменяет пропуски:
pd.pivot_table(df, values='amount', index='month', columns='category',
aggfunc='sum', fill_value=0)Multi-index: несколько уровней
Можно передать список столбцов в index или columns для создания многоуровневой сводной:
orders = pd.DataFrame({
'region': ['МСК', 'МСК', 'СПБ', 'СПБ', 'МСК', 'СПБ'],
'channel': ['web', 'app', 'web', 'app', 'web', 'app'],
'device': ['desktop', 'mobile', 'desktop', 'mobile', 'mobile', 'mobile'],
'revenue': [1000, 800, 600, 500, 900, 700]
})
pd.pivot_table(orders, values='revenue', index=['region', 'channel'],
columns='device', aggfunc='sum', fill_value=0)
# device desktop mobile
# region channel
# МСК app 0 800
# web 1000 900
# СПБ app 0 1200
# web 600 0pivot vs pivot_table
pivot — простая перестановка без агрегации. Работает только если для каждой комбинации index×columns ровно одно значение. Если есть дубликаты — упадёт с ошибкой.
pivot_table — то же самое, но с агрегацией. Дубликаты не проблема — они просто агрегируются выбранной функцией.
# pivot — упадёт, если есть дубликаты
df.pivot(index='month', columns='category', values='amount') # ValueError!
# pivot_table — агрегирует дубликаты
pd.pivot_table(df, index='month', columns='category', values='amount', aggfunc='sum') # OKПравило простое: если данные уже уникальны по ключу — pivot. Во всех остальных случаях — pivot_table.
pivot_table vs groupby
pivot_table — это по сути groupby + unstack. Результат одинаковый, но формат разный:
# groupby — длинный формат
df.groupby(['month', 'category'])['amount'].sum()
# month category
# фев еда 600
# транспорт 380
# янв еда 950
# транспорт 150
# pivot_table — широкий формат
pd.pivot_table(df, values='amount', index='month', columns='category', aggfunc='sum')
# category еда транспорт
# фев 600 380
# янв 950 150Когда что использовать: groupby удобнее для дальнейших вычислений и цепочек. pivot_table — когда нужна читаемая таблица для отчёта или визуализации.
Практические примеры
Выручка по месяцам и категориям
sales = pd.DataFrame({
'date': pd.date_range('2025-01-01', periods=120, freq='D'),
'category': ['подписка', 'разовая', 'подписка', 'разовая'] * 30,
'revenue': [500, 200, 550, 180] * 30
})
sales['month'] = sales['date'].dt.to_period('M')
report = pd.pivot_table(sales, values='revenue', index='month',
columns='category', aggfunc='sum', margins=True)Конверсия по каналу и устройству
events = pd.DataFrame({
'channel': ['organic', 'paid', 'organic', 'paid', 'organic', 'paid'],
'device': ['desktop', 'desktop', 'mobile', 'mobile', 'desktop', 'mobile'],
'sessions': [1000, 800, 1200, 600, 950, 700],
'purchases': [50, 60, 30, 25, 45, 20]
})
conv = pd.pivot_table(events, values=['sessions', 'purchases'],
index='channel', columns='device', aggfunc='sum')
conv['cr'] = conv['purchases'] / conv['sessions']Типичные ошибки
Забыть, что aggfunc по умолчанию — mean. Пишут pivot_table(df, index='month', columns='cat', values='amount') и удивляются, что числа не сходятся. Всегда указывайте aggfunc явно.
Путать pivot и pivot_table. pivot не агрегирует, и при дубликатах бросает ValueError. Если не уверены в уникальности — используйте pivot_table.
Игнорировать NaN в результате. Комбинации без данных дают NaN. Если дальше идут вычисления — используйте fill_value=0 или fillna().
Не делать reset_index после pivot_table. Результат имеет index из группирующего столбца, а columns — из разворачиваемого. Для дальнейших операций часто нужен reset_index().
Вопросы с собеседований
Чем отличается pivot от pivot_table?
pivot — простая перестановка без агрегации, требует уникальных комбинаций index×columns. pivot_table — с агрегацией, обрабатывает дубликаты через aggfunc. По сути pivot_table — это groupby + unstack.
Какой aggfunc по умолчанию в pivot_table?
mean. Это частый подвох на собеседовании. Если нужна сумма — указывайте aggfunc='sum' явно.
Как добавить итоги в сводную таблицу?
margins=True добавляет строку и столбец с общими итогами. Имя по умолчанию — «All», можно задать своё через margins_name.
Когда лучше pivot_table, а когда groupby?
pivot_table — когда нужна читаемая двумерная таблица: строки одна категория, столбцы другая. groupby — когда нужен длинный формат для дальнейших вычислений, джойнов или визуализации. Результат один и тот же, разница в форме.
Как применить несколько агрегирующих функций?
Передать список в aggfunc: aggfunc=['sum', 'mean', 'count']. Результат будет с MultiIndex в столбцах. Или передать словарь для разных столбцов: aggfunc={'revenue': 'sum', 'orders': 'count'}.
Потренируйтесь решать задачи — откройте тренажёр с 1500+ вопросами для подготовки к собеседованиям аналитиков.
FAQ
Как убрать MultiIndex из столбцов после pivot_table?
После pivot_table столбцы часто имеют MultiIndex. Чтобы «сплющить»: df.columns = ['_'.join(col).strip() for col in df.columns.values]. Или используйте droplevel(), если лишний уровень не нужен.
Можно ли развернуть pivot_table обратно в длинный формат?
Да — melt(). Это обратная операция к pivot_table: pd.melt(pivot_df, ignore_index=False).reset_index().
Как отсортировать результат pivot_table?
sort_values() по нужному столбцу или sort_index() по индексу. Например: result.sort_values(('revenue', 'sum'), ascending=False).
Где потренировать pivot_table на задачах?
В тренажёре Карьерник — задачи по pandas из реальных собеседований. Также смотрите groupby в pandas, шпаргалку по pandas и примеры вопросов.