Группировка данных (groupby) и агрегатные функции
Мы уже научились выбирать нужные столбцы и фильтровать строки, чтобы отсечь лишнее. Но в реальной работе аналитика редко просят просто показать список заказов. Чаще бизнес хочет знать: «Какова выручка по городам?» или «Какой средний чек у разных групп клиентов?». Для ответов на такие вопросы мы используем группировку — мощный инструмент, который превращает тысячи строк сырых данных в понятные и компактные отчеты.
От Сводных таблиц к логике Pandas
Если мы раньше работали со Сводными таблицами в Excel, то концепция группировки нам уже знакома. В Excel мы перетаскиваем поле в «Строки», а другое — в «Значения», выбирая тип вычисления (сумма, среднее). В Pandas этот процесс описывается концепцией Split-Apply-Combine (Разбить — Применить — Объединить).
- Split (Разбить): Данные разделяются на группы по определенному признаку (например, по категории товара).
- Apply (Применить): К каждой группе применяется функция (вычисляем сумму, среднее или количество).
- Combine (Объединить): Результаты вычислений собираются в новую таблицу.
Визуализация процесса: данные «схлопываются» до уникальных значений группирующего ключа.
Базовый синтаксис: Метод groupby()
Для начала работы мы используем метод .groupby(). Важно понимать, что сам по себе этот метод не возвращает таблицу. Он создает промежуточный объект GroupBy — это своего рода «инструкция», которая подготовила данные к расчетам, но еще не выполнила их.
# Группируем данные по столбцу 'category'
grouped = df.groupby('category')
# Если мы попробуем вывести grouped, мы увидим лишь техническое описание объекта.
# Чтобы получить результат, нужно добавить агрегатную функцию.
result = df.groupby('category')['sales'].sum()
Важное замечание: При группировке по умолчанию Pandas делает столбец, по которому мы группировали, индексом (жирным заголовком строки). Чтобы вернуть его в обычные столбцы, мы используем метод
.reset_index(). Это критически важно для дальнейшей работы с данными.
Именованная агрегация (Named Aggregation)
В 2026 году стандартом индустрии считается написание чистого и читаемого кода. Раньше аналитики часто использовали сложные цепочки переименований столбцов после группировки. Сейчас мы используем Named Aggregation — это позволяет задать имя новому столбцу и выбрать функцию для расчета в один шаг.
Рассмотрим пример анализа продаж. Мы хотим узнать общую выручку и количество уникальных покупателей для каждого региона.
Пример кода, который неудобно читать и поддерживать:
# Не самый эффективный подход
res = df.groupby('region')['sales'].agg(['sum', 'nunique'])
res.columns = ['total_revenue', 'unique_customers'] # Ручное переименование
Современный и надежный подход:
# Именованная агрегация — чисто и понятно
region_report = df.groupby('region').agg(
total_revenue=('sales', 'sum'),
unique_clients=('client_id', 'nunique'),
avg_check=('sales', 'mean')
)
# Сбрасываем индекс, чтобы превратить 'region' обратно в колонку
region_report = region_report.reset_index()
Агрегатные функции и их выбор
Мы уже знакомы с основами статистики, поэтому при выборе функции агрегации мы должны учитывать особенности данных:
sum()— общие итоги (выручка, количество проданных штук).mean()— среднее значение. Осторожно: оно чувствительно к выбросам!median()— медиана. Лучше использовать для типичного чека или зарплаты, если в данных есть аномалии.count()— количество строк (включая пустые значения, если не указано иное).size()— общее количество строк в группе.nunique()— количество уникальных элементов (например, сколько уникальных пользователей совершили покупки).
Типичные ошибки при группировке
Одной из частых проблем является попытка применить математическую функцию к нечисловым данным.
Проблемный код:
# Если в таблице есть текстовые столбцы, sum() может вызвать ошибку или предупреждение
df.groupby('city').sum()
Правильный подход:
Всегда явно указывайте, какие столбцы вы хотите агрегировать, или используйте параметр numeric_only=True.
# Указываем конкретно, что суммируем
df.groupby('city')[['sales', 'profit']].sum()
Также стоит помнить про пропуски (NaN). По умолчанию groupby исключает строки, где в ключевом столбце (по которому группируем) есть пустое значение. Если мы хотим увидеть группу с «неизвестными» значениями, нужно добавить параметр dropna=False.
Практический кейс: Анализ маркетинговых каналов
Представим, что у нас есть данные о заказах из разных рекламных источников. Нам нужно понять, какой канал приносит больше денег, а какой — более лояльных клиентов.
marketing_analysis = df.groupby('source').agg(
total_sales=('revenue', 'sum'),
orders_count=('order_id', 'count'),
loyal_customers=('customer_id', 'nunique')
).reset_index()
# Рассчитаем средний доход на одного уникального клиента
marketing_analysis['revenue_per_client'] = (
marketing_analysis['total_sales'] / marketing_analysis['loyal_customers']
)
Использование таких конструкций позволяет нам за несколько секунд превратить сырой лог транзакций в готовую таблицу для бизнес-отчета.
Теперь мы умеем «схлопывать» данные и получать из них ключевые метрики. Но часто бывает так, что нужная информация (например, имена менеджеров или названия брендов) хранится в другой таблице. Чтобы собрать полную картину, нам нужно научиться соединять таблицы между собой. В следующей теме мы разберем, как работает «склейка» данных с помощью Merge и Concat.