merge() y concat() son las dos funciones principales de pandas para combinar DataFrames provenientes de distintas fuentes.
En análisis de datos reales, la información rara vez viene en una sola tabla. Un sistema de ventas de Liverpool puede guardar los tickets en un archivo y el catálogo de productos en otro. Para analizarlos juntos, necesitas unirlos.
merge(): unión tipo SQL JOIN
merge() une dos DataFrames usando una o más columnas como llave común.
Funciona exactamente igual que un JOIN en SQL. Buscas filas donde el valor de la llave coincide en ambas tablas.
Sintaxis básica
resultado = pd.merge(df_izquierdo, df_derecho, on="columna_llave", how="tipo")
on: nombre de la columna llave (debe existir en ambos DataFrames).how: tipo de unión. Los valores posibles son"inner","left","right"y"outer".
Tipos de unión con how
| Tipo | Qué devuelve |
|---|---|
inner |
Solo filas con llave en ambas tablas |
left |
Todas las filas del DataFrame izquierdo |
right |
Todas las filas del DataFrame derecho |
outer |
Todas las filas de ambas tablas |
El tipo más común en análisis de datos es left. Conservas todos tus registros de ventas aunque el producto no esté en el catálogo.
Ejemplo 1: cruzar ventas con catálogo de productos
Supón que tienes dos tablas de un sistema de FEMSA.
import pandas as pd
# Tabla de ventas
ventas = pd.DataFrame({
"id_producto": [101, 102, 103, 104],
"cantidad": [5, 3, 8, 2],
"precio_unitario": [18500, 9500, 4200, 31000]
})
# Catálogo de productos
catalogo = pd.DataFrame({
"id_producto": [101, 102, 103],
"nombre_producto": ["Refresco 600ml", "Agua 1.5L", "Jugo 1L"],
"categoria": ["Bebidas", "Bebidas", "Jugos"]
})
# Unión left: conserva todas las ventas
resultado = pd.merge(ventas, catalogo, on="id_producto", how="left")
print(resultado)
Resultado:
id_producto cantidad precio_unitario nombre_producto categoria
0 101 5 18500 Refresco 600ml Bebidas
1 102 3 9500 Agua 1.5L Bebidas
2 103 8 4200 Jugo 1L Jugos
3 104 2 31000 NaN NaN
El producto 104 no existe en el catálogo. Con how="left" se conserva, pero con valores NaN en las columnas del catálogo. Con how="inner" esa fila desaparecería.
Ejemplo 2: merge con llaves de nombre diferente
A veces la misma columna tiene nombres distintos en cada tabla. Usa left_on y right_on.
# Tabla de empleados de Bimbo
empleados = pd.DataFrame({
"num_empleado": [1001, 1002, 1003],
"nombre": ["Ana Torres", "Luis Pérez", "María García"],
"salario": [18500, 22000, 15800]
})
# Tabla de evaluaciones
evaluaciones = pd.DataFrame({
"id_emp": [1001, 1002, 1004],
"calificacion": [9.5, 8.0, 7.2]
})
resultado = pd.merge(
empleados,
evaluaciones,
left_on="num_empleado",
right_on="id_emp",
how="left"
)
print(resultado[["nombre", "salario", "calificacion"]])
Resultado:
nombre salario calificacion
0 Ana Torres 18500 9.5
1 Luis Pérez 22000 8.0
2 María García 15800 NaN
María García no tiene evaluación registrada. Con how="left" se mantiene en el resultado con NaN.
Ejemplo 3: merge con múltiples llaves
Puedes unir por más de una columna al mismo tiempo. Esto es útil cuando la combinación de dos columnas identifica una fila de forma única.
# Ventas por tienda y mes en Liverpool
ventas_mes = pd.DataFrame({
"tienda": ["CDMX", "CDMX", "MTY"],
"mes": [1, 2, 1],
"total_ventas": [850000, 920000, 710000]
})
# Metas por tienda y mes
metas = pd.DataFrame({
"tienda": ["CDMX", "CDMX", "MTY"],
"mes": [1, 2, 1],
"meta": [800000, 900000, 750000]
})
resultado = pd.merge(ventas_mes, metas, on=["tienda", "mes"], how="inner")
resultado["cumplimiento"] = resultado["total_ventas"] / resultado["meta"]
print(resultado)
Resultado:
tienda mes total_ventas meta cumplimiento
0 CDMX 1 850000 800000 1.062500
1 CDMX 2 920000 900000 1.022222
2 MTY 1 710000 750000 0.946667
La tienda de Monterrey no alcanzó su meta en enero.
concat(): apilar DataFrames
concat() apila DataFrames uno encima del otro (por filas) o uno al lado del otro (por columnas).
Úsalo cuando tienes la misma estructura de datos dividida en varios archivos. Por ejemplo, las ventas de Mercado Libre de enero, febrero y marzo en tres archivos separados.
Sintaxis básica
resultado = pd.concat([df1, df2, df3], axis=0, ignore_index=True)
axis=0: apila por filas (valor por defecto).axis=1: apila por columnas.ignore_index=True: reinicia el índice del DataFrame resultante.
Ejemplo 4: unir reportes mensuales de Mercado Libre
# Ventas de tres meses
enero = pd.DataFrame({
"producto": ["Laptop", "Celular"],
"ventas": [45000, 32000],
"mes": ["Enero", "Enero"]
})
febrero = pd.DataFrame({
"producto": ["Laptop", "Celular"],
"ventas": [51000, 28000],
"mes": ["Febrero", "Febrero"]
})
marzo = pd.DataFrame({
"producto": ["Laptop", "Celular"],
"ventas": [47000, 35000],
"mes": ["Marzo", "Marzo"]
})
trimestre = pd.concat([enero, febrero, marzo], ignore_index=True)
print(trimestre)
Resultado:
producto ventas mes
0 Laptop 45000 Enero
1 Celular 32000 Enero
2 Laptop 51000 Febrero
3 Celular 28000 Febrero
4 Laptop 47000 Marzo
5 Celular 35000 Marzo
Ahora puedes hacer un groupby para calcular el total trimestral por producto.
Diferencia clave entre merge y concat
| Función | Cuándo usarla |
|---|---|
merge() |
Las tablas tienen columnas distintas y se relacionan por una llave |
concat() |
Las tablas tienen la misma estructura y quieres apilarlas |
Una regla simple: si piensas en "unir columnas nuevas", usa merge(). Si piensas en "agregar más filas", usa concat().
Errores comunes
Error 1: duplicar filas sin darse cuenta.
Si la columna llave tiene valores repetidos en ambas tablas, merge() crea todas las combinaciones posibles. El resultado puede tener más filas de las esperadas. Verifica con df["llave"].value_counts() antes de hacer el merge.
Error 2: olvidar ignore_index=True en concat().
Sin este parámetro, los índices originales se conservan y pueden repetirse. Esto causa errores al acceder a filas por índice. Siempre usa ignore_index=True cuando apiles tablas de distintas fuentes.
Error 3: columnas con nombres distintos en concat().
Si dos DataFrames tienen columnas con nombres ligeramente diferentes (por ejemplo, "Ventas" y "ventas"), concat() las tratará como columnas distintas y llenará con NaN. Verifica que los nombres de columna sean idénticos antes de concatenar.
Error 4: usar how="inner" cuando no debes.
Con inner, pierdes todas las filas que no tienen pareja en la otra tabla. En análisis de ventas, esto puede hacerte pensar que tienes menos registros de los que realmente existen. Cuando tengas dudas, empieza con how="left" y revisa los NaN resultantes.
Resumen de parámetros útiles
| Parámetro | Función | Ejemplo |
|---|---|---|
on |
Llave común en ambas tablas | on="id_producto" |
left_on / right_on |
Llaves con nombres distintos | left_on="num", right_on="id" |
how |
Tipo de unión | how="left" |
suffixes |
Renombra columnas duplicadas | suffixes=("_ventas", "_cat") |
ignore_index |
Reinicia índice en concat | ignore_index=True |
axis |
Dirección del apilado | axis=0 (filas) |
Puntos clave
- Usa
merge()cuando dos tablas comparten una columna llave y necesitas cruzar su información, igual que un JOIN en SQL. - El parámetro
how="left"conserva todos los registros de la tabla izquierda, aunque no tengan pareja en la tabla derecha. - Usa
concat()para apilar DataFrames que tienen la misma estructura, como reportes mensuales o archivos por región. - Siempre usa
ignore_index=Trueal concatenar para evitar índices duplicados. - Antes de hacer un merge, verifica que la columna llave no tenga duplicados inesperados con
value_counts().