En la lección anterior aprendimos con qué datos evaluar un modelo; ahora toca decidir con qué número. Hasta el momento hemos usado el accuracy (clasificación) y el MSE (regresión) de forma instrumental, sin cuestionarlos. Eso se acaba aquí: veremos que el accuracy puede ser una trampa descarada con clases desbalanceadas —el churn de MercaFresh ronda el 20 %—, que la matriz de confusión distingue tipos de error con costes de negocio muy distintos (¿qué es peor: llamar a un cliente fiel o perder a uno que se iba a marchar?), y que en regresión conviven varias métricas (MAE, MSE, RMSE, R²) con interpretaciones y unidades diferentes. Cerraremos con los modelos dummy, la materialización en scikit-learn del concepto de baseline que introdujimos en la lección 01-04: ninguna métrica significa nada en el vacío; solo significa algo comparada con una referencia.
Contenido
- La matriz de confusión: los cuatro destinos de una predicción
- Accuracy y su trampa con el desbalanceo
- Precision, recall y F1: fórmulas e interpretación de negocio
classification_reporty elección de métrica según el problema- Métricas de regresión: MAE, MSE, RMSE y R²
- El baseline: DummyClassifier y DummyRegressor
La matriz de confusión: los cuatro destinos de una predicción
En un problema binario como el churn (1 = el cliente se da de baja, 0 = se queda), cada predicción puede acabar en uno de cuatro destinos, según lo que predijo el modelo y lo que ocurrió en realidad:
| Predicho: churn (1) | Predicho: se queda (0) | |
|---|---|---|
| Real: churn (1) | TP (verdadero positivo) | FN (falso negativo) |
| Real: se queda (0) | FP (falso positivo) | TN (verdadero negativo) |
- TP (true positive): predijimos churn y el cliente efectivamente se fue. Acierto.
- TN (true negative): predijimos que se quedaba y se quedó. Acierto.
- FP (falso positivo): predijimos churn, pero el cliente era fiel. Es la "falsa alarma": MercaFresh gasta una llamada y quizá un descuento en alguien que no se iba a marchar.
- FN (falso negativo): predijimos que se quedaba y se fue. El error más caro aquí: perdemos al cliente sin haber intentado retenerlo.
Esto no es nuevo para ti: en la lección 02-05, con el teorema de Bayes, analizamos un detector con falsos positivos y vimos que el coste de cada tipo de error es distinto y que con eventos poco frecuentes las falsas alarmas pueden dominar. La matriz de confusión es exactamente ese análisis, aplicado a un clasificador.
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y # como en 06-01
)
modelo = LogisticRegression(max_iter=1000)
modelo.fit(X_train, y_train)
y_pred = modelo.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
print(cm)
# [[TN FP]
# [FN TP]] ← ojo: sklearn ordena las clases 0, 1 (filas = real, columnas = predicho)
ConfusionMatrixDisplay(cm, display_labels=["Se queda", "Churn"]).plot()Supongamos que sobre 2.000 clientes de test obtenemos:
| Pred: churn | Pred: se queda | |
|---|---|---|
| Real: churn (400) | TP = 240 | FN = 160 |
| Real: se queda (1.600) | FP = 120 | TN = 1.480 |
Toda métrica de clasificación binaria se calcula a partir de estos cuatro números.
Accuracy y su trampa con el desbalanceo
El accuracy es la fracción de aciertos totales:
$$\text{accuracy} = \frac{TP + TN}{TP + TN + FP + FN} = \frac{240 + 1480}{2000} = 0.86$$
Un 86 % suena bien... hasta que recordamos el desbalanceo. Con un churn del 20 %, un "modelo" absurdo que prediga siempre "se queda" acierta el 80 % de las veces:
import numpy as np
y_pred_vago = np.zeros_like(y_test) # siempre predice "se queda"
print((y_pred_vago == y_test).mean()) # ≈ 0.80Ese modelo tiene un 80 % de accuracy y es completamente inútil: no detecta ni un solo cliente en fuga (TP = 0). La trampa se agrava cuanto mayor es el desbalanceo: en detección de fraude con un 1 % de positivos, "nunca hay fraude" alcanza un 99 % de accuracy. Moraleja: con clases desbalanceadas, el accuracy por sí solo engaña; necesitamos métricas que miren cada clase por separado.
Precision, recall y F1: fórmulas e interpretación de negocio
Precision: cuando el modelo da la alarma, ¿acierta?
$$\text{precision} = \frac{TP}{TP + FP} = \frac{240}{240 + 120} = 0.67$$
De todos los clientes que el modelo señaló como churn, ¿qué fracción se iba de verdad? En MercaFresh: si el equipo de retención llama a los señalados, la precision mide qué porcentaje de llamadas no se desperdicia. Una precision baja significa muchas falsas alarmas: coste de campaña tirado en clientes fieles (y el riesgo de molestarlos).
Recall: de los que se van, ¿a cuántos cazamos?
$$\text{recall} = \frac{TP}{TP + FN} = \frac{240}{240 + 160} = 0.60$$
De todos los clientes que realmente se dieron de baja, ¿qué fracción detectó el modelo? Un recall del 60 % significa que el 40 % de las fugas reales pasan desapercibidas: clientes que se pierden sin que nadie intentara retenerlos. También se llama sensibilidad o tasa de verdaderos positivos (con ese nombre reaparecerá en la curva ROC de 06-04).
El tira y afloja, y la pregunta de negocio
Precision y recall están en tensión: para subir el recall hay que señalar a más clientes (alarma más sensible), lo que genera más falsos positivos y baja la precision, y viceversa. ¿Cuál priorizar? Depende de los costes:
- Coste de un FP: una llamada del equipo de retención más, quizá, un vale de 10 €. Barato.
- Coste de un FN: perder un cliente cuyo valor anual medio en MercaFresh puede ser de cientos de euros. Caro.
Con esta estructura de costes, en el churn suele interesar priorizar el recall: mejor unas cuantas llamadas de más que clientes valiosos escapándose en silencio. En otros problemas es al revés (un filtro de spam con precision baja entierra correos legítimos). En 06-04 veremos que el umbral de decisión de la regresión logística (04-02) es precisamente la palanca para mover este equilibrio.
F1: el resumen en un número
Cuando se necesita una sola cifra que combine ambas, se usa la media armónica de precision y recall:
$$F_1 = 2 \cdot \frac{\text{precision} \cdot \text{recall}}{\text{precision} + \text{recall}} = 2 \cdot \frac{0.67 \cdot 0.60}{0.67 + 0.60} \approx 0.63$$
La media armónica castiga los desequilibrios: si una de las dos es próxima a 0, el F1 se hunde aunque la otra sea perfecta (a diferencia de la media aritmética). Un modelo solo tiene buen F1 si es razonable en ambas.
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
print("Accuracy :", accuracy_score(y_test, y_pred))
print("Precision:", precision_score(y_test, y_pred))
print("Recall :", recall_score(y_test, y_pred))
print("F1 :", f1_score(y_test, y_pred))classification_report y elección de métrica según el problema
scikit-learn resume todo lo anterior, por clase, en una sola llamada:
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred, target_names=["Se queda", "Churn"])) precision recall f1-score support
Se queda 0.90 0.93 0.91 1600
Churn 0.67 0.60 0.63 400
accuracy 0.86 2000
macro avg 0.78 0.76 0.77 2000
weighted avg 0.85 0.86 0.86 2000Cómo leerlo:
- Cada fila da precision/recall/F1 tratando esa clase como "positiva".
supportes cuántos ejemplos reales hay de esa clase en el test. macro avg: media simple de las clases (todas pesan igual, útil con desbalanceo para no ocultar la clase minoritaria).weighted avg: media ponderada porsupport(con desbalanceo se parece al accuracy y puede maquillar una clase minoritaria mala).- Fíjate en que la clase mayoritaria luce un 0.91 de F1 mientras el churn se queda en 0.63: el informe por clases destapa lo que el accuracy global escondía.
¿Qué métrica elegir? Una guía práctica:
| Situación | Métrica principal | Por qué |
|---|---|---|
| Clases equilibradas, errores de coste similar | Accuracy | Simple y suficiente |
| El coste alto es la falsa alarma (spam, bloquear compras legítimas) | Precision | Minimizar FP |
| El coste alto es el positivo no detectado (churn, diagnóstico, fraude) | Recall | Minimizar FN |
| Desbalanceo y se quiere un solo número equilibrado | F1 | Combina P y R |
| Comparar modelos independientemente del umbral | ROC-AUC | Lección 06-04 |
Métricas de regresión: MAE, MSE, RMSE y R²
Cambiamos de problema: la predicción del gasto mensual de cada cliente de MercaFresh, la regresión que planteamos en 04-01. Aquí no hay aciertos y fallos, sino distancias entre lo predicho ($\hat{y}_i$) y lo real ($y_i$).
- MAE (error absoluto medio): $\frac{1}{n}\sum |y_i - \hat{y}_i|$. Se lee directamente en las unidades del target: "nos equivocamos, de media, en 18 € al mes". Trata todos los errores por igual.
- MSE (error cuadrático medio): $\frac{1}{n}\sum (y_i - \hat{y}_i)^2$. Al elevar al cuadrado, castiga mucho más los errores grandes (un error de 100 € pesa como 100 errores de 10 €) y sus unidades son €², poco interpretables. Es la métrica que la regresión lineal minimiza internamente (04-01).
- RMSE: $\sqrt{MSE}$. Recupera las unidades originales (€) manteniendo la sensibilidad a errores grandes. Siempre RMSE ≥ MAE; una brecha grande entre ambos delata la existencia de errores puntuales enormes (outliers).
- R² (coeficiente de determinación): fracción de la varianza del target que el modelo explica. 1.0 = predicción perfecta; 0.0 = tan bueno como predecir siempre la media; puede ser negativo en test si el modelo es peor que la media. Es adimensional, lo que permite comparar problemas con escalas distintas.
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np
reg = LinearRegression().fit(X_train_g, y_train_g) # gasto mensual (€)
y_pred_g = reg.predict(X_test_g)
mae = mean_absolute_error(y_test_g, y_pred_g)
mse = mean_squared_error(y_test_g, y_pred_g)
rmse = np.sqrt(mse)
r2 = r2_score(y_test_g, y_pred_g)
print(f"MAE : {mae:.2f} € ← error medio 'típico'")
print(f"MSE : {mse:.2f} €² ← difícil de interpretar directamente")
print(f"RMSE: {rmse:.2f} € ← como MAE pero penaliza errores grandes")
print(f"R² : {r2:.3f} ← fracción de varianza explicada")| Métrica | Unidades | Sensible a outliers | Cuándo preferirla |
|---|---|---|---|
| MAE | Las del target (€) | No especialmente | Interpretación directa; errores grandes no son "peores por unidad" |
| MSE | Target² (€²) | Mucho | Optimización interna; comparación técnica |
| RMSE | Las del target (€) | Mucho | Reportar cuando los errores grandes son especialmente costosos |
| R² | Sin unidades | Moderada | Comunicar "cuánto explica" el modelo; comparar datasets |
En MercaFresh, un MAE de 18 € sobre un gasto medio de 120 € mensuales (~15 % de error relativo) es un mensaje que el negocio entiende de inmediato; un MSE de 850 €² no.
El baseline: DummyClassifier y DummyRegressor
En la lección 01-04 introdujimos el concepto de baseline: antes de celebrar cualquier métrica, hay que preguntarse "¿mejor que qué?". scikit-learn lo materializa con modelos deliberadamente tontos:
from sklearn.dummy import DummyClassifier, DummyRegressor
from sklearn.metrics import f1_score, mean_absolute_error
# Clasificación: predecir siempre la clase mayoritaria ("se queda")
dummy_clf = DummyClassifier(strategy="most_frequent")
dummy_clf.fit(X_train, y_train)
print("Accuracy dummy:", dummy_clf.score(X_test, y_test)) # ≈ 0.80
print("F1 dummy :", f1_score(y_test, dummy_clf.predict(X_test))) # 0.0 !
# Regresión: predecir siempre el gasto medio
dummy_reg = DummyRegressor(strategy="mean")
dummy_reg.fit(X_train_g, y_train_g)
print("MAE dummy:", mean_absolute_error(y_test_g, dummy_reg.predict(X_test_g)))La lectura es reveladora: el dummy alcanza un 80 % de accuracy (¡la trampa del desbalanceo, cuantificada!) pero un F1 de 0 en la clase churn. Nuestro modelo real, con 86 % de accuracy, solo mejora al dummy en 6 puntos de accuracy... pero pasa de 0.0 a 0.63 de F1, que es donde está el valor real. Reglas prácticas:
- Calcula siempre el baseline dummy antes de evaluar tu primer modelo.
- Reporta las métricas de tu modelo junto a las del baseline: "MAE de 18 € frente a 41 € del baseline de la media" es un resultado; "MAE de 18 €" a secas, no.
- Si tu modelo no supera claramente al dummy, algo falla: features sin señal, fuga en dirección contraria, un bug... o un problema que simplemente no se puede predecir con esos datos.
Errores Comunes y Consejos
- Reportar solo accuracy con clases desbalanceadas. Es el error estrella. Acompáñalo siempre de la matriz de confusión y del F1 (o precision/recall) de la clase minoritaria.
- Confundir precision con recall. Truco mnemotécnico: precision = de mis predicciones positivas, ¿cuántas eran correctas?; recall = de los positivos reales, ¿cuántos recuperé?
- Elegir la métrica después de ver los resultados. Decidir "mi métrica es la que me sale mejor" es autoengaño. Fija la métrica (con el negocio) antes de comparar modelos.
- Interpretar el MSE en unidades del target. El MSE está en unidades al cuadrado; para comunicar usa MAE o RMSE.
- Asumir que R² alto = modelo útil. Un R² de 0.95 con fuga de datos (06-01) no vale nada; y un R² de 0.3 puede ser valiosísimo en un problema muy ruidoso, si supera con claridad al baseline.
- Consejo: la matriz de confusión es tu radiografía por defecto: casi cualquier duda sobre un clasificador binario ("¿dónde falla?, ¿a quién confunde?") se responde mirándola antes que a ninguna métrica agregada.
Ejercicios
Ejercicio 1
Un modelo de churn evaluado sobre 1.000 clientes (200 churn reales) produce: TP = 150, FN = 50, FP = 100, TN = 700. Calcula a mano accuracy, precision, recall y F1. ¿Qué accuracy tendría el dummy de clase mayoritaria? ¿Merece la pena el modelo?
Ejercicio 2
MercaFresh evalúa dos modelos de gasto mensual. Modelo A: MAE = 15 €, RMSE = 45 €. Modelo B: MAE = 18 €, RMSE = 22 €. Explica qué revela la diferencia entre MAE y RMSE de cada modelo y razona cuál elegirías si los errores grandes de predicción (p. ej., infraestimar en 200 € el gasto de un gran cliente) son especialmente costosos.
Ejercicio 3
Escribe el código que entrena una LogisticRegression y un DummyClassifier(strategy="most_frequent") sobre X_train, y_train (churn), y para ambos imprime el classification_report sobre test. Indica qué dos números del informe compararías para decidir si el modelo aporta valor.
Soluciones
Solución 1.
- Accuracy = (150 + 700) / 1000 = 0.85
- Precision = 150 / (150 + 100) = 0.60
- Recall = 150 / (150 + 50) = 0.75
- F1 = 2 · (0.60 · 0.75) / (0.60 + 0.75) = 0.9 / 1.35 ≈ 0.67
- Dummy mayoritario: acierta los 800 "se queda" → accuracy = 0.80.
El modelo solo gana 5 puntos de accuracy al dummy, pero eso es engañoso a favor del dummy: el modelo detecta el 75 % de las fugas reales (el dummy, el 0 %). Con el coste asimétrico del churn (perder un cliente ≫ una llamada de más), sí merece la pena, y el recall de 0.75 con precision 0.60 es un compromiso razonable para una campaña de retención.
Solución 2. La brecha RMSE − MAE mide cuánto pesan los errores grandes. El modelo A tiene mejor error típico (MAE 15 < 18) pero un RMSE triple que su MAE (45 vs. 15): comete errores puntuales muy grandes. El modelo B es algo peor "en el día a día" pero sus errores son homogéneos (22 vs. 18: sin catástrofes). Si los errores grandes son especialmente costosos, se elige el modelo B: sacrifica 3 € de error medio a cambio de eliminar los fallos extremos.
Solución 3.
from sklearn.linear_model import LogisticRegression
from sklearn.dummy import DummyClassifier
from sklearn.metrics import classification_report
modelo = LogisticRegression(max_iter=1000).fit(X_train, y_train)
dummy = DummyClassifier(strategy="most_frequent").fit(X_train, y_train)
for nombre, m in [("Regresión logística", modelo), ("Dummy", dummy)]:
print(f"===== {nombre} =====")
print(classification_report(y_test, m.predict(X_test),
target_names=["Se queda", "Churn"],
zero_division=0))Compararía sobre todo el recall y el F1 de la clase "Churn": en el dummy son 0.0 (no señala a nadie), así que cualquier valor claramente positivo del modelo demuestra que aporta capacidad real de detección, cosa que el accuracy (0.80 vs. ~0.86) apenas deja ver.
Conclusión
Ya sabemos medir: la matriz de confusión separa los cuatro destinos de una predicción y conecta con el análisis de costes de errores que hicimos con Bayes en 02-05; el accuracy engaña con el desbalanceo del churn; precision y recall traducen los errores a lenguaje de negocio (llamadas desperdiciadas frente a clientes perdidos) y el F1 los resume; en regresión, MAE/RMSE hablan en euros y el R² en varianza explicada; y el DummyClassifier/DummyRegressor convierte el baseline de 01-04 en código, dando contexto a cualquier cifra. Pero todas estas métricas las hemos calculado sobre una única división train/test, y esa división depende del azar de una semilla: con otro random_state, otros números. ¿Cómo de fiable es entonces una métrica calculada una sola vez? Esa inquietud tiene nombre y solución —la validación cruzada— y es exactamente el tema de la próxima lección.
Curso de Machine Learning
Módulo 1: Introducción al Machine Learning
- ¿Qué es el Machine Learning?
- Historia y evolución del Machine Learning
- Tipos de Machine Learning
- Aplicaciones del Machine Learning
- El flujo de trabajo de un proyecto de Machine Learning
Módulo 2: Fundamentos de Estadística y Probabilidad
- Conceptos básicos de estadística
- Distribuciones de probabilidad
- Correlación y covarianza
- Inferencia estadística
- Teorema de Bayes
Módulo 3: Preprocesamiento de Datos
- Limpieza de datos
- Manejo de datos faltantes
- Transformación de datos
- Codificación de variables categóricas
- Normalización y estandarización
- Ingeniería de características
Módulo 4: Algoritmos de Machine Learning Supervisado
- Regresión lineal
- Regresión logística
- Árboles de decisión
- Máquinas de soporte vectorial (SVM)
- K-Vecinos más cercanos (K-NN)
- Naive Bayes
- Redes neuronales
Módulo 5: Algoritmos de Machine Learning No Supervisado
- Clustering: K-means
- Clustering jerárquico
- Análisis de componentes principales (PCA)
- Análisis de agrupamiento DBSCAN
- Visualización de datos con t-SNE y UMAP
Módulo 6: Evaluación y Validación de Modelos
- División de datos: entrenamiento, validación y prueba
- Métricas de evaluación
- Validación cruzada
- Curva ROC y AUC
- Overfitting y underfitting
Módulo 7: Técnicas Avanzadas y Optimización
- Regularización: Ridge, Lasso y Elastic Net
- Ensemble Learning
- Gradient Boosting
- Redes neuronales profundas (Deep Learning)
- Optimización de hiperparámetros
Módulo 8: Implementación y Despliegue de Modelos
- Frameworks y bibliotecas populares
- Implementación de modelos en producción
- Mantenimiento y monitoreo de modelos
- Consideraciones éticas y de privacidad
Módulo 9: Proyectos Prácticos
- Proyecto 1: Predicción de precios de viviendas
- Proyecto 2: Clasificación de imágenes
- Proyecto 3: Análisis de sentimientos en redes sociales
- Proyecto 4: Detección de fraudes
- Proyecto 5: Segmentación de clientes
