Pandas Merge & Join: Joins estilo SQL do jeito certo
Updated on
Em joins é comum errar: chaves desalinhadas duplicam linhas ou descartam registros. how="inner" é usado demais; validate e indicator quase nunca.
PAS:
- Problema: Merges multiplicam linhas ou perdem dados por chaves erradas.
- Agitar: Depurar leva tempo—sufixos duplicados, produtos cartesianos inesperados, linhas faltando.
- Solução: Definir chaves explicitamente, escolher o
howadequado, usarvalidateeindicatorpara auditar cedo.
Tabela rápida de joins
Tipo (how) | Mantém esquerda? | Mantém direita? | Uso típico |
|---|---|---|---|
inner | ✅ só matches | ✅ só matches | Interseção |
left | ✅ tudo | 🚫 só matches | Enriquecer a esquerda |
right | 🚫 só matches | ✅ tudo | Enriquecer a direita (raro; normalmente inverta) |
outer | ✅ tudo | ✅ tudo | União completa com lacunas |
Dados de exemplo
import pandas as pd
orders = pd.DataFrame({
"order_id": [1, 2, 3],
"customer_id": [100, 101, 102],
"amount": [50, 80, 60],
})
customers = pd.DataFrame({
"customer_id": [100, 101, 103],
"name": ["Ada", "Ben", "Cara"],
"segment": ["pro", "basic", "pro"],
})Merge básico com chave de coluna
result = orders.merge(
customers,
on="customer_id",
how="left",
validate="many_to_one", # tabela de dimensão esperada
indicator=True, # auditar cobertura
)validatedetecta cardinalidades inesperadas (many_to_manyé alerta real).indicatoradiciona_mergecomleft_only/right_only/both.suffixes=("_order", "_cust")evita sobrescrever colunas.
Join com nomes de chave diferentes
payments = pd.DataFrame({
"cust_id": [100, 100, 103],
"last_payment": ["2025-05-20", "2025-05-27", "2025-05-21"],
})
orders.merge(
payments,
left_on="customer_id",
right_on="cust_id",
how="left",
)Joins baseados em índice
customers_idx = customers.set_index("customer_id")
orders.join(customers_idx, on="customer_id", how="left").joiné prático quando a tabela da direita já tem a chave no índice.- Em multi-índice, use
on=["level_0", "level_1"]ou alinhe antes.
Tratar duplicados e sobreposições
# Encontrar duplicatas antes do merge
dupes = customers["customer_id"].value_counts()
problem_keys = dupes[dupes > 1]
# Detectar explosões após o merge
exploded = orders.merge(customers, on="customer_id", how="inner", validate="many_to_many")- Se a contagem de linhas sobe em um
many_to_oneesperado, investigue duplicados. - Considere
drop_duplicates(subset=keys)na dimensão.
Mesclar várias métricas de uma vez
agg = (
orders.groupby("customer_id", as_index=False)
.agg(total_amount=("amount", "sum"), orders_count=("order_id", "count"))
)
customers.merge(agg, on="customer_id", how="left")Agregue e depois una para evitar cadeias de merges em dados transacionais.
Checklist de depuração
| Sintoma | Checar |
|---|---|
| Linhas explodiram | Veja _merge; use validate conforme a cardinalidade esperada. |
| Linhas faltando | Teste how="left" ou how="outer"; alinhe dtypes das chaves. |
| Matches errados | Assegure dtypes iguais nas chaves (string vs int). |
| Colunas sobrepostas | Defina suffixes para não sobrescrever. |
Guias relacionados
Principais pontos
- Escolha o tipo de join com intenção; para enriquecer,
lefté o mais seguro. - Use
validate,indicatoresuffixespara flagrar problemas cedo. - Alinhe chaves e dtypes; deduplique dimensões para evitar explosões.