Agrupar e agregar
Separar por chaves, calcular agregações, pivot_table e distinguir agg de transform.
Queremos o número total de unidades por cidade. Cada venda tem uma quantidade, mas o relatório precisa de uma linha por cidade. Agrupar identifica as vendas da mesma cidade; agregar reduz essas vendas a um resultado.
Separar, calcular e reunir
import pandas as pd
vendas = pd.DataFrame({
"cidade": ["Porto", "Porto", "Braga", "Braga"],
"produto": ["pão", "leite", "pão", "arroz"],
"quantidade": [2, 3, 5, 4],
"preco": [1.5, 1.2, 1.5, 2.0],
})
vendas["total"] = vendas["quantidade"] * vendas["preco"]
resumo = vendas.groupby("cidade", as_index=False).agg(
unidades=("quantidade", "sum"),
faturacao=("total", "sum"),
vendas=("produto", "size"),
)
print(resumo.round(2).to_string(index=False))Dados de entrada
Porto vende 5 unidades em duas vendas e fatura 6,60 euros. Braga vende 9 unidades em duas vendas e fatura 15,50 euros. A soma da faturação dos grupos é 22,10 euros, igual à da tabela original.
as_index=False conserva cidade como uma coluna. Sem esse argumento, cidade torna-se o índice do resultado. A agregação com nomes diz de que coluna vem cada cálculo e como se chama no relatório.
size, count e múltiplas chaves
size conta linhas do grupo. count conta valores não nulos de uma coluna. Se uma das vendas não tem produto conhecido, size continua a contar a venda e count nessa coluna não a conta.
groupby(["cidade", "produto"]) cria um grupo por par. Cada chave adicional refina os grupos. Por defeito, linhas com chaves em falta podem ser excluídas; usa dropna=False quando devem formar um grupo explícito.
agg(["sum", "mean"]) calcula várias estatísticas. Não agregues a coluna de preço com soma se a pergunta for faturação. Primeiro calcula quantidade vezes preço por venda e só depois soma esses totais.
transform conserva as linhas
agg produz um resultado por grupo. transform devolve um valor associado a cada linha original. Para calcular a proporção de unidades de uma venda dentro da cidade:
total_cidade = vendas.groupby("cidade")["quantidade"].transform("sum")
vendas["proporcao"] = vendas["quantidade"] / total_cidade
No Porto, as proporções são 2/5 e 3/5. Em Braga, 5/9 e 4/9. A soma é um em cada cidade, se o total do grupo for não nulo e todas as vendas forem consideradas.
Tabela dinâmica com pivot_table
tabela = vendas.pivot_table(
index="cidade",
columns="produto",
values="quantidade",
aggfunc="sum",
fill_value=0,
)
Cada célula soma as quantidades de uma combinação cidade-produto. pivot_table admite combinações repetidas porque a agregação decide como as reunir. A função por defeito é média, por isso escreve aggfunc="sum" quando o enunciado pede totais.
fill_value=0 transforma uma combinação sem vendas em zero depois da agregação. Isto exige interpretar a ausência como nenhuma venda, não como uma quantidade desconhecida. margins=True acrescenta totais, mas só deves somá-los outra vez se quiseres contar os dados duas vezes.
Rever a agregação
Exercícios
Contar observações incompletas
Um grupo tem três linhas, mas uma célula da coluna produto está em falta. Quanto vale count() nessa coluna?
Primeira pista
Mais uma pista
Ver solução
count vale 2. size valeria 3, porque conta linhas independentemente dessa ausência.
Erros frequentes
Conservar a forma inicial
Queres acrescentar a cada venda a quantidade total da sua cidade. Qual é a escolha?
Primeira pista
Mais uma pista
transform conserva as linhas; agg reduz aos grupos.
Ver solução
Usa transform e atribui o resultado a uma coluna nova. Depois confere que as vendas da mesma cidade recebem o mesmo total.
- groupby("cidade")["quantidade"].transform("sum"). Devolve um valor para cada linha original, alinhado pelo índice.
- groupby("cidade")["quantidade"].sum() atribuído diretamente. Tem uma linha por cidade; os rótulos podem não alinhar com o índice das vendas.
- quantidade.sum(). Calcula o total global e perde a distinção de cidades.
Erros frequentes
Usar uma agregação reduzida como se tivesse o índice da tabela inicial.