Pandas: Agrupamento por Agregação
Última atualização: 2026-08-26
Agregação com GroupBy é o coração da análise de dados — visualizar vendas por região, calcular preços médios por categoria, contar pedidos por mês — tudo se resume em "dividir, calcular, combinar." O groupby do Pandas implementa o clássico paradigma split-apply-combine. Nesta lição, diagramas Mermaid ajudarão você a compreender totalmente o processo, e você dominará as três operações-chave: agg / transform / filter.
1. O Que Você Vai Aprender
- ❶ Como o groupby funciona (dividir-aplicar-combinar)
- ❷ Funções de agregação (soma/média/contagem/máx/mín)
- ❸ Múltiplas agregações e funções personalizadas com agg
- ❹ Transformação dentro do grupo com transform
- ❺ Filtragem em nível de grupo com filter
2. Alice Totalliza Vendas de Cafeteria por Categoria
(1) O Ponto de Dor: Loops Manuais São Tediosos
Alice deseja totalizar as vendas por categoria de bebida. Escrever loops manualmente:
import pandas as pd
df = pd.DataFrame({
'drink': ['Latte', 'Americano', 'Mocha', 'Latte', 'Espresso',
'Americano', 'Latte', 'Mocha', 'Espresso', 'Latte'],
'category': ['Hot', 'Hot', 'Hot', 'Hot', 'Hot',
'Iced', 'Iced', 'Iced', 'Iced', 'Iced'],
'sales': [320, 280, 350, 310, 150, 200, 180, 160, 90, 120],
'quantity': [64, 56, 50, 62, 30, 40, 36, 22, 18, 24]
})
# Loop manual — tedioso e sujeito a erros
for cat in df['category'].unique():
subset = df[df['category'] == cat]
print(f"{cat}: sales={subset['sales'].sum()}, qty={subset['quantity'].sum()}")
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) A Solução: Uma Única Linha com groupby
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: fundamentos do groupby (Dificuldade ⭐)
import pandas as pd
df = pd.DataFrame({
'drink': ['Latte', 'Americano', 'Mocha', 'Latte', 'Espresso',
'Americano', 'Latte', 'Mocha', 'Espresso', 'Latte'],
'category': ['Hot', 'Hot', 'Hot', 'Hot', 'Hot',
'Iced', 'Iced', 'Iced', 'Iced', 'Iced'],
'sales': [320, 280, 350, 310, 150, 200, 180, 160, 90, 120],
'quantity': [64, 56, 50, 62, 30, 40, 36, 22, 18, 24]
})
# Uma linha substitui todo o loop!
result = df.groupby('category')['sales'].sum()
print(result)
# category
# Hot 1410
# Iced 750
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
3. O Princípio Dividir-Aplicar-Combinar
(1) Diagrama Mermaid do Processo de Agrupamento
graph TB
subgraph Split["① Dividir — Separar por categoria"]
S1["Quente: Latte 320<br>Americano 280<br>Mocha 350<br>Latte 310<br>Espresso 150"]
S2["Gelado: Americano 200<br>Latte 180<br>Mocha 160<br>Espresso 90<br>Latte 120"]
end
subgraph Apply["② Aplicar — Somar cada grupo"]
A1["Quente → 320+280+350<br>+310+150 = 1410"]
A2["Gelado → 200+180+160<br>+90+120 = 750"]
end
subgraph Combine["③ Combinar — Juntar resultados"]
C1["categoria | vendas<br>Quente | 1410<br>Gelado | 750"]
end
Split --> Apply --> Combine
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) O Objeto GroupBy é Lazy
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Avaliação lazy com GroupBy (Dificuldade ⭐)
import pandas as pd
df = pd.DataFrame({
'category': ['Hot', 'Hot', 'Iced', 'Iced'],
'sales': [320, 280, 200, 180]
})
# groupby retorna um objeto GroupBy — ainda sem cálculo
grouped = df.groupby('category')
print(type(grouped)) # <class 'pandas.core.groupby.DataFrameGroupBy'>
# O cálculo acontece quando você chama uma agregação
print(grouped['sales'].sum())
# Inspecionar os grupos
print(grouped.groups) # {'Hot': [0, 1], 'Iced': [2, 3]}
print(grouped.ngroups) # 2
# Iterar sobre os grupos (raramente necessário)
for name, group in grouped:
print(f"Grupo: {name}")
print(group)
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
4. Funções de Agregação Comuns
(1) Agregações Integradas
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga alongado. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Funções de agregação integradas (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'category': ['Electronics', 'Electronics', 'Clothing', 'Clothing', 'Home', 'Home'],
'product': ['Laptop', 'Phone', 'Shirt', 'Pants', 'Lamp', 'Chair'],
'price': [999, 699, 45, 65, 30, 120],
'stock': [50, 120, 200, 180, 300, 80],
'rating': [4.7, 4.5, 4.2, 4.0, 3.8, 4.3]
})
# Agregação única por coluna
print(df.groupby('category')['price'].mean())
# Electronics 849.0
# Clothing 55.0
# Home 75.0
# Múltiplas colunas, mesma agregação
print(df.groupby('category')[['price', 'stock']].sum())
# Métodos de agregação comuns:
# .sum() .mean() .median() .min() .max()
# .count() .size() .std() .var() .first() .last()
# .nunique() .idxmax() .idxmin()
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga alongado. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) size vs count
| Método | O Que Computa | Tratamento de NaN |
|---|---|---|
| size | Número de linhas por grupo (inclui NaN) | Inclui NaN |
| count | Número de valores não-NaN por grupo | Exclui NaN |
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga alongado. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: size vs count (Dificuldade ⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'category': ['A', 'A', 'B', 'B', 'A'],
'value': [1, np.nan, 3, 4, 5]
})
print(df.groupby('category').size())
# category
# A 3 ← 3 linhas (incluindo a linha com NaN)
# B 2
print(df.groupby('category').count())
# value
# category
# A 2 ← 2 valores não-NaN
# B 2
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga alongado. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
5. Múltiplas Agregações com agg
(1) Múltiplas Funções de Agregação
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Múltiplas agregações com agg (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'category': ['Electronics', 'Electronics', 'Clothing', 'Clothing', 'Home', 'Home'],
'product': ['Laptop', 'Phone', 'Shirt', 'Pants', 'Lamp', 'Chair'],
'price': [999, 699, 45, 65, 30, 120],
'stock': [50, 120, 200, 180, 300, 80],
'rating': [4.7, 4.5, 4.2, 4.0, 3.8, 4.3]
})
# Multiple aggregations on one column
print(df.groupby('category')['price'].agg(['mean', 'min', 'max']))
# mean min max
# category
# Clothing 55.0 45 65
# Electronics 849.0 699 999
# Home 75.0 30 120
# Different aggregations per column
print(df.groupby('category').agg({
'price': ['mean', 'max'],
'stock': 'sum',
'rating': 'mean'
}))
# Named aggregations (cleaner column names)
result = df.groupby('category').agg(
avg_price=('price', 'mean'),
max_price=('price', 'max'),
total_stock=('stock', 'sum'),
avg_rating=('rating', 'mean')
)
print(result)
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) Funções de Agregação Personalizadas
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Agregação personalizada (Dificuldade ⭐⭐⭐)
import pandas as pd
df = pd.DataFrame({
'category': ['A', 'A', 'A', 'B', 'B', 'B'],
'value': [10, 20, 30, 100, 200, 300]
})
# Custom function: range (max - min)
def value_range(series):
return series.max() - series.min()
result = df.groupby('category')['value'].agg(['mean', value_range])
print(result)
# mean value_range
# category
# A 20.0 20
# B 200.0 200
# Lambda in agg (less readable but concise)
result2 = df.groupby('category')['value'].agg([
('mean', 'mean'),
('range', lambda x: x.max() - x.min()),
('cv', lambda x: x.std() / x.mean()) # coefficient of variation
])
print(result2)
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
6. Transformação Dentro do Grupo com transform
(1) transform Preserva a Forma Original
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Padronização dentro do grupo com transform (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'student': ['Alice', 'Alice', 'Bob', 'Bob', 'Charlie', 'Charlie'],
'subject': ['Math', 'English', 'Math', 'English', 'Math', 'English'],
'score': [85, 90, 92, 88, 78, 82]
})
# Z-score normalization per student
df['z_score'] = df.groupby('student')['score'].transform(
lambda x: (x - x.mean()) / x.std()
)
print(df)
# Fill missing with group mean (instead of global mean)
df2 = pd.DataFrame({
'category': ['A', 'A', 'A', 'B', 'B'],
'value': [10, 20, None, 100, None]
})
df2['value_filled'] = df2.groupby('category')['value'].transform(
lambda x: x.fillna(x.mean())
)
print(df2)
# Rank within group
df['rank'] = df.groupby('student')['score'].transform('rank', method='min')
print(df[['student', 'subject', 'score', 'rank']])
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) Comparação entre transform e agg
| Característica | agg | transform |
|---|---|---|
| Forma de retorno | Uma linha por grupo | Mesmo comprimento do DataFrame original |
| Caso de uso | Relatórios de resumo | Preencher a tabela original |
| Operações típicas | soma/média/contagem | Padronização/preenchimento/classificação |
| Transmissão (broadcasting) | ❌ | ✅ Transmite automaticamente para as linhas originais |
7. Filtragem em Nível de Grupo com filter
(1) Manter ou Descartar Grupos por Condição
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Filtrando grupos com filter (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'category': ['Electronics', 'Electronics', 'Electronics',
'Books', 'Books',
'Clothing', 'Clothing', 'Clothing', 'Clothing'],
'product': ['Laptop', 'Phone', 'Tablet', 'Novel', 'Textbook',
'Shirt', 'Pants', 'Jacket', 'Socks'],
'sales': [5000, 3000, 2000, 200, 300, 800, 600, 400, 100]
})
# Manter apenas grupos onde as vendas totais > 1000
big_categories = df.groupby('category').filter(lambda x: x['sales'].sum() > 1000)
print(big_categories)
# Electronics e Clothing mantidos; Books descartado (200+300=500 < 1000)
# Manter grupos com pelo menos 3 itens
large_groups = df.groupby('category').filter(lambda x: len(x) >= 3)
print(large_groups['category'].unique()) # ['Electronics', 'Clothing']
# Manter grupos onde qualquer produto tem vendas > 4000
has_top_seller = df.groupby('category').filter(lambda x: x['sales'].max() > 4000)
print(has_top_seller['category'].unique()) # ['Electronics']
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
8. Agrupamento Multi-Coluna e as_index
(1) Agrupando por Múltiplas Colunas
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e siga along. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.
: Agregação de groupby multi-coluna (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'region': ['North', 'North', 'North', 'South', 'South', 'South'],
'category': ['Electronics', 'Clothing', 'Electronics',
'Electronics', 'Clothing', 'Clothing'],
'product': ['Laptop', 'Shirt', 'Phone', 'Tablet', 'Pants', 'Jacket'],
'sales': [5000, 800, 3000, 2000, 600, 400]
})
# Group by multiple columns
result = df.groupby(['region', 'category'])['sales'].sum()
print(result)
# region category
# North Clothing 800
# Electronics 8000
# South Clothing 1000
# Electronics 2000
# as_index=False → mantém as colunas de agrupamento como colunas comuns
result2 = df.groupby(['region', 'category'], as_index=False)['sales'].sum()
print(result2)
# region category sales
# 0 North Clothing 800
# 1 North Electronics 8000
# 2 South Clothing 1000
# 3 South Electronics 2000
# sort=False → preserva a ordem original da primeira ocorrência
result3 = df.groupby(['region', 'category'], sort=False)['sales'].sum()
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e siga along. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.
9. Exemplo Completo: Análise Multi-Dimensional de Agrupamento para E-Commerce
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Análise multi-dimensional de agrupamento (groupby) (Dificuldade ⭐⭐⭐)
import pandas as pd
import numpy as np
# ============================================
# Exemplo abrangente: análise de agrupamento
# multi-dim para e-commerce com agg/transform/filter
# ============================================
# 1. Criar dados de vendas
np.random.seed(42)
df = pd.DataFrame({
'region': np.random.choice(['Norte', 'Sul', 'Leste', 'Oeste'], 100),
'category': np.random.choice(['Eletrônicos', 'Vestuário', 'Casa', 'Esportes'], 100),
'product': [f'Item_{i:03d}' for i in range(100)],
'sales': np.round(np.random.uniform(50, 2000, 100), 2),
'quantity': np.random.randint(1, 50, 100),
'discount': np.random.choice([0, 0.1, 0.2, 0.3], 100)
})
# 2. agg: resumo de múltiplas métricas por categoria
summary = df.groupby('category').agg(
total_sales=('sales', 'sum'),
avg_sales=('sales', 'mean'),
max_sales=('sales', 'max'),
order_count=('sales', 'count'),
avg_quantity=('quantity', 'mean')
).round(2)
print("=== Resumo por Categoria ===")
print(summary)
# 3. Agrupamento por múltiplas colunas
region_cat = df.groupby(['region', 'category'], as_index=False).agg(
total_sales=('sales', 'sum'),
avg_discount=('discount', 'mean')
).round(3)
print("\n=== Região × Categoria ===")
print(region_cat.head(8))
# 4. transform: ranking dentro do grupo
df['sales_rank_in_region'] = df.groupby('region')['sales'].transform(
'rank', method='min', ascending=False
)
df['sales_pct_in_category'] = df.groupby('category')['sales'].transform(
lambda x: (x / x.sum() * 100).round(1)
)
print("\n=== Top 3 no Norte ===")
print(df[df['region'] == 'Norte'].nsmallest(3, 'sales_rank_in_region')
[['product', 'sales', 'sales_rank_in_region']])
# 5. filter: manter categorias com > 20 pedidos
big_cats = df.groupby('category').filter(lambda x: len(x) > 20)
print(f"\n=== Categorias Grandes ===")
print(big_cats['category'].value_counts())
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
❓ Perguntas Frequentes
result.loc[('North', 'Electronics')] para selecionar um grupo específico, ou use as_index=False para evitar o índice hierárquico completamente. O reset_index() também pode achatar um índice hierárquico em colunas regulares.📖 Resumo
- O núcleo do groupby é dividir-aplicar-combinar: dividir, computar, mesclar
- O objeto GroupBy utiliza avaliação preguiçosa (lazy evaluation) — o cálculo só acontece quando uma função de agregação é chamada
- Agregações integradas: sum/mean/count/size/min/max/std/nunique, etc.
aggsuporta múltiplas agregações e diferentes agregações por coluna; a sintaxe de agregação nomeada é a mais limpatransformretorna um resultado de mesmo tamanho, ideal para padronização/preenchimento/classificaçãofilterseleciona por condições a nível de grupo, mantendo ou descartando grupos inteiros- O agrupamento em múltiplas colunas produz um MultiIndex; use
as_index=Falsepara evitar indexação hierárquica
📝 Exercícios
- Básico (Dificuldade ⭐): Crie um DataFrame de vendas (região/categoria/vendas). Use groupby + soma/média/contagem para três agregações diferentes e compare os resultados.
- Intermediário (Dificuldade ⭐⭐): Crie uma tabela de notas de alunos. Use agg para calcular média/máxima/mínima para cada disciplina, e use transform para calcular as notas normalizadas por z-score para cada aluno.
- Desafio (Dificuldade ⭐⭐⭐): Simule 50 linhas de pedidos de e-commerce (região/categoria/vendas/quantidade/desconto). Complete o seguinte pipeline: agg resumo multi-métrica → groupby multi-coluna (região+categoria) → transform ranking intra-grupo → filtrar para manter grandes grupos → produzir um relatório abrangente.