Machine learning en R: caret y tidymodels para entrenar y evaluar modelos

R tiene dos frameworks principales para machine learning: caret, el clásico que lleva más de quince años en activo y da acceso a más de 200 algoritmos con una interfaz unificada, y tidymodels, el sucesor moderno que sigue la filosofía del tidyverse y separa limpiamente el preprocesamiento, el modelado y la evaluación. Ambos siguen siendo útiles, pero tidymodels es la apuesta de Posit para el futuro.

caret: el framework clásico

caret (Classification And REgression Training) lleva desde 2007 siendo el pegamento entre los miles de paquetes de ML que existen en R. Su función train() permite cambiar de algoritmo simplemente cambiando el argumento method, sin reaprender la sintaxis:

library(caret)

# Datos de ejemplo: clasificación binaria
data(Sonar, package = "mlbench")

# Dividir en train/test
set.seed(42)
idx   <- createDataPartition(Sonar$Class, p = 0.75, list = FALSE)
train <- Sonar[idx, ]
test  <- Sonar[-idx, ]

# Configurar validación cruzada
ctrl <- trainControl(
  method          = "cv",
  number          = 10,
  classProbs      = TRUE,
  summaryFunction = twoClassSummary,
  savePredictions = "final"
)

# Entrenar random forest
mod_rf <- train(
  Class ~ .,
  data      = train,
  method    = "rf",
  metric    = "ROC",
  trControl = ctrl,
  ntree     = 200
)

# El mismo código con otro algoritmo
mod_xgb <- train(
  Class ~ .,
  data      = train,
  method    = "xgbTree",
  metric    = "ROC",
  trControl = ctrl
)

print(mod_rf)

Evaluación y comparación

# Predicción sobre test
pred_rf  <- predict(mod_rf,  newdata = test)
pred_xgb <- predict(mod_xgb, newdata = test)

# Matriz de confusión con métricas
confusionMatrix(pred_rf, test$Class, positive = "M")

# Comparar modelos
resultados <- resamples(list(RF = mod_rf, XGB = mod_xgb))
summary(resultados)
dotplot(resultados)  # gráfico de comparación

tidymodels: el framework moderno

tidymodels separa las responsabilidades en paquetes distintos que trabajan juntos: rsample para dividir datos y validación cruzada, recipes para preprocesamiento, parsnip para definir modelos, workflows para combinar receta y modelo, y tune para ajuste de hiperparámetros.

library(tidymodels)

# 1. Dividir datos
set.seed(42)
split  <- initial_split(Sonar, prop = 0.75, strata = Class)
train  <- training(split)
test   <- testing(split)
folds  <- vfold_cv(train, v = 10, strata = Class)

# 2. Receta de preprocesamiento
receta <- recipe(Class ~ ., data = train) |>
  step_normalize(all_numeric_predictors()) |>
  step_nzv(all_predictors()) |>
  step_corr(all_numeric_predictors(), threshold = 0.9)

# 3. Especificación del modelo
mod_spec <- rand_forest(
  mtry  = tune(),
  trees = tune(),
  min_n = tune()
) |>
  set_engine("ranger") |>
  set_mode("classification")

# 4. Workflow: receta + modelo
wf <- workflow() |>
  add_recipe(receta) |>
  add_model(mod_spec)

# 5. Ajuste de hiperparámetros
grid <- grid_random(
  mtry(range  = c(5, 30)),
  trees(range = c(100, 500)),
  min_n(range = c(2, 20)),
  size = 20
)

resultados_tune <- tune_grid(
  wf,
  resamples = folds,
  grid      = grid,
  metrics   = metric_set(roc_auc, accuracy, f_meas)
)

# Ver mejores combinaciones
show_best(resultados_tune, metric = "roc_auc")
autoplot(resultados_tune)

Ajuste final y evaluación

# Seleccionar la mejor combinación
mejor <- select_best(resultados_tune, metric = "roc_auc")

# Actualizar el workflow con los mejores hiperparámetros
wf_final <- finalize_workflow(wf, mejor)

# Ajustar sobre todos los datos de train y evaluar en test
resultado_final <- last_fit(wf_final, split)

# Métricas en test
collect_metrics(resultado_final)

# Predicciones en test
predicciones <- collect_predictions(resultado_final)

# Curva ROC
predicciones |>
  roc_curve(Class, .pred_M) |>
  autoplot()

# Matriz de confusión
conf_mat(predicciones, truth = Class, estimate = .pred_class) |>
  autoplot(type = "heatmap")

Guardar y reutilizar modelos

# Extraer el modelo final ajustado
modelo_listo <- extract_workflow(resultado_final)

# Guardar para producción
saveRDS(modelo_listo, "modelo_sonar_v1.rds")

# Cargar y predecir
modelo_cargado <- readRDS("modelo_sonar_v1.rds")
nuevos <- Sonar[1:5, -61]  # primeras 5 filas sin la respuesta
predict(modelo_cargado, new_data = nuevos, type = "prob")

Cuándo usar caret y cuándo tidymodels

caret tiene más historia y documentación. Si llevas tiempo usándolo o heredas código que lo usa, no hay razón urgente para migrar. tidymodels es más limpio conceptualmente, se integra mejor con el resto del tidyverse y tiene mejor soporte para técnicas modernas de validación. Para proyectos nuevos, tidymodels es la opción recomendada.

Hay que decirlo sin rodeos: R en machine learning no compite con Python en deep learning ni en infraestructura de producción. Pero para modelos tabulares clásicos (random forest, gradient boosting, SVM, regresión regularizada), tidymodels ofrece una experiencia muy completa. Para los modelos estadísticos base sobre los que se construye todo esto, puedes revisar el artículo sobre regresión lineal y GLMs en R. Si te interesa comparar con el ecosistema de Julia para ML, tenemos el artículo de Julia para ciencia de datos.

Imagen: Pexels / Pavel Danilyuk

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP