Métricas: clasificación, regresión, qué elegir
yardstick: la API unificada
Antes de yardstick, calcular métricas en R era un mosaico: ROCR para curvas ROC, pROC para AUC, fórmulas a mano para RMSE, caret::confusionMatrix para clasificación. Cada uno con su sintaxis.
yardstick unifica todo bajo un patrón consistente: la métrica recibe un data.frame con las columnas de verdad y predicción, y devuelve un valor.
library(tidymodels)
# Patrón base (regresión)
predicciones |>
rmse(truth = real, estimate = .pred)
# Patrón base (clasificación con probabilidades)
predicciones |>
roc_auc(truth = clase, .pred_positivo)Funciona idénticamente sea cual sea la métrica. Si dominas el patrón, todo el catálogo es accesible.
Métricas de clasificación: el zoo
Para clasificación binaria con clase positiva = “Sí”:
| Métrica | Qué mide | Función |
|---|---|---|
| Accuracy | Predicciones correctas / total | accuracy() |
| Precision | Verdaderos positivos / predichos positivos | precision() |
| Recall (Sensitivity) | Verdaderos positivos / reales positivos | recall() |
| Specificity | Verdaderos negativos / reales negativos | specificity() |
| F1 | Media armónica de precision y recall | f_meas() |
| ROC AUC | Área bajo la curva ROC | roc_auc() |
| PR AUC | Área bajo la curva precision-recall | pr_auc() |
| Log-loss | Penalización logarítmica de probabilidades | mn_log_loss() |
Más de 30 funciones en total. El catálogo cubre prácticamente cualquier situación.
Por qué accuracy no basta con clases desbalanceadas
Imagina un detector de fraude con 1 % de positivos. Un modelo que dice “no fraude” siempre tiene:
- Accuracy = 99 %: parece excelente.
- Recall = 0 %: no detecta ningún fraude.
- Precision = NaN (no hay positivos predichos).
- F1 = 0.
Accuracy es engañosa cuando hay clases desbalanceadas. La métrica útil depende del coste de cada tipo de error:
- Si falsos negativos son caros (perder un fraude, no detectar una enfermedad grave): prioriza recall.
- Si falsos positivos son caros (mandar a investigación a un cliente legítimo): prioriza precision.
- Si ambos importan por igual: F1 (la media armónica los balancea).
- Si quieres una vista global: ROC AUC o PR AUC.
ROC AUC vs PR AUC: cuándo cada una
Las dos curvas más usadas para clasificación binaria con probabilidades:
ROC AUC representa true positive rate vs false positive rate al variar el umbral. AUC = 1 es perfecto, AUC = 0.5 es azar.
- Bueno: invariante al desbalanceo de clases en muchos casos.
- Trampa: con clases muy desbalanceadas, ROC AUC puede dar valores engañosamente altos porque el espacio de “negativos correctos” es enorme y dominan la curva.
PR AUC representa precision vs recall al variar el umbral.
- Mejor para clases desbalanceadas porque ignora los verdaderos negativos.
- Trampa: depende de la proporción de la clase positiva, no es comparable directamente entre datasets con distinto balance.
Regla práctica:
- Balance ~50/50: ROC AUC.
- Desbalanceo notable (≤ 10 % de positivos): PR AUC, o reporta ambas.
- Para detectar minoría: PR AUC casi siempre.
predicciones |>
roc_auc(truth = clase, .pred_positivo)
predicciones |>
pr_auc(truth = clase, .pred_positivo)Visualizar las curvas
library(ggplot2)
predicciones |>
roc_curve(truth = clase, .pred_positivo) |>
autoplot()
predicciones |>
pr_curve(truth = clase, .pred_positivo) |>
autoplot()autoplot() da una curva con la diagonal de referencia. Si el modelo está cerca de la diagonal en ROC, predice al azar.
Log-loss y calibración
Log-loss (también llamado cross-entropy) penaliza la distancia entre probabilidad predicha y realidad. Si tu modelo dice “85 % probabilidad de cáncer” y resulta positivo, log-loss penaliza poco. Si dice “5 %” y resulta positivo, penaliza mucho.
predicciones |>
mn_log_loss(truth = clase, .pred_positivo)Cuándo importa: cuando las probabilidades predichas se usan para decidir (no solo la clase). En medicina, un “75 % de probabilidad de enfermedad” debería ocurrir el 75 % de las veces, si tu modelo dice 75 % y solo el 30 % de esos casos son positivos, está mal calibrado aunque clasifique bien.
Para evaluar calibración visualmente:
library(probably)
predicciones |>
cal_plot_breaks(truth = clase, estimate = .pred_positivo)La curva debería estar cerca de la diagonal. Modelos sobreconfiados (gradient boosting, random forest sin calibración) suelen necesitar recalibración (Platt scaling, isotonic regression) si el caso de uso depende de probabilidades.
Métricas de regresión: las tres clásicas
| Métrica | Qué mide | Función | Penaliza |
|---|---|---|---|
| RMSE | Raíz del error cuadrático medio | rmse() |
Errores grandes desproporcionadamente |
| MAE | Error absoluto medio | mae() |
Errores proporcionalmente |
| MAPE | Error absoluto porcentual medio | mape() |
En proporción relativa |
| R² | Proporción de varianza explicada | rsq() |
(Bondad de ajuste, no error) |
Diferencias críticas:
- RMSE > MAE siempre cuando hay errores grandes (RMSE eleva al cuadrado). Si los outliers en error te preocupan más que los típicos, RMSE es la métrica.
- MAE trata todos los errores por igual. Si un error de 100 es exactamente 2× peor que uno de 50 en tu problema, MAE es lo correcto.
- MAPE expresa en porcentaje. Útil cuando las escalas varían: predecir el precio de viviendas con MAPE permite comparar un error en una casa de 100k€ con uno en 1M€. Trampa: indefinida cuando la real es 0. Explota cuando es pequeña.
- R² es la métrica que entiende cualquier audiencia no técnica. Para reporting general, suma R² al RMSE/MAE.
predicciones |>
metrics(truth = real, estimate = .pred)
#> # A tibble: 3 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 rmse standard 2.45
#> 2 rsq standard 0.85
#> 3 mae standard 1.82metrics() aplica un conjunto sensato por defecto (RMSE, RSQ, MAE para regresión. Accuracy y AUC para clasificación).
metric_set(): combinar varias en una llamada
Cuando entrenas con fit_resamples() o tune_grid(), especificas qué métricas calcular:
mis_metricas <- metric_set(roc_auc, pr_auc, f_meas, accuracy)
res <- fit_resamples(
wf,
resamples = folds,
metrics = mis_metricas
)metric_set() agrupa varias en un objeto único. Todas se calculan sobre los mismos folds, así que la comparación entre modelos es directa.
Trampas habituales
- Optimizar para accuracy con clases desbalanceadas. El modelo se desplazará hacia predecir siempre la clase mayoritaria. Si te importan los positivos, usa F1, recall o PR AUC.
- Comparar AUC entre datasets distintos. Una AUC de 0.85 en un dataset desbalanceado y 0.85 en uno balanceado no son lo mismo. La AUC depende del problema.
- Reportar solo el punto sin IC. Cualquier métrica que sale de CV viene con
std_err. Reportar “AUC = 0.82” sin “IC ≈ ±0.04” esconde la incertidumbre real. - Olvidar argumento
event_level. En clasificación binaria,yardstickasume por defecto que el primer nivel del factor es el evento positivo. Si tu factor está al revés (Noprimero,Sísegundo),precision()yrecall()miden la clase incorrecta.event_level = "second"lo corrige.
En la siguiente entrega
Has aprendido a evaluar correctamente. La siguiente pieza es comparar múltiples modelos en paralelo sin escribir cada uno a mano. workflowsets automatiza el cruce recipes × modelos y devuelve un ranking honesto. Lo siguiente.