merge en pandas: cómo unir DataFrames paso a paso

merge en pandas combina dos DataFrames a partir de una o más claves, igual que un JOIN en SQL. Permite añadir el nombre del cliente a sus pedidos, cruzar productos con precios o comparar registros de dos sistemas.
La dificultad no está en escribir la función, sino en comprender la cardinalidad. Si las claves se repiten de ambos lados, las filas pueden multiplicarse. Esta guía enseña a unir y, sobre todo, a validar el resultado.
DataFrames de ejemplo
import pandas as pd
clientes = pd.DataFrame({
"cliente_id": [1, 2, 3],
"nombre": ["Ana", "Luis", "Marta"],
})
pedidos = pd.DataFrame({
"pedido_id": [101, 102, 103, 104],
"cliente_id": [1, 1, 2, 4],
"total": [250, 180, 320, 90],
})
El cliente 1 tiene dos pedidos, el 3 no tiene pedidos y el pedido del cliente 4 no encuentra maestro.
inner merge
Conserva las coincidencias:
resultado = pedidos.merge(
clientes,
on="cliente_id",
how="inner",
)
Desaparecen el cliente 3 y el pedido del cliente 4.
left merge
Conserva todas las filas del DataFrame izquierdo:
resultado = pedidos.merge(
clientes,
on="cliente_id",
how="left",
)
El pedido del cliente 4 permanece y nombre queda como NaN. Este patrón sirve para enriquecer una tabla transaccional y detectar referencias sin correspondencia.
right y outer
right = pedidos.merge(clientes, on="cliente_id", how="right")
outer = pedidos.merge(clientes, on="cliente_id", how="outer")
rightconserva todas las filas de la derecha.outerconserva todas las claves de ambos lados.
En la práctica, muchos equipos prefieren invertir el orden y usar left en vez de right, porque se lee con más facilidad.
Indicador de coincidencia
auditoria = pedidos.merge(
clientes,
on="cliente_id",
how="outer",
indicator=True,
)
print(auditoria["_merge"].value_counts())
_merge marca:
both;left_only;right_only.
Es una herramienta excelente para conciliaciones.
Unir claves con nombres distintos
resultado = pedidos.merge(
clientes,
left_on="id_cliente",
right_on="cliente_id",
how="left",
)
Después decide qué clave conservar:
resultado = resultado.drop(columns="cliente_id")
No mantengas dos columnas redundantes sin explicar su origen.
Merge por varias columnas
resultado = ventas.merge(
tarifas,
on=["pais", "categoria"],
how="left",
)
Las combinaciones de ambas columnas deben coincidir. Revisa espacios, mayúsculas, acentos y tipos antes de unir.
El problema de las filas duplicadas
Si una clave aparece dos veces a la izquierda y tres a la derecha, el resultado tendrá seis combinaciones para esa clave. No es un error de pandas; es un JOIN muchos a muchos.
Comprueba:
clientes["cliente_id"].duplicated().sum()
pedidos["pedido_id"].duplicated().sum()
Y declara la cardinalidad esperada:
resultado = pedidos.merge(
clientes,
on="cliente_id",
how="left",
validate="many_to_one",
)
Valores útiles:
one_to_one;one_to_many;many_to_one;many_to_many.
validate convierte un supuesto silencioso en una prueba ejecutable.
Sufijos para columnas repetidas
Si ambos DataFrames tienen fecha:
resultado = pedidos.merge(
clientes,
on="cliente_id",
how="left",
suffixes=("_pedido", "_cliente"),
)
Usa sufijos descriptivos. _x y _y se vuelven ambiguos al encadenar transformaciones.
Tipos y limpieza de claves
Una columna entera no coincide con texto:
pedidos["cliente_id"] = pedidos["cliente_id"].astype("Int64")
clientes["cliente_id"] = clientes["cliente_id"].astype("Int64")
Para texto:
pedidos["codigo"] = pedidos["codigo"].str.strip().str.upper()
clientes["codigo"] = clientes["codigo"].str.strip().str.upper()
No elimines ceros iniciales de códigos sin confirmar el significado. Un código es texto aunque contenga dígitos.
merge, join y concat
| Función | Uso típico |
|---|---|
merge |
Unir por columnas o índices con lógica SQL |
join |
Unir principalmente por índice |
concat |
Apilar filas o columnas |
todo_el_ano = pd.concat(
[enero, febrero, marzo],
ignore_index=True,
)
concat no busca coincidencias de clave como merge.
Unir por índice
Si el identificador está en el índice:
clientes_idx = clientes.set_index("cliente_id")
resultado = pedidos.merge(
clientes_idx,
left_on="cliente_id",
right_index=True,
how="left",
validate="many_to_one",
)
DataFrame.join() también es cómodo para índices, pero merge suele hacer más explícita la relación. No conviertas una columna en índice solo para unir si después necesitarás tratarla como campo normal.
Cross merge: producto cartesiano
combinaciones = productos.merge(
regiones,
how="cross",
)
Devuelve cada combinación posible. Es útil para construir escenarios o una cuadrícula completa, pero el tamaño crece como filas_izquierda × filas_derecha. Calcula ese volumen antes de ejecutarlo.
merge_asof para tiempos
Cuando necesitas la fila temporal más cercana:
resultado = pd.merge_asof(
eventos.sort_values("fecha"),
precios.sort_values("fecha"),
on="fecha",
direction="backward",
)
Es útil para asignar a cada evento el último precio conocido. Los DataFrames deben estar ordenados y debes definir tolerancia si una coincidencia demasiado antigua no es válida.
Checklist después de un merge
antes = len(pedidos)
resultado = pedidos.merge(
clientes,
on="cliente_id",
how="left",
validate="many_to_one",
indicator=True,
)
assert len(resultado) == antes
print(resultado["_merge"].value_counts())
print(resultado.isna().sum())
Además, compara totales de control antes y después. Si una unión de enriquecimiento cambia la suma de ventas, probablemente multiplicó filas.
Errores comunes
- No definir la cardinalidad esperada.
- Unir claves con tipos distintos.
- Confundir
concatymerge. - Usar
drop_duplicatespara esconder una multiplicación. - Ignorar
left_onlyyright_only. - Mantener sufijos ambiguos.
- Unir por nombres cuando existe un identificador estable.
- No verificar conteos y totales.
Si luego necesitas resumir el resultado, usa groupby en pandas.
Preguntas frecuentes
¿Qué hace merge en pandas?
Combina filas de dos DataFrames según claves, con estrategias equivalentes a inner, left, right y full outer JOIN.
¿Por qué un merge aumenta el número de filas?
Porque una clave se repite en ambos lados y genera todas las combinaciones. Usa validate para detectar cardinalidades inesperadas.
¿Cómo conservo todas las filas del primer DataFrame?
Usa how="left".
¿Cómo identifico filas sin coincidencia?
Añade indicator=True y revisa _merge.
¿Cuál es la diferencia entre merge y concat?
Merge cruza por claves; concat apila objetos por filas o columnas.
¿Cómo evito columnas _x y _y?
Selecciona columnas antes de unir o define suffixes=("_origen1", "_origen2").

Deja una respuesta