Uma análise completa de vendas
Importar, validar, relacionar e agregar dados, conservando decisões e verificações.
Vamos responder a duas perguntas: quanto faturou cada cidade e qual foi o preço médio por unidade vendida? Temos um CSV com vendas e outra tabela com preços por produto. Os dados abaixo são fictícios e pequenos para poderes verificar cada passo.
Definir as observações
Cada linha de vendas identifica uma venda, com código único, cidade, produto e quantidade. O catálogo tem um preço por produto. Quantidade deve ser positiva e o preço deve ser conhecido antes de calcular a faturação.
| Venda | Cidade | Produto | Quantidade |
|---|---|---|---|
| 1 | Porto | A | 2 |
| 2 | Porto | B | 3 |
| 3 | Braga | A | 5 |
| 4 | Braga | C | 4 |
A custa 1,50 euros, B custa 1,20 e C custa 2,00. À mão, Porto fatura 6,60 e Braga 15,50. O total é 22,10 euros e há 14 unidades.
Código do princípio ao fim
from io import StringIO
import pandas as pd
csv_vendas = 'venda;cidade;produto;quantidade\n1;Porto;A;2\n2;Porto;B;3\n3;Braga;A;5\n4;Braga;C;4\n'
vendas = pd.read_csv(StringIO(csv_vendas), sep=";", dtype={"produto": "string"})
precos = pd.DataFrame({"produto": ["A", "B", "C"], "preco": [1.5, 1.2, 2.0]})
assert vendas["venda"].is_unique
assert vendas[["cidade", "produto", "quantidade"]].notna().all().all()
assert (vendas["quantidade"] > 0).all()
assert precos["produto"].is_unique
dados = vendas.merge(precos, on="produto", how="left", validate="many_to_one")
assert len(dados) == len(vendas)
assert dados["preco"].notna().all()
dados["total"] = dados["quantidade"] * dados["preco"]
relatorio = dados.groupby("cidade", as_index=False).agg(
unidades=("quantidade", "sum"),
faturacao=("total", "sum"),
vendas=("venda", "size"),
)
relatorio["preco_medio"] = relatorio["faturacao"] / relatorio["unidades"]
assert abs(relatorio["faturacao"].sum() - dados["total"].sum()) < 1e-10
print(relatorio.round(4).to_string(index=False))
print("Faturação total:", round(dados["total"].sum(), 2))
print("Unidades:", dados["quantidade"].sum())
print("Preço médio global:", round(dados["total"].sum() / dados["quantidade"].sum(), 4))Dados de entrada
O preço médio por unidade é 1,32 euros no Porto e aproximadamente 1,7222 em Braga. O global é 22,10 / 14, aproximadamente 1,5786 euros. Não calculamos a média das médias das cidades, porque venderam quantidades diferentes.
Por que cada verificação existe
A chave de venda única impede contar o mesmo identificador duas vezes. As colunas essenciais não podem estar ausentes. A quantidade positiva faz parte do contrato deste exemplo; noutro conjunto, quantidades negativas podem representar devoluções e precisam de outra regra.
A chave de produto única evita multiplicar linhas na junção. how="left" conserva as vendas, permitindo detetar produtos sem preço. Só calculamos totais depois de confirmar que todos têm correspondência.
A contagem de linhas deve manter-se na junção muitos-para-um. A soma da faturação dos grupos deve coincidir com a soma antes de agrupar. Estas verificações não provam que os preços reais estão corretos, mas detetam perdas e duplicações no processamento.
Acrescentar uma situação incompleta
Substitui C por D numa das vendas e volta a executar. A verificação dos preços falha antes de produzir o relatório. Para continuar, é preciso consultar o catálogo ou definir uma política para vendas sem preço. Não substituas o preço em falta por zero só para obter uma tabela final.
Duplica a linha de A no catálogo e executa novamente. validate="many_to_one" rejeita a junção. Sem essa verificação, as vendas de A seriam duplicadas e a soma ficaria errada.
Preparar uma resolução de avaliação
Lê o pedido e identifica a unidade de análise. Escreve a chave que identifica cada linha, as colunas de que precisas e o resultado esperado. Depois escolhe seleção, transformação, junção ou agregação conforme a pergunta.
Antes de executar, prevê pelo menos uma célula e o número de linhas do resultado. Depois de executar, confere esse caso e um total que deva conservar-se. Na resposta, inclui o código, o valor obtido e a sua interpretação com unidade. Uma tabela correta sem explicar o que cada linha representa pode não responder à pergunta.
Exercícios
Calcular o preço médio global
Porto faturou 6,60 euros em 5 unidades e Braga 15,50 em 9. Qual é o preço médio global por unidade? Arredonda a quatro casas decimais.
Primeira pista
A média global usa as somas da faturação e das unidades.
Mais uma pista
Ver solução
O resultado é aproximadamente 1,5786 euros por unidade. Uma média simples das duas médias daria igual peso a cidades com quantidades diferentes.
Erros frequentes
Somar médias ou calcular a sua média simples sem ponderar as unidades.
Detetar um catálogo duplicado
O catálogo passa a ter duas linhas para o mesmo produto. Explica o efeito numa junção e como a análise o deteta antes do relatório.
Primeira pista
Uma junção cria um par para cada correspondência da chave.
Mais uma pista
Ver solução
A junção duplicaria as vendas desse produto e poderia aumentar a faturação. A unicidade da chave e validate=“many_to_one” impedem continuar com esse catálogo. Não elimines arbitrariamente um preço sem resolver a ambiguidade.
Confere a tua resposta:
- Expliquei que cada venda desse produto encontra duas correspondências.
- Identifiquei validate="many_to_one" como verificação da relação.
- Indiquei que conferir linhas e totais ajuda a detetar multiplicação.
Erros frequentes
Aceitar o relatório porque o código executou ou escolher o primeiro preço sem uma regra.