En un dataset real, no todas las variables tienen el mismo tipo. Algunas son numéricas, como la edad, el salario o la cantidad de productos comprados. Otras son categóricas, como la ciudad, el tipo de plan o el canal de venta.
Para un ser humano, leer una columna como plan = premium es trivial. Pero un algoritmo de Machine Learning no entiende palabras: necesita números. Por eso, antes de entrenar, debemos decidir cómo transformar cada tipo de variable.
Una variable numérica expresa una cantidad o magnitud. Por ejemplo:
Una variable categórica expresa una categoría o etiqueta. Por ejemplo:
El error clásico de principiante es intentar pasar columnas de texto directamente al modelo. La mayoría de los algoritmos de Scikit-learn no aceptan cadenas como entrada.
Supongamos que tenemos la variable plan con estos valores:
Una mala idea sería convertirlos así:
básico = 1
estándar = 2
premium = 3
Eso hace creer al modelo que existe una distancia numérica natural entre las categorías. En muchos casos, esa relación no existe. Por eso suele preferirse One-Hot Encoding, que crea una columna por categoría.
OneHotEncoder transforma una categoría en varias columnas binarias. Por ejemplo, si una columna canal tiene los valores web, móvil y tienda, el resultado puede quedar así:
canal_web canal_móvil canal_tienda
1 0 0
0 1 0
0 0 1
De este modo, el modelo recibe números sin interpretar que una categoría es “más grande” que otra.
Vamos a trabajar con un dataset pequeño donde combinamos variables numéricas y categóricas:
Usaremos ColumnTransformer para aplicar transformaciones diferentes según el tipo de columna.
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
clientes = pd.DataFrame({
"edad": [22, 25, 27, 30, 35, 40, 45, 50, 28, 33],
"ingresos": [300, 350, 400, 500, 650, 800, 900, 1100, 420, 560],
"canal": ["web", "web", "móvil", "tienda", "web", "móvil", "tienda", "web", "móvil", "tienda"],
"plan": ["básico", "básico", "básico", "estándar", "estándar", "premium", "premium", "premium", "estándar", "premium"],
"compra": [0, 0, 0, 1, 1, 1, 1, 1, 0, 1]
})
X = clientes[["edad", "ingresos", "canal", "plan"]]
y = clientes["compra"]
columnas_numericas = ["edad", "ingresos"]
columnas_categoricas = ["canal", "plan"]
preprocesador = ColumnTransformer(
transformers=[
("num", "passthrough", columnas_numericas),
("cat", OneHotEncoder(handle_unknown="ignore"), columnas_categoricas)
]
)
modelo = Pipeline([
("preprocesamiento", preprocesador),
("clasificador", LogisticRegression(max_iter=1000))
])
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
modelo.fit(X_train, y_train)
y_pred = modelo.predict(X_test)
print("Predicciones:", y_pred)
print("Valores reales:", y_test.values)
print("Exactitud:", accuracy_score(y_test, y_pred))
nuevo_cliente = pd.DataFrame({
"edad": [36],
"ingresos": [700],
"canal": ["web"],
"plan": ["premium"]
})
prediccion = modelo.predict(nuevo_cliente)[0]
probabilidad = modelo.predict_proba(nuevo_cliente)[0, 1]
print("Predicción para el nuevo cliente:", prediccion)
print(f"Probabilidad de compra: {probabilidad:.3f}")
Salida resumida esperada:
Predicciones: [1 0 1]
Valores reales: [1 0 1]
Exactitud: 1.0
Predicción para el nuevo cliente: 1
Probabilidad de compra: 0.7...
columnas_numericas: identifica qué variables pasan al modelo como números.columnas_categoricas: identifica qué variables necesitan codificación.OneHotEncoder(handle_unknown="ignore"): transforma categorías en columnas binarias y evita errores si aparece una categoría nueva en predicción.ColumnTransformer(...): permite aplicar una transformación a las columnas numéricas y otra distinta a las categóricas.Pipeline([...]): une el preprocesamiento y el modelo en un solo flujo ordenado.modelo.fit(...): primero transforma los datos y luego entrena la regresión logística.modelo.predict(...): cuando llega un nuevo caso, aplica automáticamente la misma preparación y luego predice.Cuando un dataset mezcla tipos de columnas, intentar preparar todo manualmente se vuelve incómodo y propenso a errores. ColumnTransformer resuelve esto de forma limpia:
Pipeline;En proyectos reales, esta forma de trabajar es mucho más segura que transformar columnas “a mano” en distintos momentos del flujo.
Un error común consiste en transformar una columna categórica con reglas improvisadas o distintas entre entrenamiento y predicción. Por ejemplo, si hoy codificamos web = 0 y mañana cambiamos el criterio, el modelo recibirá información inconsistente.
La solución práctica es clara:
Por eso Pipeline y ColumnTransformer suelen usarse juntos.
OneHotEncoder convierte categorías en columnas binarias sin imponer un orden numérico artificial.ColumnTransformer permite combinar transformaciones diferentes en un mismo dataset.Pipeline asegura que el mismo preprocesamiento se repita al entrenar y al predecir.