Joins & Merges
Combinar tabelas por chaves compartilhadas é onde ocorrem duplicação silenciosa de linhas e perda de registros. merge e concat do pandas exigem tipos de join explícitos e validação.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
import pandas as pd
merged = left.merge(
right,
on="order_id",
how="left",
validate="many_to_one",
indicator=True,
)
unmatched = merged.loc[merged["_merge"] == "left_only"]Quando usar isso:
- Enriquecer tabelas de fatos com atributos de dimensão
- Juntar respostas de API de múltiplos endpoints
- Unir partições Parquet mensais verticalmente
- Construir conjuntos de treinamento a partir de tabelas de features + rótulos
Exemplo de Trabalho
import pandas as pd
orders = pd.DataFrame(
{"order_id": [1, 2, 3], "customer_id": [10, 11, 10], "amount": [120, 340, 80]}
)
customers = pd.DataFrame(
{"customer_id": [10, 11], "segment": ["SMB", "Enterprise"]}
)
refunds = pd.DataFrame({"order_id": [2], "refund": [50.0]})
# Enriquecimento de dimensão - espera-se 1:1 ou muitos:1
enriched = orders.merge(
customers,
on="customer_id",
how="left",
validate="many_to_one",
)
# Extensão de fato - reembolsos podem estar ausentes
with_refunds = enriched.merge(
refunds,
on="order_id",
how="left",
validate="one_to_one",
)
with_refunds["refund"] = with_refunds["refund"].fillna(0.0)
with_refunds["net"] = with_refunds["amount"] - with_refunds["refund"]
# Auditoria da cobertura do join
audit = orders.merge(customers, on="customer_id", how="left", indicator=True)
missing_customers = audit.loc[audit["_merge"] == "left_only"]
print(with_refunds)
print("linhas de cliente ausentes:", len(missing_customers))O que isso demonstra:
validatepara afirmar expectativas de cardinalidade- Left join preservando todos os pedidos
indicator=Truepara detecção de órfãos- Preencher NA após left join para fatos opcionais
Mergulho Profundo
Como Funciona
mergeexecuta joins estilo banco de dados em chaves de coluna (hash ou sort-merge).howcontrola quais chaves sobrevivem: inner, left, right, outer.validatelevanta um erro se a cardinalidade real violar a relação declarada.concatempilha ao longo do eixo 0 (linhas) ou 1 (colunas) sem alinhamento de chave.
Tipos de Join
| how | Mantém |
|---|---|
| inner | Chaves em ambos |
| left | Todas as chaves da esquerda |
| right | Todas as chaves da direita |
| outer | União das chaves |
Notas de Python
import pandas as pd
# Nomes de coluna diferentes
pd.merge(orders, regions, left_on="region_id", right_on="id")
# Unir arquivos mensais com colunas consistentes
pd.concat([jan, feb], ignore_index=True)Armadilhas
- Merge de muitos para muitos - duplicatas explodem a contagem de linhas multiplicativamente. Correção: deduplique as chaves primeiro ou use
validate="m:m"conscientemente com verificações de contagem de linhas. - Incompatibilidade de tipo de dado da chave -
int64vsobject"1" resulta em join vazio. Correção: useastypenas chaves de ambos os lados antes do merge. - Nomes de coluna duplicados - sufixos padrão são
_x/_y. Correção:suffixes=("", "_dim")e remova colunas redundantes. - Merge acidental no índice - esquecer
on=junta no índice se alinhado. Correção:reset_index()ou flags explícitasleft_index. - concat sem ignore_index - preserva rótulos de linha duplicados. Correção:
ignore_index=Trueou índice hierárquico por fonte.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
DuckDB read_parquet + SQL | Joins complexos de múltiplas tabelas | Dois frames pequenos em memória |
Polars join | Joins preguiçosos grandes | Já no meio do pipeline pandas |
DataFrame.join | Tabelas largas alinhadas por índice | Colunas chave não estão no índice |
| ETL de Banco de Dados | Os dados já vivem no data warehouse | Exploração apenas em notebook |
FAQs
Como detecto uma explosão de muitos para muitos?
assert len(merged) == len(left) # para muitos para um- Compare
lenantes/depois; investigue se o produto cresce.
Quando usar concat vs merge?
concat: mesmo esquema, empilhar períodos ou fragmentos.merge: tabelas diferentes compartilhando chaves.
Como faço merge em múltiplas chaves?
left.merge(right, on=["region", "month"])O que `indicator=True` faz?
- Adiciona a coluna
_merge:left_only,right_only,both. - Sinal rápido de qualidade de dados após left joins.
Como faço um anti-join (linhas em left não em right)?
left.merge(right, on="id", how="left", indicator=True).query("_merge == 'left_only'")Devo definir índices antes do join?
- Não é necessário -
on=é mais claro para a maioria das análises. - Joins de índice ajudam em joins repetidos na mesma chave em loops apertados.
Como faço join asof de séries temporais?
pd.merge_asof(trades.sort_values("ts"), quotes.sort_values("ts"), on="ts")- Seleciona a cotação anterior mais próxima para cada timestamp de negociação.
Posso fazer merge com diferentes granularidades?
- Agregue para um grão comum primeiro (diário vs. horário).
- Muitos para muitos geralmente significa incompatibilidade de grão.
Como removo linhas de chave duplicadas?
right = right.drop_duplicates("customer_id", keep="last")Merge preserva a ordem?
- Não garantido - ordene a saída explicitamente para apresentações.
Relacionados
- Limpeza e Transformação de Dados - normalize chaves primeiro
- GroupBy & Agregação - agregue após o enriquecimento
- Formatos de Arquivo - partições Parquet para concatenar
- Boas Práticas de Análise de Dados - joins reproduzíveis
Versões da Stack: Esta página foi escrita para Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.