Machine Learning con Tidyverse

Juan Isaula

2023-01-18

Cree, ajuste y evalúe modelos de Regresión

En este artículo, aprenderá a utilizar el flujo de trabajo de lista de columnas para crear, ajustar y evaluar modelos de regresión. Tendrás la oportunidad de trabajar con dos tipos de modelos: modelos lineales y modelos random forest models (modelos de bosque aleatorio).

Divisiones de entrenamiento, prueba y validación

Dos de las preguntas más importantes que un cientifico de datos debe responder al crear modelos de aprendizaje automático son: ¿Qué tan bien se desempeñaría mi modelo con datos nuevos? y ¿Seleccioné el modelo con mejor desempeño? A lo largo de este artículo aprenderá las técnicas necesarias para responder a estas preguntas.

División de datos en ntrenamiento (Train) y Prueba (Test)

Para responder a la primera pregunta, “¿qué tan bien funcionaría mi modelo con nuevos datos?” Comience con todos sus datos, esto contiene tanto las características como el resultado que desea predecir y dividirlo en dos porciones.

Tal como se puede apreciar en el gráfico, la primera parte se usa para entrenar un modelo y la segunda parte se usa para probar qué tan bien funciona con nuevos datos. Esto se conoce como la división de entrenamiento y prueba. En un flujo de trabajo de aprendizaje automático disciplinado, este es un primer paso fundamental. Siempre que los datos de prueba sean una representación justa de los datos que puede esperar ver en el futuro, puede usarlos para estimar el rendimiento esperado para futuras observaciones.

División Inicial

Para hacer la división de entrenamiento y prueba, utilizará la función initial_split() del paquete rsample. Vea el siguiente bloque de código, aquí usaremos los datos gapminder que viene incorporada en R con el proposito de ejemplificar:

library(rsample)
library(gapminder)

gap_split <- initial_split(gapminder, prop =0.75)
training_data <- training(gap_split)
testing_data <- testing(gap_split)
nrow(training_data)
## [1] 1278

El parámetro prop se utiliza para especificar la proporción de datos que se seleccionarán para el conjunto de entrenamiento, en este caso es del 75%. Esto significa que el 25% de los datos se retendrán aleatoriamente como conjunto de prueba. Para preparar los marcos de datos de entrenamiento y prueba, utiliza las funciones training() y testing(), respectivamente. De las 1,704 observaciones en el conjunto de datos de gapminder, 1,278 o aproximadamente el 75% se divide en datos de entrenamiento y el 25% restante se reserva como datos de prueba.

División de entrenamiento-Validación

Debido a que está interesado en mantener los datos de prueba independientes, no debe usarlos para tomar decisiones sobre sus modelos. Entonces, para responder a la segunda pregunta: “¿Seleccioné el modelo con mejor desempeño?” Debe confiar exclusivamente en los datos del entrenamiento.

Los datos del tren se pueden dividir aún más en dos particiones de entrenar y validar.

Ahora puede usar los nuevos datos del entrenamiento para construir sus modelos y usar la validación para calcular su rendimiento.

Validación Cruzada

Puede llevar esto un paso más allá repitiendo esta división entre entrenar y validar varias veces. Cada vez reservando una porción diferente de los datos para su evaluación. Esto se conoce como validación cruzada y ofrece dos ventajas clave:

  • En primer lugar, al retener de forma iterativa diferentes partes de los datos de entrenamiento, básicamente puede utilizarlos todos para evaluar el rendimiento general de un modelo.

  • En segundo lugar, puede calcular múltiples medidas de rendimiento. Esto ayuda a tener en cuenta la variabilidad natural que existiría al medir el rendimiento de sus modelos.

Vfold_cv()

Puede usar la función vfold_cv() del paquete rsample para crear estos pares de datos de entrenamiento y validación con validación cruzada.

cv_split <- vfold_cv(training_data, v =3)
cv_split
## #  3-fold cross-validation 
## # A tibble: 3 × 2
##   splits            id   
##   <list>            <chr>
## 1 <split [852/426]> Fold1
## 2 <split [852/426]> Fold2
## 3 <split [852/426]> Fold3

El parámetro v se usa para indicar cuántas veces se deben dividir los datos. Este nuevo marco de datos ahora lo lleva de vuelta al flujo de trabajo de la columna de lista. Para construir un modelo para cada pliegue, primero deberá extraer los marcos de datos de entrenamiento y validación en sus propias columnas de lista.

map() - entrenamiento & validación

Para extraer los marcos de datos de entrenamiento y validación en sus propias columnas de lista. usará map() para aplicar las funciones training() y testing(). Esto crea el entrenamiento deseado y valida los marcos de datos para cada pliegue. Tenga en cuenta que esto es similar a lo que hizo con la división inicial, excepto que ahora lo está haciendo durante muchas divisiones.

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.0      ✔ purrr   0.3.4 
## ✔ tibble  3.1.8      ✔ dplyr   1.0.10
## ✔ tidyr   1.2.0      ✔ stringr 1.4.1 
## ✔ readr   2.1.2      ✔ forcats 0.5.2 
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
cv_data <- cv_split %>%  
  mutate(train = map(splits,~training(.x)),  
                                validate = map(splits,~testing(.x)))

Tenga en cuenta que cargamos la libreria tidyverse ya que si no, no podriamos usar el comando %>%. Muy bien, con esto en mente, ya tenemos construidos muchos modelos, veamos:

head(cv_data)
## #  3-fold cross-validation 
## # A tibble: 3 × 4
##   splits            id    train              validate          
##   <list>            <chr> <list>             <list>            
## 1 <split [852/426]> Fold1 <tibble [852 × 6]> <tibble [426 × 6]>
## 2 <split [852/426]> Fold2 <tibble [852 × 6]> <tibble [426 × 6]>
## 3 <split [852/426]> Fold3 <tibble [852 × 6]> <tibble [426 × 6]>

Por último, puede usar cada uno de los tres marcos de datos del entrenamiento para construir los modelos correspondientes, es decir,

cv_models_lm <- cv_data %>% 
  mutate(model = map(train,~lm(formula = lifeExp~., data = .x)))

cv_models_lm
## #  3-fold cross-validation 
## # A tibble: 3 × 5
##   splits            id    train              validate           model 
##   <list>            <chr> <list>             <list>             <list>
## 1 <split [852/426]> Fold1 <tibble [852 × 6]> <tibble [426 × 6]> <lm>  
## 2 <split [852/426]> Fold2 <tibble [852 × 6]> <tibble [426 × 6]> <lm>  
## 3 <split [852/426]> Fold3 <tibble [852 × 6]> <tibble [426 × 6]> <lm>

Medición del Rendimiento de la Validación Cruzada

Ahora que ha generado sus marcos de datos y modelos con validación cruzada, aprendamos a usar los datos de validación para medir el rendimiento de cada modelo.

Medición del Rendimiento

Para medir el rendimiento de validación de sus modelos, debe comparar los valores reales de la esperanza de vida en los marcos de datos de validación con los generados mediante el modelo de predicción. Para hacer esto, primero debe preparar ambos conjuntos de valores.

Tal como puede apreciar en la figura previa, primero debe aislar los valores reales, Me referiré a este vector de valores Actual A continuación, debe utilizar las características de estas observaciones junto con el modelo para generar una serie de predicciones para los datos de validación.

Ahora que tiene los valores pronosticados y reales de la esperanza de vida, puede compararlos directamente. Al medir las diferencias entre ellos, puede evaluar el rendimiento general utilizando su métrica preferida.

Error Absoluto Medio

Una de las métricas que prefiero se llama Error Absoluto Medio o MAE. \[MAE = \frac{\sum_{i=1}^n |Actual_{i} - Predicted_{i}|}{n}\] Esta métrica captura la magnitud promedio por la cual las predicciones difieren de los valores reales. El rasgo más atractivo de esta métrica es que tiene una interpretación intuitiva. Usando el MAE, tiene una idea de cuánto, en promedio, la predicción de su modelo diferirá de la realidad.

Ingredientes para la medición del desempeño

Para resumir, necesita tres ingredientes para medir el rendimiento: - los valores de esperanza de vida reales, - los valores de esperanza de vida pronosticados y - una métrica para comparar los dos.

Ahora vamos a aprender cómo hacer esto en R.

  1. Extraer los valores reales

Para extraer los valores reales de la esperanza de vida de los marcos de datos de validación, puede utilizar la función map(). Aquí, el punto x se refiere a cada marco de datos validado, por lo que puede usar el operador dólar para acceder al vector de la columna de esperanza de vida.

cv_prep_lm <- cv_models_lm %>%  
  mutate(validate_actual = map(validate,~.x$lifeExp))

Funciones predict() & map2()

Para generar los valores predichos, necesita usar la función predict(). Esta función requiere dos parámetros, predict(model,data). Ahora necesita expandir su colección de herramientas de map() para incluir la función map2(). Esto es muy similar a la función map(), excepto que ahora usa el punto x y el punto y como sus dos primeros parámetros y se refiere a estos marcadores de posición en la fórmula de la misma manera, map2(.x = model, .y = data, .f = ~predict(.x,.y)).

  1. Preparar los valores pronosticados

Como antes, puede usar esta función map2() dentro de mutate() para agregar una columna de predicciones para cada pliegue de validación cruzada.

cv_eval_lm <- cv_prep_lm %>%  
  mutate(validate_actual = map(validate,~.x$lifeExp),  
         validate_predicted = map2(model, validate,~predict(.x, .y)))
## Warning in predict.lm(.x, .y): prediction from a rank-deficient fit may be
## misleading

## Warning in predict.lm(.x, .y): prediction from a rank-deficient fit may be
## misleading

## Warning in predict.lm(.x, .y): prediction from a rank-deficient fit may be
## misleading

Ahora que tiene los valores reales y predichos para cada pliegue de validación cruzada, puede compararlos usando la función mae() del paquete Metrics. Nuevamente, puede usar map2(). Como sabe que el resultado será un vector double, puede usar directamente la función map2_double() para asegurarse de que el valor se devuelva como un vector en lugar de una lista. Y así es como puede medir el rendimiento de cada pliegue de validación cruzada.

library(Metrics)

cv_eval_lm <- cv_eval_lm%>% 
  mutate(validate_mae = map2_dbl(validate_actual, validate_predicted,
                                 ~mae(actual = .x, predicted = .y)))

cv_eval_lm$validate_mae
## [1] 3.069236 2.661486 2.936420
mean(cv_eval_lm$validate_mae)
## [1] 2.889048

Creación y ajuste de un random forest model

Revisemos brevemente lo que ha hecho hasta ahora para evaluar el rendimiento de la validación cruzada del modelo de regresión.

Con la validación cruzada, divide los datos de entrenamiento en múltiples pares de entrenamiento y validación.

La sección del Train para cada uno de estos pliegues de validación cruzada se utilizó para construir un modelo correspondiente, que luego se usó junto con los conjuntos de validación repartidos Para calcular el error absoluto medio para cada pliegue de validación cruzada.

Una vez que haya tomado el mae promedio a través de los pliegues de validación cruzada, habrá medido el rendimiento del modelo en los datos retenidos.Para su modelo de regresión lineal, el error absoluto medio es de 2,7 años, lo que significa que puede esperar que las predicciones del modelo se desvíen, en promedio, en 2,7 años. ¿Es este el mejor modelo que podemos construir?

Otro Modelo

Puede determinar esto repitiendo estos pasos con un modelo diferente. Debido a que se utilizarán los mismos datos en todos los modelos, puede comparar directamente su rendimiento de validación entre ellos, lo que le permite seleccionar el modelo con mejor rendimiento. Puede utilizar este flujo de trabajo de aprendizaje automático para comparar prácticamente cualquier modelo. Probemos esto con un modelo de bosque aleatorio para ver si logra un mayor rendimiento.

Beneficios del random forest model

El random forest model es un modelo muy popular en la comunidad de aprendizaje automático. Los detalles de cómo funciona este algoritmo están fuera del alcance de este artículo, pero se pueden encontrar en otros excelentes articulos en medium de sobre aprendizaje automático. Dado que que puede haber una relación no lineal entre las características del gapminder y la esperanza de vida. También sabemos que la característica del país tenía una relación directa con otras características. Los modelos de bosques aleatorios manejan de forma nativa tanto las relaciones no lineales como las interacciones de características, por lo que podemos ser optimistas acerca de probar este modelo.

Herramientas básicas del random forest model

Utilizará la implementación de random forest model del paquete ranger. Para construir el modelo de bosque aleatorio con hiperparámetros predeterminados, use la siguiente sintaxis rf_model <- ranger(formula = ___, data = ___, seed = ___). Debe proporcionar la fórmula y los datos al igual que el modelo de regresión. Debido a que un bosque aleatorio tiene un elemento aleatorio, recomiendo usar el argumento semilla para garantizar que sus resultados sean reproducibles. La sintaxis para preparar los valores de predicción para nuevos datos también es similar a la de un modelo lineal. prediction <- predict(rf_model, new_data)$predictions La única diferencia es que necesita usar el signo de dólar para extraer explícitamente el vector de predicción del objeto de predicción.

Cree modelos básicos de random forest model

Puede aplicar esto como antes mapeando los datos del tren para construir los modelos para cada pliegue. Luego use map2() para generar las predicciones para cada pliegue.

library(ranger)
cv_models_rf <- cv_data %>% 
  mutate(model = map(train,~ranger(formula = lifeExp~., data = .x, seed =42)))

cv_prep_rf <- cv_models_rf %>% mutate(validate_predicted = 
                                        map2(model, validate,
                                             ~predict(.x, .y)$predictions))