Как группировать данные в pandas
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Базовый синтаксис
df.groupby('category')['amount'].sum()Аналог SQL:
SELECT category, SUM(amount) FROM df GROUP BY category;1. Группировка по одной колонке
import pandas as pd
df = pd.DataFrame({
'category': ['A', 'B', 'A', 'B', 'A'],
'amount': [100, 200, 150, 250, 120]
})
# сумма
df.groupby('category')['amount'].sum()
# A 370
# B 450
# среднее
df.groupby('category')['amount'].mean()
# максимум
df.groupby('category')['amount'].max()2. По нескольким колонкам
df.groupby(['country', 'city'])['revenue'].sum()3. Несколько агрегаций одновременно
df.groupby('category')['amount'].agg(['sum', 'mean', 'count'])Или с именованными:
df.groupby('category').agg(
total=('amount', 'sum'),
average=('amount', 'mean'),
transactions=('amount', 'count')
)4. Разные агрегации на разных колонках
df.groupby('category').agg({
'amount': 'sum',
'qty': 'mean',
'user_id': 'nunique'
})5. Custom аггрегации
df.groupby('category')['amount'].agg(lambda x: x.quantile(0.95))
# или более сложно
def iqr(x):
return x.quantile(0.75) - x.quantile(0.25)
df.groupby('category')['amount'].agg(iqr)6. transform — вернуть тот же размер
Добавить колонку «среднее по группе» в каждую строку:
df['mean_per_category'] = df.groupby('category')['amount'].transform('mean')Теперь в каждой строке — среднее её категории. Без groupby — 5 строк. С transform — 5 строк.
7. apply — более гибко, но медленно
df.groupby('category').apply(lambda g: g.sort_values('amount').head(3))
# топ-3 самых маленьких в каждой категорииApply медленнее agg/transform — используйте, только если нужно нечто сложное.
8. reset_index после groupby
# по умолчанию groupby возвращает Series с MultiIndex
g = df.groupby(['a', 'b'])['c'].sum() # MultiIndex Series
# в плоский DataFrame
g = g.reset_index()Или сразу as_index=False:
df.groupby(['a', 'b'], as_index=False)['c'].sum()9. groupby + filter
Оставить только группы, соответствующие условию:
# категории с >100 записей
df.groupby('category').filter(lambda g: len(g) > 100)10. Топ-N в каждой группе
df.sort_values(['category', 'amount'], ascending=[True, False]) \
.groupby('category').head(3)11. Running total в группе
df['running_total'] = df.sort_values('date') \
.groupby('category')['amount'].cumsum()12. Pivot-like — unstack
sales = df.groupby(['month', 'category'])['amount'].sum()
sales.unstack('category')
# строки — month, колонки — categoryИли через pd.pivot_table:
pd.pivot_table(df, values='amount', index='month', columns='category', aggfunc='sum')13. group_keys=False для apply
Избежать лишнего индекса:
df.groupby('category', group_keys=False).apply(lambda g: g.nlargest(3, 'amount'))14. Groupby и NaN
По умолчанию NaN-группы пропускаются:
df.groupby('category', dropna=False)['amount'].sum()
# включит NaN-категориюЧастые ошибки
1. Забыть колонку
df.groupby('category').sum()
# суммирует ВСЕ числовые колонки, не только нужныеПравильно:
df.groupby('category')['amount'].sum()2. transform vs agg
aggвозвращает n_groups строкtransformвозвращает len(df) строк
Ошибка — использовать agg там, где нужен transform.
3. Медленный apply
Для простых агрегаций (sum, mean) используйте встроенные — они vectorized.
4. Забыть reset_index
После groupby индекс — ключ группировки. Для дальнейшей работы может понадобиться reset.
Связанные темы
FAQ
Groupby или pivot_table?
Pivot_table — удобнее для «широкого» представления с несколькими колонками. Groupby — универсальнее.
transform быстрее apply?
Да, transform векторизован. Apply — построчно.
Как сохранить только группы с >N?
.filter(lambda g: len(g) > N).
Можно ли несколько groupby цепочкой?
Да. Часто используют для многомерной агрегации.
Тренируйте pandas — откройте тренажёр с 1500+ вопросами для собесов.