Skip to content

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 validate y elegir el how correcto; añadir indicator para auditar rápido.

Cheat sheet de joins

Tipo (how)¿Conserva izquierda?¿Conserva derecha?Uso típico
inner✅ solo coincidencias✅ solo coincidenciasIntersección
left✅ todas🚫 solo coincidenciasEnriquecer la izquierda
right🚫 solo coincidencias✅ todasEnriquecer la derecha (raro; suele ser mejor invertir)
outer✅ todas✅ todasUnió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
)
  • validate detecta cardinalidades inesperadas (many_to_many hay que atenderlo).
  • indicator agrega _merge con left_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")
  • .join es ú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íntomaRevisa
Filas explotaronMira _merge; ajusta validate a la cardinalidad esperada.
Faltan filas tras el mergePrueba how="left" o how="outer"; revisa tipos de dato de las claves.
Matches incorrectosAlinea dtypes en las claves (strings vs ints, etc.).
Columna solapadaDefine suffixes para evitar sobrescritura.

Guías relacionadas


Claves finales

  • Elige el tipo de join con intención; left suele ser el más seguro para enriquecer.
  • Usa validate, indicator y suffixes para detectar problemas temprano.
  • Alinea claves y dtypes; deduplica dimensiones para evitar explosiones.