pandas: группировки, соединения и упорядоченные показатели

melt, pivot_table и explode: широкий и длинный форматы

Содержание курса

Сводная таблица с агрегацией через pd.pivot_table

pd.melt идёт в одну сторону — из широкого формата в длинный. pd.pivot_table — в обратную: берёт длинную таблицу и строит из неё агрегированный широкий формат.

Представим такую таблицу продаж:

import pandas as pd

df_sales = pd.DataFrame({
    'city':    ['Москва', 'Москва', 'Казань', 'Казань', 'Москва'],
    'month':   ['Jan',    'Feb',    'Jan',    'Feb',    'Jan'],
    'revenue': [100,      200,      150,      130,      80]
})

Здесь несколько строк с одинаковой парой city + month (Москва, Jan встречается дважды). Мы хотим получить таблицу, где строки — города, столбцы — месяцы, а в ячейках — суммарная выручка:

pt = pd.pivot_table(
    df_sales,
    index='city',       # уникальные значения этого столбца станут строками
    columns='month',    # уникальные значения этого столбца станут столбцами
    values='revenue',   # что агрегировать
    aggfunc='sum'       # как агрегировать
)
print(pt)

Вывод:

month   Feb   Jan
city
Казань  130   150
Москва  200   180

Параметры по смыслу:

  • index — столбец, чьи уникальные значения образуют строки результата.
  • columns — столбец, чьи уникальные значения образуют столбцы результата.
  • values — столбец с числами, которые нужно агрегировать.
  • aggfunc — функция агрегации: 'sum', 'mean', 'count' или любая Python-функция. По умолчанию 'mean' — это частая причина неожиданных результатов, поэтому всегда указывай явно.

Именованный индекс и как от него избавиться

У результата pivot_table есть особенность: city становится именованным индексом, а month — именем оси столбцов. Это не ошибка, но если нужна плоская таблица без индекса — вызывай reset_index():

pt_flat = pt.reset_index()
print(pt_flat)

Вывод:

month    city  Feb  Jan
0      Казань  130  150
1      Москва  200  180

После reset_index() city превращается в обычный столбец, индекс становится стандартным RangeIndex. Обрати внимание: метка month над строкой столбцов никуда не девается — это columns.name, оставшееся от параметра columns='month'. Это косметика API, не влияющая на данные; при необходимости убирается через pt_flat.columns.name = None.

Ещё одна частая ситуация — пропуски в результате. Если для какой-то комбинации строка/столбец данных нет, pivot_table ставит NaN. Параметр fill_value позволяет заменить их нулём или любым другим значением:

pt = pd.pivot_table(
    df_sales,
    index='city',
    columns='month',
    values='revenue',
    aggfunc='sum',
    fill_value=0
)

Сводная таблица, построенная через pivot_table, — это полноценный DataFrame, с которым можно работать дальше: сортировать, фильтровать, применять rank или cumsum по строкам или столбцам.