Joins y Combinaciones
Combinar tablas en claves compartidas es donde ocurren la duplicación silenciosa de filas y la pérdida de registros. merge y concat de pandas requieren tipos de unión explícitos y validación.
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
import pandas as pd
merged = left.merge(
right,
on="order_id",
how="left",
validate="many_to_one",
indicator=True,
)
unmatched = merged.loc[merged["_merge"] == "left_only"]Cuándo usar esto:
- Enriquecer tablas de hechos con atributos de dimensión
- Unir respuestas de API de múltiples puntos de conexión
- Unir particiones mensuales de Parquet verticalmente
- Construir conjuntos de entrenamiento a partir de tablas de características + etiquetas
Ejemplo de Trabajo
import pandas as pd
orders = pd.DataFrame(
{"order_id": [1, 2, 3], "customer_id": [10, 11, 10], "amount": [120, 340, 80]}
)
customers = pd.DataFrame(
{"customer_id": [10, 11], "segment": ["SMB", "Enterprise"]}
)
refunds = pd.DataFrame({"order_id": [2], "refund": [50.0]})
# Enriquecimiento de dimensión - se espera 1:1 o muchos:1
enriched = orders.merge(
customers,
on="customer_id",
how="left",
validate="many_to_one",
)
# Extensión de hechos - los reembolsos pueden faltar
with_refunds = enriched.merge(
refunds,
on="order_id",
how="left",
validate="one_to_one",
)
with_refunds["refund"] = with_refunds["refund"].fillna(0.0)
with_refunds["net"] = with_refunds["amount"] - with_refunds["refund"]
# Auditoría de cobertura de la combinación
audit = orders.merge(customers, on="customer_id", how="left", indicator=True)
missing_customers = audit.loc[audit["_merge"] == "left_only"]
print(with_refunds)
print("filas de clientes faltantes:", len(missing_customers))Lo que esto demuestra:
validatepara afirmar las expectativas de cardinalidad- Unión izquierda que preserva todos los pedidos
indicator=Truepara la detección de huérfanos- Rellenar NA después de la unión izquierda para hechos opcionales
Inmersión Profunda
Cómo Funciona
mergerealiza uniones estilo base de datos en claves de columna (hash o sort-merge).howcontrola qué claves sobreviven: inner, left, right, outer.validatelanza un error si la cardinalidad real viola la relación declarada.concatapila a lo largo del eje 0 (filas) o 1 (columnas) sin alineación de claves.
Tipos de Unión
| how | Mantiene |
|---|---|
| inner | Claves en ambos |
| left | Todas las claves izquierdas |
| right | Todas las claves derechas |
| outer | Unión de claves |
Notas de Python
import pandas as pd
# Nombres de columna diferentes
pd.merge(orders, regions, left_on="region_id", right_on="id")
# Unir archivos mensuales con columnas consistentes
pd.concat([jan, feb], ignore_index=True)Peligros
- Combinación de muchos a muchos - las duplicaciones explotan el recuento de filas multiplicativamente. Solución: eliminar duplicados de claves primero o usar
validate="m:m"a sabiendas con comprobaciones de recuento de filas. - Desajuste de tipo de datos de clave -
int64vsobject"1" produce una combinación vacía. Solución: usarastypeen las claves de ambos lados antes de la combinación. - Nombres de columna duplicados - los sufijos son
_x/_ypor defecto. Solución:suffixes=("", "_dim")y eliminar columnas redundantes. - Combinación accidental en el índice -
on=olvidado combina en el índice si está alineado. Solución:reset_index()o indicadores explícitosleft_index. concatsinignore_index- preserva etiquetas de fila duplicadas. Solución:ignore_index=Trueo índice jerárquico por fuente.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
DuckDB read_parquet + SQL | Combinaciones complejas de múltiples tablas | Dos marcos pequeños en memoria |
Polars join | Combinaciones perezosas grandes | Ya inmerso en el pipeline de pandas |
DataFrame.join | Tablas anchas alineadas por índice | Columnas clave no en el índice |
| ETL de base de datos | Los datos ya viven en el almacén de datos | Exploración solo en notebooks |
Preguntas Frecuentes
¿Cómo detecto una explosión de muchos a muchos?
assert len(merged) == len(left) # para muchos a uno- Compara
lenantes/después; investiga si el producto crece.
¿Cuándo usar concat vs merge?
concat: mismo esquema, apilar períodos o fragmentos.merge: tablas diferentes que comparten claves.
¿Cómo combino en múltiples claves?
left.merge(right, on=["region", "month"])¿Qué hace indicator=True?
- Añade la columna
_merge:left_only,right_only,both. - Señal rápida de calidad de datos después de uniones izquierdas.
¿Cómo hago una anti-unión (filas en la izquierda no en la derecha)?
left.merge(right, on="id", how="left", indicator=True).query("_merge == 'left_only'")¿Debo establecer índices antes de la unión?
- No es necesario -
on=es más claro para la mayoría de los análisis. - Las uniones de índices ayudan a las uniones repetidas en la misma clave en bucles ajustados.
¿Cómo combino series de tiempo asof?
pd.merge_asof(trades.sort_values("ts"), quotes.sort_values("ts"), on="ts")- Selecciona la cotización anterior más cercana por marca de tiempo de operación.
¿Puedo combinar con diferentes granularidades?
- Agregar primero a un grano común (diario vs. por hora).
- Muchos a muchos a menudo significa desajuste de grano.
¿Cómo elimino filas de clave duplicadas?
right = right.drop_duplicates("customer_id", keep="last")¿Merge preserva el orden?
- No garantizado - ordena la salida explícitamente para presentaciones.
Relacionado
- Limpieza y Transformación de Datos - normalizar claves primero
- GroupBy y Agregación - agregar después de enriquecer
- Formatos de Archivo - particiones de Parquet para concatenar
- Mejores Prácticas de Análisis de Datos - uniones reproducibles
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.