ggplot(grasa_ent, aes(x = 2.54 * estatura, y = 0.454 * peso)) +
geom_point() + xlab("Estatura (cm)") + ylab("Peso (kg)")
11 Entrenamiento, Validación y Prueba
El enfoque que vimos arriba, en donde dividemos la muestra en dos partes al azar, es la manera más fácil de seleccionar modelos. En general, el proceso es el siguiente:
- Una parte con los que ajustamos todos los modelos que nos interesa. Esta es la muestra de entrenamiento
- Una parte como muestra de prueba, con el que evaluamos el desempeño de cada modelo ajustado en la parte anterior. En este contexto, a esta muestra se le llama muestra de validación.
- Posiblemente una muestra adicional independiente, que llamamos muestra de prueba, con la que hacemos una evaluación final del modelo seleccionado arriba. Es una buena idea apartar esta muestra si el proceso de validación incluye muchos métodos con varios parámetros afinados (como la \(\lambda\) de regresión ridge).
Cuando tenemos datos abundantes, este enfoque es el usual. Por ejemplo, podemos dividir la muestra en 50-25-25 por ciento. Ajustamos modelos con el primer 50%, evaluamos y seleccionamos con el segundo 25% y finalmente, si es necesario, evaluamos el modelo final seleccionado con la muestra final de 25%.
La razón de este proceso es que así podemos ir y venir entre entrenamiento y validación, buscando mejores enfoques y modelos, y no ponemos en riesgo la estimación final del error, o evaluación de calibración de intervalos o probabilidades. (Pregunta: ¿por qué probar agresivamente buscando mejorar el error de validación podría ponder en riesgo la estimación final del error del modelo seleccionado? )
Pudes ver el ejemplo anterior donde usamos esta estrategia para evaluar distintos valores de \(\lambda\).
- No hay una regla general para decidir el tamaño del conjunto de entrenamiento. Generalmente conjuntos de datos más grandes y seleccionados apropiadamente dan mejores resultados.
- Los conjuntos de validación y prueba deben ser preferentemente muestras aleatorias de las poblaciones para las que queremos hacer predicciones, para tener una estimación razonable (no sesgada por ejemplo) del desempeño futuro de nuestro modelo.
- En cuanto a tamaño, en validación y prueba requerimos que sean de tamaño suficiente para tener una estimación con precisión suficientemente buena del error y del desempeño predictivo general de nuestros modelos (en el proceso de selección, con el conjunto de validación, y en la evaluación final, con el conjunto de prueba).
- En validación y prueba, estamos haciendo una pregunta de inferencia: ¿de qué tamaño y bajo que diseño debe ser extraida la muestra de validación y prueba?
Por ejemplo: supongamos que hacemos un modelo para predecir impago. Quizá nuestro conjunto de entrenamiento tiene pocas personas de cierta región del país. Esto no quiere decir que no podamos aplicar nuestros métodos, siempre y cuando nuestra muesra de validación/prueba tenga suficientes ejemplos para asegurarnos de que nuestro desempeño no es malo en esas regiones (y por tanto produce resultados indeseables en la toma de decisiones).
Para decidir de antemano los tamaños de validación y prueba, tenemos que tener una idea de qué tanto varía el error de caso a caso (la varianza), si queremos hacer estimaciones en subgrupos de datos (que requerirán tamaño de muestra suficiente también), y cuánto es aceptable como error de estimación del desempeño predictivo, que generalmente no queremos que sea más del 25%, por ejemplo. En caso de usar muestras relativamente chicas de validación o prueba, es necesario estimar el error de estimación del desempeño.
11.1 Validación cruzada
En muchos casos, no queremos apartar una muestra de validación para seleccionar modelos, pues no tenemos muchos datos (al dividir la muestra obtendríamos un modelo relativamente malo en relación al que resulta de todos los datos, o obtendríamos un modelo que no podemos evaluar apropiadamente).
Un criterio para afinar hiperparámetros (como regularización) es el de validación cruzada, que es un método computacional para producir una estimación interna (usando sólo muestra de entrenamiento) del error de predicción.
Validación cruzada también tiene nos da diagnósticos adicionales para entender la variación del desempeño según el conjunto de datos de entrenamiento que usemos, algo que es más difícil ver si solo tenemos una muestra de validación.
En validación cruzada (con \(k\) vueltas), construimos al azar una partición, con tamaños similares, de la muestra de entrenamiento \({\mathcal L}=\{ (x_i,y_i)\}_{i=1}^n\):
\[ {\mathcal L}={\mathcal L}_1\cup {\mathcal L}_2\cup\cdots\cup {\mathcal L}_k.\]
Construimos \(k\) modelos distintos, digamos \(\hat{f}_j\), usando solamente la muestra \({\mathcal L}-{\mathcal L}_j\), para \(j=1,2,\ldots, k\). Cada uno de estos modelos lo evaluamos usando la parte que no usamos para entrenarlo, \({\mathcal L}_j\), para obtener una estimación honesta del error del modelo \(\hat{f}_k\), a la que denotamos por \(\hat{e}_j\).
Notemos entonces que tenemos \(k\) estimaciones del error \(\hat{e}_1,\ldots, \hat{e}_k\), una para cada uno de los modelos que construimos. La idea ahora es que
- Cada uno de los modelos \(\hat{f}_j\) es similar al modelo ajustado con toda la muestra \(\hat{f}\), de forma que podemos pensar que cada una de las estimaciones \(\hat{e}_j\) es un estimador del error de \(\hat{f}\).
- Dado el punto anterior, podemos construir una mejor estimación promediando las \(k\) estimaciones anteriores, para obtener: \[\widehat{cv} = \frac{1}{k} \sum_{j=1}^k \hat{e}_j.\]
- ¿Cómo escoger \(k\)? Usualmente se usan \(k=5,10,20\), y \(k=10\) es el más popular. La razón es que cuando \(k\) es muy chico, tendemos a evaluar modelos construidos con pocos datos (comparado al modelo con todos los datos de entrenamiento). Por otra parte, cuando \(k\) es grande el método puede ser muy costoso (por ejemplo, si \(k=N\), hay que entrenar un modelo para cada dato de entrada).
11.2 Ejemplo
Consideremos nuestro problema de predicción de grasa corporal. Definimos el flujo de procesamiento, e indicamos qué parametros queremos afinar:
Examinamos brevemente los datos
Y observamos un datos que es probablemente un error de captura, o quizá una forma de cuerpo para la que no necesariamente quisiéramos hacer predicciones con nuestro modelo. Incluímos este filtro en nuestra receta:
<- recipe(grasacorp ~ ., grasa_ent) |>
grasa_receta step_filter(estatura < 120)
# con tune() indicamos que ese parámetro será afinado
<- linear_reg(mixture = 0, penalty = tune()) |>
modelo_regularizado set_engine("glmnet", lambda.min.ratio = 1e-20)
<- workflow() |>
flujo_reg add_model(modelo_regularizado) |>
add_recipe(grasa_receta)
# construimos conjunto de parámetros
<- parameters(penalty(range = c(-2, 2), trans = log10_trans()))
bf_set # construimos un grid para probar valores individuales
<- grid_regular(bf_set, levels = 50)
bf_grid bf_grid
# A tibble: 50 × 1
penalty
<dbl>
1 0.01
2 0.0121
3 0.0146
4 0.0176
5 0.0212
6 0.0256
7 0.0309
8 0.0373
9 0.0450
10 0.0543
# ℹ 40 more rows
Ya hora construimos los cortes de validación cruzada. Haremos validación cruzada 10
<- vfold_cv(grasa_ent, v = 10)
validacion_particion # tiene información de índices en cada "fold" o "doblez"vuelta"
validacion_particion
# 10-fold cross-validation
# A tibble: 10 × 2
splits id
<list> <chr>
1 <split [113/13]> Fold01
2 <split [113/13]> Fold02
3 <split [113/13]> Fold03
4 <split [113/13]> Fold04
5 <split [113/13]> Fold05
6 <split [113/13]> Fold06
7 <split [114/12]> Fold07
8 <split [114/12]> Fold08
9 <split [114/12]> Fold09
10 <split [114/12]> Fold10
Y corremos sobre todo el grid los modelos, probando con los cortes de validación cruzada:
<- tune_grid(flujo_reg,
metricas_vc resamples = validacion_particion,
grid = bf_grid,
metrics = metric_set(rmse, mae))
|> unnest(.metrics) metricas_vc
# A tibble: 1,000 × 8
splits id penalty .metric .estimator .estimate .config .notes
<list> <chr> <dbl> <chr> <chr> <dbl> <chr> <list>
1 <split [113/13]> Fold01 0.01 rmse standard 3.86 Prepro… <tibble>
2 <split [113/13]> Fold01 0.0121 rmse standard 3.86 Prepro… <tibble>
3 <split [113/13]> Fold01 0.0146 rmse standard 3.86 Prepro… <tibble>
4 <split [113/13]> Fold01 0.0176 rmse standard 3.86 Prepro… <tibble>
5 <split [113/13]> Fold01 0.0212 rmse standard 3.86 Prepro… <tibble>
6 <split [113/13]> Fold01 0.0256 rmse standard 3.86 Prepro… <tibble>
7 <split [113/13]> Fold01 0.0309 rmse standard 3.86 Prepro… <tibble>
8 <split [113/13]> Fold01 0.0373 rmse standard 3.87 Prepro… <tibble>
9 <split [113/13]> Fold01 0.0450 rmse standard 3.87 Prepro… <tibble>
10 <split [113/13]> Fold01 0.0543 rmse standard 3.87 Prepro… <tibble>
# ℹ 990 more rows
Vemos que esta función da un valor del error para cada vuelta de validación cruzada, y cada valor de lambda que pusimos en el grid:
|> unnest(.metrics) |> group_by(id, .metric) |> count() metricas_vc
# A tibble: 20 × 3
# Groups: id, .metric [20]
id .metric n
<chr> <chr> <int>
1 Fold01 mae 50
2 Fold01 rmse 50
3 Fold02 mae 50
4 Fold02 rmse 50
5 Fold03 mae 50
6 Fold03 rmse 50
7 Fold04 mae 50
8 Fold04 rmse 50
9 Fold05 mae 50
10 Fold05 rmse 50
11 Fold06 mae 50
12 Fold06 rmse 50
13 Fold07 mae 50
14 Fold07 rmse 50
15 Fold08 mae 50
16 Fold08 rmse 50
17 Fold09 mae 50
18 Fold09 rmse 50
19 Fold10 mae 50
20 Fold10 rmse 50
Y ahora podemos graficar:
ggplot(metricas_vc |> unnest(.metrics) |> filter(.metric == "rmse"),
aes(x = penalty, y = .estimate)) + geom_point() +
scale_x_log10()
Nótese que para valores bajos de penalización hay variación considerable en el error (los modelos cambian mucho de corrida a corrida). Para resumir, como explicamos arriba, podemos resumir con media y error estándar:
<- metricas_vc |>
metricas_resumen collect_metrics()
metricas_resumen
# A tibble: 100 × 7
penalty .metric .estimator mean n std_err .config
<dbl> <chr> <chr> <dbl> <int> <dbl> <chr>
1 0.01 mae standard 3.94 10 0.312 Preprocessor1_Model01
2 0.01 rmse standard 4.61 10 0.330 Preprocessor1_Model01
3 0.0121 mae standard 3.93 10 0.311 Preprocessor1_Model02
4 0.0121 rmse standard 4.61 10 0.330 Preprocessor1_Model02
5 0.0146 mae standard 3.93 10 0.311 Preprocessor1_Model03
6 0.0146 rmse standard 4.60 10 0.330 Preprocessor1_Model03
7 0.0176 mae standard 3.93 10 0.310 Preprocessor1_Model04
8 0.0176 rmse standard 4.60 10 0.330 Preprocessor1_Model04
9 0.0212 mae standard 3.93 10 0.309 Preprocessor1_Model05
10 0.0212 rmse standard 4.60 10 0.330 Preprocessor1_Model05
# ℹ 90 more rows
<- ggplot(metricas_resumen |> filter(.metric == "rmse"),
g_1 aes(x = penalty, y = mean, ymin = mean - std_err, ymax = mean + std_err)) +
geom_linerange() +
geom_point(colour = "red") +
scale_x_log10()
g_1
Nótese que la estimación del error de predicción por validación cruzada incluye un error de estimación (intervalos). Esto nos da dos opciones para escoger la lambda final:
- Escoger la que de el mínimo valor de error por validación cruzada
- Escoger la lambda más grande que no esté a más de 1 error estándar del mínimo.
Podemos obtener estos resultados de esta forma:
|> show_best(metric = "rmse") metricas_vc
# A tibble: 5 × 7
penalty .metric .estimator mean n std_err .config
<dbl> <chr> <chr> <dbl> <int> <dbl> <chr>
1 0.115 rmse standard 4.58 10 0.322 Preprocessor1_Model14
2 0.139 rmse standard 4.58 10 0.321 Preprocessor1_Model15
3 0.0954 rmse standard 4.58 10 0.324 Preprocessor1_Model13
4 0.168 rmse standard 4.58 10 0.319 Preprocessor1_Model16
5 0.0791 rmse standard 4.58 10 0.325 Preprocessor1_Model12
<- metricas_vc |> select_best(metric = "rmse")
minimo <- metricas_vc |> select_by_one_std_err(metric = "rmse", desc(penalty)) minimo_ee
En la gráfica se muestran las dos posiblidades:
+
g_1 geom_vline(data= minimo, aes(xintercept = penalty), colour = "blue") +
geom_vline(data = minimo_ee, aes(xintercept = penalty), colour = "blue")
Nota: aún cuando la mejora en desempeño predictivo al usar regularización no sea muy grande, obtenemos modelos más parsimoniosos, interpretables y robustos al aplicarla.
Finalmente, graficamos sobre la muestra de prueba
<- finalize_workflow(flujo_reg, minimo_ee) |>
modelo_final fit(grasa_ent)
<- predict(modelo_final, testing(grasa_particion)) |>
preds_tbl bind_cols(testing(grasa_particion))
ggplot(preds_tbl, aes(x = .pred, y = grasacorp)) +
geom_point() +
geom_abline(colour = "red") +
coord_obs_pred()
Observación: Nótese que obtenemos en particular una predicción con un error considerablemente más grande que el resto: Si examinamos:
|> mutate(error_abs = abs(grasacorp - .pred)) |>
preds_tbl arrange(desc(error_abs)) |> head()
# A tibble: 6 × 16
.pred grasacorp edad peso estatura cuello pecho abdomen cadera muslo rodilla
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 53.4 35.2 46 363. 72.2 51.2 136. 148. 148. 87.3 49.1
2 16.7 5.2 55 142. 67.2 35.2 92.7 82.8 91.9 54.4 35.2
3 20.1 31.4 67 164. 67.8 38.4 97.7 95.8 97.1 54.8 38.2
4 18.7 7.8 27 216 76 39.4 104. 90.9 108. 66.2 39.2
5 22.1 32.9 44 166 65.5 39.1 101. 93.9 100. 58.9 37.6
6 21.4 10.9 55 180. 68.8 41.1 107. 95.3 98.2 57.4 37.1
# ℹ 5 more variables: tobillo <dbl>, biceps <dbl>, antebrazo <dbl>,
# muñeca <dbl>, error_abs <dbl>
Y vemos que el peso de este ejemplo sale fuera del rango que vimos en entrenamiento:
|> mutate(error_abs = abs(grasacorp - .pred)) |>
preds_tbl mutate(error_grande = error_abs > 16 ) |>
ggplot(aes(x = estatura, y = peso, colour = factor(error_grande))) +
geom_point()
Lo que explica el tamaño del error para este caso.
11.3 ¿Cómo se desempeña validación cruzada como estimación del error?
Podemos comparar el desempeño estimado con validación cruzada con el de muestra de prueba: Consideremos nuestro ejemplo simulado de regresión logística. Repetiremos varias veces el ajuste y compararemos el error de prueba con el estimado por validación cruzada:
set.seed(28015)
<- rnorm(100, 0, 0.2)
a_vec <- tibble(term = paste0('V', 1:length(a_vec)), valor = a_vec)
a <- linear_reg(penalty = 0.01) |>
modelo_1 set_engine("glmnet", lambda.min.ratio = 1e-20)
<- workflow() |>
flujo_1 add_model(modelo_1) |>
add_formula(y ~ .)
<- function(n, beta){
sim_datos <- nrow(beta)
p <- matrix(rnorm(n * p, 0, 0.5), n, p) + rnorm(n)
mat_x colnames(mat_x) <- beta |> pull(term)
<- beta |> pull(valor)
beta_vec <- (mat_x %*% beta_vec)
f_x <- as.numeric(f_x) + rnorm(n, 0, 1)
y <- as_tibble(mat_x) |>
datos mutate(y = y)
datos
}<- function(reps, flujo, beta){
simular_evals <- sim_datos(n = 4000, beta = beta[1:40, ])
datos <- initial_split(datos, 0.05)
particion <- training(particion)
datos_ent <- testing(particion)
datos_pr
# evaluar con muestra de prueba
<- metric_set(rmse)
metricas <- flujo_1 |> fit(datos_ent)
flujo_ajustado <- predict(flujo_ajustado, datos_pr) |>
eval_prueba bind_cols(datos_pr |> dplyr::select(y)) |>
metricas(y, .pred)
<- predict(flujo_ajustado, datos_ent) |>
eval_entrena bind_cols(datos_ent |> select(y)) |>
metricas(y, .pred)
# particionar para validación cruzada
<- vfold_cv(datos_ent, v = 10)
particiones_val_cruzada <- flujo_1 |>
eval_vc fit_resamples(resamples = particiones_val_cruzada, metrics = metricas) |>
collect_metrics()
<-
res_tbl |> mutate(tipo = "prueba") |>
eval_prueba bind_rows(eval_entrena |> mutate(tipo = "entrenamiento")) |>
bind_rows(eval_vc |>
select(.metric, .estimator, .estimate = mean) |>
mutate(tipo = "val_cruzada"))
}
set.seed(82853)
<- tibble(reps = 1:25) |>
evals_tbl mutate(data = map(reps, ~ simular_evals(.x, flujo_1, beta = a))) |>
unnest(data)
ggplot(evals_tbl |>
filter(.metric == "rmse") |>
pivot_wider(names_from = tipo, values_from = .estimate) |>
pivot_longer(cols = c(entrenamiento, val_cruzada), names_to = "tipo"),
aes(x = prueba, y = value)) +
geom_point() + facet_wrap(~ tipo) +
geom_abline(colour = "red") +
xlab("Error de predicción (prueba)") +
ylab("Error estimado") + coord_equal() + xlim(0.8, 1.2)
Observa los rangos de los ejes. Vemos que aunque los dos tipos de estimaciones están centradas en lugares similares, el error por validación cruzada es ligeramente pesimista (como esperábamos), y no está muy correlacionado con el error de prueba.
Sin embargo, cuando usamos validación cruzada para seleccionar modelos tenemos lo siguiente:
set.seed(8559)
<- sim_datos(n = 4000, beta = a[1:40, ])
datos <- linear_reg(mixture = 0, penalty = tune()) |>
modelo set_engine("glmnet")
<- workflow() |>
flujo add_model(modelo) |>
add_formula(y ~ .)
# crear partición de análisis y evaluación
<- initial_validation_split(datos, c(0.05, 0.9))
particion_val <- tibble(penalty = exp(seq(-5, 5, 1)))
candidatos # evaluar
<- tune_grid(flujo, resamples = validation_set(particion_val), grid = candidatos,
val_datos metrics = metric_set(rmse, mae)) |>
collect_metrics() |>
select(penalty, .metric, mean) |>
mutate(tipo ="datos de validación")
# extraer datos de entrenamiento
<- training(particion_val)
datos_ent <- vfold_cv(datos_ent, v = 10)
particion_vc <- tune_grid(flujo, resamples = particion_vc, grid = candidatos,
val_cruzada metrics = metric_set(rmse, mae)) |>
collect_metrics() |>
select(penalty, .metric, mean) |>
mutate(tipo = "validación cruzada")
<- bind_rows(val_datos, val_cruzada) |>
comparacion_val filter(.metric == "mae")
ggplot(comparacion_val, aes(x = penalty, y = mean, colour = tipo)) +
geom_line() + geom_point() +
facet_wrap(~.metric) +
scale_x_log10()
Vemos que la estimación en algunos casos no es tan buena, aún cuando todos los datos fueron usados. Pero el mínimo se encuentra en lugares muy similares. La razón es:
Validación cruzada considera perturbaciones del conjunto de entrenamiento, de forma que lo que intenta evaluar es el error producido, para cada lambda, sobre distintas muestras de entrenamiento. En realidad nosotros queremos evaluar el error de predicción del modelo que ajustamos. Validación cruzada es más un estimador del error esperado de predicción sobre los modelos que ajustaríamos con distintas muestras de entrenamiento.
El resultado es que:
- Usamos validación cruzada para escoger la complejidad adecuada de la familia de modelos que consideramos.
- Como estimación del error de predicción del modelo que ajustamos, validación cruzada es más seguro que usar el error de entrenamiento, que muchas veces puede estar fuertemente sesgado hacia abajo. Sin embargo, lo mejor en este caso es utilizar una muestra de prueba.
- Existen variaciones (validación cruzada anidada, puedes ver este paper, y está implementado en tidymodels con la función nested_cv) que aún cuando es más exigente computacionalmente, produce mejores resultados cuando queremos utilizarla como estimación del error de prueba.
- Estratificación: especialmente en casos donde queremos predecir una variable categórica con algunas clases muy minoritarias, o cuando la respuesta tiene colas largas, puede ser buena idea estratificar la selecciones de muestra de prueba y las muestras de validación cruzada, de manera que cada corte es similar en composición de la variable respuesta. Esto es para evitar variación debida a la composición de muestras de validación, especialmente cuando la muestra de entrenamiento es relativamente chica.
11.4 Validación cruzada repetida
Con el objeto de reducir la varianza de las estimaciones por validación cruzada, podemos repetir varias veces usando distintas particiones seleccionadas al azar.
Por ejemplo, podemos repetir 5 veces validación cruzada con 10 vueltas, y ajustamos un total de 50 modelos. Esto no es lo mismo que validación cruzada con 50 vueltas. Hay razones para no subdividir tanto la muestra de entrenamiento:
- Aunque esquemas de validación cruzada-\(k\) con \(k\) grande pueden ser factibles, estos no se favorecen por la cantidad de cómputo necesaria y porque presentan sesgo hacia modelos más complejos (Shao 1993).
- En el extremo, podemos hacer validación leave-one-out (LOOCV), pero
- En estudios de simulación se desempeñan mejor métodos con \(k=5, 10, 20\), y cuando es posible, es mejor usar repeticiones
En nuestro ejemplo de grasa corporal:
set.seed(883)
# validación cruzada repetida
<- vfold_cv(grasa_ent, v = 10, repeats = 5)
validacion_particion # tiene información de índices en cada "fold" o "doblez" o "vuelta"
validacion_particion
# 10-fold cross-validation repeated 5 times
# A tibble: 50 × 3
splits id id2
<list> <chr> <chr>
1 <split [113/13]> Repeat1 Fold01
2 <split [113/13]> Repeat1 Fold02
3 <split [113/13]> Repeat1 Fold03
4 <split [113/13]> Repeat1 Fold04
5 <split [113/13]> Repeat1 Fold05
6 <split [113/13]> Repeat1 Fold06
7 <split [114/12]> Repeat1 Fold07
8 <split [114/12]> Repeat1 Fold08
9 <split [114/12]> Repeat1 Fold09
10 <split [114/12]> Repeat1 Fold10
# ℹ 40 more rows
<- tune_grid(flujo_reg,
metricas_vc resamples = validacion_particion,
grid = bf_grid,
metrics = metric_set(rmse, mae))
<- select_best(metricas_vc, metric = "rmse")
mejor <- select_by_one_std_err(metricas_vc, metric = "rmse", desc(penalty))
mejor_1ee |> unnest(.metrics) metricas_vc
# A tibble: 5,000 × 9
splits id id2 penalty .metric .estimator .estimate .config
<list> <chr> <chr> <dbl> <chr> <chr> <dbl> <chr>
1 <split [113/13]> Repeat1 Fold01 0.01 rmse standard 4.18 Preproc…
2 <split [113/13]> Repeat1 Fold01 0.0121 rmse standard 4.18 Preproc…
3 <split [113/13]> Repeat1 Fold01 0.0146 rmse standard 4.18 Preproc…
4 <split [113/13]> Repeat1 Fold01 0.0176 rmse standard 4.18 Preproc…
5 <split [113/13]> Repeat1 Fold01 0.0212 rmse standard 4.18 Preproc…
6 <split [113/13]> Repeat1 Fold01 0.0256 rmse standard 4.18 Preproc…
7 <split [113/13]> Repeat1 Fold01 0.0309 rmse standard 4.18 Preproc…
8 <split [113/13]> Repeat1 Fold01 0.0373 rmse standard 4.18 Preproc…
9 <split [113/13]> Repeat1 Fold01 0.0450 rmse standard 4.18 Preproc…
10 <split [113/13]> Repeat1 Fold01 0.0543 rmse standard 4.18 Preproc…
# ℹ 4,990 more rows
# ℹ 1 more variable: .notes <list>
Vemos que esta función da un valor del error para cada vuelta de validación cruzada, y cada valor de lambda que pusimos en el grid:
|> unnest(.metrics) |> group_by(id, .metric) |> count() metricas_vc
# A tibble: 10 × 3
# Groups: id, .metric [10]
id .metric n
<chr> <chr> <int>
1 Repeat1 mae 500
2 Repeat1 rmse 500
3 Repeat2 mae 500
4 Repeat2 rmse 500
5 Repeat3 mae 500
6 Repeat3 rmse 500
7 Repeat4 mae 500
8 Repeat4 rmse 500
9 Repeat5 mae 500
10 Repeat5 rmse 500
Y obtenemos:
<- metricas_vc |>
metricas_resumen collect_metrics()
<- ggplot(metricas_resumen |> filter(.metric == "rmse"),
g_1 aes(x = penalty, y = mean, ymin = mean - std_err, ymax = mean + std_err)) +
geom_linerange() +
geom_point(colour = "red") +
scale_x_log10() +
geom_vline(xintercept = c(mejor$penalty, mejor_1ee$penalty), colour = "blue")
g_1