Pandas Merge & Join: Joins estilo SQL bien hechos
Updated on
Al unir tablas es fácil cometer errores: claves incorrectas, filas duplicadas o pérdida silenciosa de datos. how="inner" se usa demasiado y pocas veces se activan validate o indicator.
Enfoque PAS:
- Problema: Los merges multiplican filas o eliminan registros por claves desalineadas.
- Agitar: Depurar joins consume tiempo: sufijos duplicados, productos cartesianos inesperados o filas faltantes.
- Solución: Definir claves explícitas, usar
validatey elegir elhowcorrecto; añadirindicatorpara auditar rápido.
Cheat sheet de joins
Tipo (how) | ¿Conserva izquierda? | ¿Conserva derecha? | Uso típico |
|---|---|---|---|
inner | ✅ solo coincidencias | ✅ solo coincidencias | Intersección |
left | ✅ todas | 🚫 solo coincidencias | Enriquecer la izquierda |
right | 🚫 solo coincidencias | ✅ todas | Enriquecer la derecha (raro; suele ser mejor invertir) |
outer | ✅ todas | ✅ todas | Unión completa con huecos |
Datos de ejemplo
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 con clave de columna
result = orders.merge(
customers,
on="customer_id",
how="left",
validate="many_to_one", # se espera dimensión
indicator=True, # auditar cobertura
)validatedetecta cardinalidades inesperadas (many_to_manyhay que atenderlo).indicatoragrega_mergeconleft_only/right_only/both.suffixes=("_order", "_cust")evita sobrescribir columnas.
Join con nombres de clave distintos
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 basados en índice
customers_idx = customers.set_index("customer_id")
orders.join(customers_idx, on="customer_id", how="left").joines útil si la tabla derecha ya tiene la clave en el índice.- Para multi-índice, usa
on=["level_0", "level_1"]o alinea antes.
Manejar duplicados y solapamientos
# Detectar claves duplicadas antes del merge
dupes = customers["customer_id"].value_counts()
problem_keys = dupes[dupes > 1]
# Detectar explosiones tras el merge
exploded = orders.merge(customers, on="customer_id", how="inner", validate="many_to_many")- Si la cuenta de filas sube en un supuesto
many_to_one, revisa duplicados. drop_duplicates(subset=keys)en la tabla de dimensiones suele ayudar.
Combinar varias métricas a la 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")Agrega y luego une para evitar cadenas de joins sobre datos transaccionales.
Checklist de depuración
| Síntoma | Revisa |
|---|---|
| Filas explotaron | Mira _merge; ajusta validate a la cardinalidad esperada. |
| Faltan filas tras el merge | Prueba how="left" o how="outer"; revisa tipos de dato de las claves. |
| Matches incorrectos | Alinea dtypes en las claves (strings vs ints, etc.). |
| Columna solapada | Define suffixes para evitar sobrescritura. |
Guías relacionadas
Claves finales
- Elige el tipo de join con intención;
leftsuele ser el más seguro para enriquecer. - Usa
validate,indicatorysuffixespara detectar problemas temprano. - Alinea claves y dtypes; deduplica dimensiones para evitar explosiones.