7  Un Flujo De Modelado

En el capítulo anterior, analizamos el paquete parsnip, que se puede utilizar para definir y ajustar el modelo. Este capítulo presenta un nuevo concepto llamado flujo de modelado. El propósito de este concepto (y el objeto tidymodels workflow() correspondiente) es encapsular las partes principales del proceso de modelado (discutido en Sección 1.5). El flujo de trabajo es importante en dos sentidos. En primer lugar, utilizar un concepto de flujo de trabajo fomenta una buena metodología, ya que es un punto de entrada único a los componentes de estimación de un análisis de datos. En segundo lugar, permite al usuario organizar mejor los proyectos. Estos dos puntos se analizan en las siguientes secciones.

7.1 ¿Dónde Comienza Y Termina El Modelo?

Hasta ahora, cuando hemos utilizado el término “el modelo”, nos referimos a una ecuación estructural que relaciona algunos predictores con uno o más resultados. Consideremos nuevamente la regresión lineal como ejemplo. Los datos de resultado se indican como \(y_i\), donde hay \(i = 1 \ldots n\) muestras en el conjunto de entrenamiento. Supongamos que hay \(p\) predictores \(x_{i1}, \ldots, x_{ip}\) que se utilizan en el modelo. La regresión lineal produce una ecuación modelo de

\[ \hat{y}_i = \hat{\beta}_0 + \hat{\beta}_1x_{i1} + \ldots + \hat{\beta}_px_{ip} \]

Si bien este es un modelo lineal, es lineal sólo en los parámetros. Los predictores podrían ser términos no lineales (como el \(\log(x_i)\)).

La forma convencional de pensar sobre el proceso de modelado es que sólo incluye el ajuste del modelo.

Para algunos conjuntos de datos sencillos, ajustar el modelo en sí puede ser todo el proceso. Sin embargo, a menudo se presentan una variedad de opciones y pasos adicionales antes de que el modelo se ajuste:

  • Si bien nuestro modelo de ejemplo tiene predictores \(p\), es común comenzar con más predictores candidatos \(p\). Mediante un análisis de datos exploratorio o utilizando el conocimiento del dominio, algunos de los predictores pueden excluirse del análisis. En otros casos, se puede utilizar un algoritmo de selección de características para realizar una elección basada en datos para el conjunto de predictores mínimo para el modelo.
  • Hay ocasiones en las que falta el valor de un predictor importante. En lugar de eliminar esta muestra del conjunto de datos, el valor faltante podría imputarse utilizando otros valores de los datos. Por ejemplo, si faltara \(x_1\) pero estuviera correlacionado con los predictores \(x_2\) y \(x_3\), un método de imputación podría estimar la observación faltante de \(x_1\) a partir de los valores de \(x_2\) y \(x_3\).
  • Puede resultar beneficioso transformar la escala de un predictor. Si no hay información a priori sobre cuál debería ser la nueva escala, podemos estimar la escala adecuada utilizando una técnica de transformación estadística, los datos existentes y algún criterio de optimización. Otras transformaciones, como PCA, toman grupos de predictores y los transforman en nuevas características que se utilizan como predictores.

Si bien estos ejemplos están relacionados con pasos que ocurren antes de que el modelo se ajuste, también puede haber operaciones que ocurren después de que se crea el modelo. Cuando se crea un modelo de clasificación donde el resultado es binario (por ejemplo, “evento” y “no evento”), se acostumbra utilizar un límite de probabilidad del 50% para crear una predicción de clase discreta, también conocida como predicción dura. Por ejemplo, un modelo de clasificación podría estimar que la probabilidad de un evento era del 62%. Usando el valor predeterminado típico, la predicción difícil sería “evento”. Sin embargo, es posible que el modelo deba centrarse más en reducir los resultados falsos positivos (es decir, donde los verdaderos no eventos se clasifican como eventos). Una forma de hacerlo es elevar el límite del 50% a un valor mayor. Esto aumenta el nivel de evidencia requerido para llamar evento a una nueva muestra. Si bien esto reduce la tasa de verdaderos positivos (lo cual es malo), puede tener un efecto más dramático en la reducción de falsos positivos. La elección del valor de corte debe optimizarse utilizando datos. Este es un ejemplo de un paso de posprocesamiento que tiene un efecto significativo en el funcionamiento del modelo, aunque no esté incluido en el paso de ajuste del modelo.

Es importante centrarse en el proceso de modelado más amplio, en lugar de ajustar únicamente el modelo específico utilizado para estimar los parámetros. Este proceso más amplio incluye cualquier paso de preprocesamiento, el ajuste del modelo en sí mismo, así como posibles actividades de posprocesamiento. En este libro, nos referiremos a este concepto más completo como flujo de modelado y resaltaremos cómo manejar todos sus componentes para producir una ecuación de modelo final.

En otro software, como Python o Spark, colecciones similares de pasos se denominan pipelines. En tidymodels, el término “pipeline” ya connota una secuencia de operaciones encadenadas con un operador de pipe (como %>% de magrittr o el nativo más nuevo |>). En lugar de utilizar terminología ambigua en este contexto, llamamos a la secuencia de operaciones computacionales relacionadas con el modelado flujos de trabajo.

Unir los componentes analíticos del análisis de datos es importante por otra razón. Los capítulos futuros demostrarán cómo medir con precisión el rendimiento, así como también cómo optimizar los parámetros estructurales (es decir, ajuste del modelo). Para cuantificar correctamente el rendimiento del modelo en el conjunto de entrenamiento, [Capítulo @ sec-resampling] recomienda el uso de métodos de remuestreo. Para hacer esto correctamente, no se debe excluir de la validación ninguna parte del análisis basada en datos. Para ello, el flujo de trabajo debe incluir todos los pasos de estimación importantes.

A modo de ejemplo, considere la extracción de señales del análisis de componentes principales (PCA). Hablaremos más sobre esto en Sección 8.4 y en el Capítulo 16; PCA es una forma de reemplazar predictores correlacionados con nuevas características artificiales que no están correlacionadas y capturan la mayor parte de la información del conjunto original. Las nuevas características podrían usarse como predictores y la regresión de mínimos cuadrados podría usarse para estimar los parámetros del modelo.

Hay dos formas de pensar sobre el flujo de trabajo del modelo. Figura 7.1 ilustra el método incorrecto: pensar que el paso de preprocesamiento de PCA no forma parte del flujo de trabajo de modelado.

Un modelo mental incorrecto de dónde ocurre la estimación del modelo en el proceso de análisis de datos. Los datos y el conjunto de predictores son sustratos para un paso de preprocesamiento inicial utilizando PCA. Estos datos se pasan al algoritmo de ajuste del modelo para producir un modelo ajustado. La figura indica que el flujo de trabajo del modelo solo incluye el proceso de ajuste del modelo. Esto implica que el ajuste del modelo es el único lugar donde se produce la estimación.
Figura 7.1: Modelo mental incorrecto de dónde ocurre la estimación del modelo en el proceso de análisis de datos

La falacia aquí es que, aunque PCA realiza cálculos importantes para producir los componentes, se supone que sus operaciones no tienen incertidumbre asociada con ellos. Los componentes de PCA se tratan como conocidos y, si no se incluyen en el flujo de trabajo del modelo, el efecto de PCA no se podría medir adecuadamente.

Figura 7.2 muestra un enfoque apropiado.

Un modelo mental correcto de dónde ocurre la estimación del modelo en el proceso de análisis de datos. Los datos y el conjunto de predictores son sustratos para un paso de preprocesamiento inicial utilizando PCA. Estos datos se pasan al algoritmo de ajuste del modelo para producir un modelo ajustado. La figura indica que el flujo de trabajo del modelo incluye el proceso de ajuste del modelo y el paso PCA. Esto implica que ambas operaciones deben considerarse pasos de estimación.
Figura 7.2: Modelo mental correcto de dónde ocurre la estimación del modelo en el proceso de análisis de datos.

De esta forma, el preprocesamiento PCA se considera parte del proceso de modelado.

7.2 Conceptos Básicos Del Flujo De Trabajo

El paquete workflows permite al usuario vincular objetos de modelado y preprocesamiento. Empecemos de nuevo con los datos de Ames y un modelo lineal simple:

library(tidymodels)  # Incluye el paquete de flujos de trabajo.
tidymodels_prefer()

lm_model <- 
  linear_reg() %>% 
  set_engine("lm")

Un flujo de trabajo siempre requiere un objeto modelo parsnip:

lm_wflow <- 
  workflow() %>% 
  add_model(lm_model)

lm_wflow
## ══ Workflow ═════════════════════════════════════════════════════════════════════════
## Preprocessor: None
## Model: linear_reg()
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

Tenga en cuenta que aún no hemos especificado cómo este flujo de trabajo debe preprocesar los datos: Preprocessor: None.

Si nuestro modelo es muy simple, se puede utilizar una fórmula R estándar como preprocesador:

lm_wflow <- 
  lm_wflow %>% 
  add_formula(Sale_Price ~ Longitude + Latitude)

lm_wflow
## ══ Workflow ═════════════════════════════════════════════════════════════════════════
## Preprocessor: Formula
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Sale_Price ~ Longitude + Latitude
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

Los flujos de trabajo tienen un método fit() que se puede utilizar para crear el modelo. Usando los objetos creados en Sección 6.6:

lm_fit <- fit(lm_wflow, ames_train)
lm_fit
## ══ Workflow [trained] ═══════════════════════════════════════════════════════════════
## Preprocessor: Formula
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Sale_Price ~ Longitude + Latitude
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Coefficients:
## (Intercept)    Longitude     Latitude  
##     -302.97        -2.07         2.71

También podemos predict() en el flujo de trabajo ajustado:

predict(lm_fit, ames_test %>% slice(1:3))
## # A tibble: 3 × 1
##   .pred
##   <dbl>
## 1  5.22
## 2  5.21
## 3  5.28

El método predict() sigue las mismas reglas y convenciones de nomenclatura que describimos para el paquete parsnip en Sección 6.3.

Tanto el modelo como el preprocesador se pueden eliminar o actualizar:

lm_fit %>% update_formula(Sale_Price ~ Longitude)
## ══ Workflow ═════════════════════════════════════════════════════════════════════════
## Preprocessor: Formula
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Sale_Price ~ Longitude
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

Tenga en cuenta que, en este nuevo objeto, el resultado muestra que el modelo ajustado anterior se eliminó ya que la nueva fórmula es inconsistente con el ajuste del modelo anterior.

7.3 Agregar Variables Sin Procesar Al workflow()

Hay otra interfaz para pasar datos al modelo, la función add_variables(), que usa una sintaxis similar a dplyr para elegir variables. La función tiene dos argumentos principales: outcomes y predictors. Estos utilizan un enfoque de selección similar al backend tidyselect de los paquetes tidyverse para capturar múltiples selectores usando c().

lm_wflow <- 
  lm_wflow %>% 
  remove_formula() %>% 
  add_variables(outcome = Sale_Price, predictors = c(Longitude, Latitude))
lm_wflow
## ══ Workflow ═════════════════════════════════════════════════════════════════════════
## Preprocessor: Variables
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Outcomes: Sale_Price
## Predictors: c(Longitude, Latitude)
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

Los predictores también podrían haberse especificado utilizando un selector más general, como

predictors = c(ends_with("tude"))

Una ventaja es que cualquier columna de resultados especificada accidentalmente en el argumento de los predictores se eliminará silenciosamente. Esto facilita el uso de:

predictors = everything()

Cuando el modelo se ajusta, la especificación reúne estos datos, sin modificar, en un marco de datos y los pasa a la función subyacente:

fit(lm_wflow, ames_train)
## ══ Workflow [trained] ═══════════════════════════════════════════════════════════════
## Preprocessor: Variables
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Outcomes: Sale_Price
## Predictors: c(Longitude, Latitude)
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Coefficients:
## (Intercept)    Longitude     Latitude  
##     -302.97        -2.07         2.71

Si desea que el método de modelado subyacente haga lo que normalmente haría con los datos, add_variables() puede ser una interfaz útil. Como veremos en Sección 7.4.1, también facilita especificaciones de modelado más complejas. Sin embargo, como mencionamos en la siguiente sección, modelos como glmnet y xgboost esperan que el usuario cree variables indicadoras a partir de predictores de factores. En estos casos, una interfaz de receta o fórmula suele ser una mejor opción.

En el próximo capítulo, veremos un preprocesador más potente (llamado recipe) que también se puede agregar a un flujo de trabajo.

7.4 ¿Cómo Utiliza Un workflow() La Fórmula?

Recuerde de Sección 3.2 que el método de fórmula en R tiene múltiples propósitos (lo discutiremos más a fondo en el Capítulo 8). Uno de ellos es codificar correctamente los datos originales en un formato listo para el análisis. Esto puede implicar la ejecución de transformaciones en línea (por ejemplo, log(x)), la creación de columnas de variables ficticias, la creación de interacciones u otras expansiones de columnas, etc. Sin embargo, muchos métodos estadísticos requieren diferentes tipos de codificaciones:

  • La mayoría de los paquetes para modelos basados en árboles utilizan la interfaz de fórmulas pero no codifican los predictores categóricos como variables ficticias.

  • Los paquetes pueden utilizar funciones en línea especiales que le indican a la función del modelo cómo tratar el predictor en el análisis. Por ejemplo, en los modelos de análisis de supervivencia, un término de fórmula como strata(site) indicaría que la columna site es una variable de estratificación. Esto significa que no debe tratarse como un predictor regular y no tiene una estimación de parámetro de ubicación correspondiente en el modelo.

  • Algunos paquetes de R han ampliado la fórmula de manera que las funciones básicas de R no pueden analizar ni ejecutar. En modelos multinivel (por ejemplo, modelos mixtos o modelos bayesianos jerárquicos), un término de modelo como (semana | sujeto) indica que la columna semana es un efecto aleatorio que tiene diferentes estimaciones de parámetros de pendiente para cada valor de la columna sujeto.

Un flujo de trabajo es una interfaz de propósito general. Cuando se utiliza add_formula(), ¿cómo debería el flujo de trabajo preprocesar los datos? Dado que el preprocesamiento depende del modelo, workflows intenta emular lo que haría el modelo subyacente siempre que sea posible. Si no es posible, el procesamiento de la fórmula no debe afectar las columnas utilizadas en la fórmula. Veamos esto con más detalle.

Modelos basados en árboles

Cuando ajustamos un árbol a los datos, el paquete parsnip comprende lo que haría la función de modelado. Por ejemplo, si un modelo de bosque aleatorio se ajusta usando los paquetes ranger o randomForest, el flujo de trabajo sabe que las columnas de predictores que son factores deben dejarse como están.

Como contraejemplo, un árbol potenciado creado con el paquete xgboost requiere que el usuario cree variables ficticias a partir de predictores de factores (ya que xgboost::xgb.train() no lo hará). Este requisito está integrado en el objeto de especificación del modelo y un flujo de trabajo que utiliza xgboost creará las columnas indicadoras para este motor. También tenga en cuenta que un motor diferente para árboles potenciados, C5.0, no requiere variables ficticias, por lo que el flujo de trabajo no crea ninguna.

Esta determinación se realiza para cada combinación de modelo y motor.

7.4.1 Fórmulas especiales y funciones en línea.

Varios modelos multinivel se han estandarizado según una especificación de fórmula diseñada en el paquete lme4. Por ejemplo, para ajustar un modelo de regresión que tenga efectos aleatorios para los sujetos, usaríamos la siguiente fórmula:

library(lme4)
lmer(distance ~ Sex + (age | Subject), data = Orthodont)

El efecto de esto es que cada sujeto tendrá un parámetro estimado de intersección y pendiente para la “edad”.

El problema es que los métodos estándar de R no pueden procesar adecuadamente esta fórmula:

model.matrix(distance ~ Sex + (age | Subject), data = Orthodont)
## Warning in Ops.ordered(age, Subject): '|' is not meaningful for ordered factors
##      (Intercept) SexFemale age | SubjectTRUE
## attr(,"assign")
## [1] 0 1 2
## attr(,"contrasts")
## attr(,"contrasts")$Sex
## [1] "contr.treatment"
## 
## attr(,"contrasts")$`age | Subject`
## [1] "contr.treatment"

El resultado es un marco de datos de cero filas.

El problema es que la fórmula especial debe ser procesada por el código del paquete subyacente, no por el enfoque estándar model.matrix().

Incluso si esta fórmula pudiera usarse con model.matrix(), esto aún presentaría un problema ya que la fórmula también especifica los atributos estadísticos del modelo.

La solución en workflows es una fórmula de modelo suplementaria opcional que se puede pasar a add_model(). La especificación add_variables() proporciona los nombres de las columnas básicas, y luego la fórmula real dada al modelo se establece dentro de add_model():

library(multilevelmod)

multilevel_spec <- linear_reg() %>% set_engine("lmer")

multilevel_workflow <- 
  workflow() %>% 
  # Pase los datos tal cual:
  add_variables(outcome = distance, predictors = c(Sex, age, Subject)) %>% 
  add_model(multilevel_spec, 
            # Esta fórmula se le da al modelo.
            formula = distance ~ Sex + (age | Subject))

multilevel_fit <- fit(multilevel_workflow, data = Orthodont)
multilevel_fit
## ══ Workflow [trained] ═══════════════════════════════════════════════════════════════
## Preprocessor: Variables
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Outcomes: distance
## Predictors: c(Sex, age, Subject)
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Linear mixed model fit by REML ['lmerMod']
## Formula: distance ~ Sex + (age | Subject)
##    Data: data
## REML criterion at convergence: 471.2
## Random effects:
##  Groups   Name        Std.Dev. Corr 
##  Subject  (Intercept) 7.391         
##           age         0.694    -0.97
##  Residual             1.310         
## Number of obs: 108, groups:  Subject, 27
## Fixed Effects:
## (Intercept)    SexFemale  
##       24.52        -2.15

Incluso podemos usar la función strata() mencionada anteriormente del paquete survival para el análisis de supervivencia:

library(censored)

parametric_spec <- survival_reg()

parametric_workflow <- 
  workflow() %>% 
  add_variables(outcome = c(fustat, futime), predictors = c(age, rx)) %>% 
  add_model(parametric_spec, 
            formula = Surv(futime, fustat) ~ age + strata(rx))

parametric_fit <- fit(parametric_workflow, data = ovarian)
parametric_fit
## ══ Workflow [trained] ═══════════════════════════════════════════════════════════════
## Preprocessor: Variables
## Model: survival_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Outcomes: c(fustat, futime)
## Predictors: c(age, rx)
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Call:
## survival::survreg(formula = Surv(futime, fustat) ~ age + strata(rx), 
##     data = data, model = TRUE)
## 
## Coefficients:
## (Intercept)         age 
##     12.8734     -0.1034 
## 
## Scale:
##   rx=1   rx=2 
## 0.7696 0.4704 
## 
## Loglik(model)= -89.4   Loglik(intercept only)= -97.1
##  Chisq= 15.36 on 1 degrees of freedom, p= 9e-05 
## n= 26

Observe cómo en ambas convocatorias se utilizó la fórmula específica del modelo.

7.5 Crear Múltiples Flujos De Trabajo A La Vez

En algunas situaciones, los datos requieren numerosos intentos para encontrar un modelo apropiado. Por ejemplo:

  • Para los modelos predictivos, es aconsejable evaluar una variedad de tipos de modelos diferentes. Esto requiere que el usuario cree múltiples especificaciones de modelo.

  • Las pruebas secuenciales de modelos suelen comenzar con un conjunto ampliado de predictores. Este “modelo completo” se compara con una secuencia del mismo modelo que elimina cada predictor por turno. Utilizando métodos básicos de prueba de hipótesis o validación empírica, se puede aislar y evaluar el efecto de cada predictor.

En estas situaciones, así como en otras, puede resultar tedioso u oneroso crear muchos flujos de trabajo a partir de diferentes conjuntos de preprocesadores y/o especificaciones de modelo. Para solucionar este problema, el paquete workflowset crea combinaciones de componentes de flujo de trabajo. Una lista de preprocesadores (por ejemplo, fórmulas, selectores dplyr u objetos de recetas de ingeniería de características que se analizan en el siguiente capítulo) se puede combinar con una lista de especificaciones de modelo, lo que da como resultado un conjunto de flujos de trabajo.

Como ejemplo, digamos que queremos centrarnos en las diferentes formas en que se representa la ubicación de la casa en los datos de Ames. Podemos crear un conjunto de fórmulas que capturen estos predictores:

location <- list(
  longitude = Sale_Price ~ Longitude,
  latitude = Sale_Price ~ Latitude,
  coords = Sale_Price ~ Longitude + Latitude,
  neighborhood = Sale_Price ~ Neighborhood
)

Estas representaciones se pueden cruzar con uno o más modelos usando la función workflow_set(). Simplemente usaremos la especificación del modelo lineal anterior para demostrar:

library(workflowsets)
location_models <- workflow_set(preproc = location, models = list(lm = lm_model))
location_models
## # A workflow set/tibble: 4 × 4
##   wflow_id        info             option    result    
##   <chr>           <list>           <list>    <list>    
## 1 longitude_lm    <tibble [1 × 4]> <opts[0]> <list [0]>
## 2 latitude_lm     <tibble [1 × 4]> <opts[0]> <list [0]>
## 3 coords_lm       <tibble [1 × 4]> <opts[0]> <list [0]>
## 4 neighborhood_lm <tibble [1 × 4]> <opts[0]> <list [0]>
location_models$info[[1]]
## # A tibble: 1 × 4
##   workflow   preproc model      comment
##   <list>     <chr>   <chr>      <chr>  
## 1 <workflow> formula linear_reg ""
extract_workflow(location_models, id = "coords_lm")
## ══ Workflow ═════════════════════════════════════════════════════════════════════════
## Preprocessor: Formula
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Sale_Price ~ Longitude + Latitude
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

Los conjuntos de flujos de trabajo están diseñados principalmente para funcionar con remuestreo, lo cual se analiza en el Capítulo 10. Las columnas “opción” y “resultado” deben completarse con tipos específicos de objetos que resultan del remuestreo. Demostraremos esto con más detalle en los Capítulos 11 y 15.

Mientras tanto, creemos ajustes de modelo para cada fórmula y guárdelos en una nueva columna llamada fit. Usaremos las operaciones básicas dplyr y purrr:

location_models <-
   location_models %>%
   mutate(fit = map(info, ~ fit(.x$workflow[[1]], ames_train)))
location_models
## # A workflow set/tibble: 4 × 5
##   wflow_id        info             option    result     fit       
##   <chr>           <list>           <list>    <list>     <list>    
## 1 longitude_lm    <tibble [1 × 4]> <opts[0]> <list [0]> <workflow>
## 2 latitude_lm     <tibble [1 × 4]> <opts[0]> <list [0]> <workflow>
## 3 coords_lm       <tibble [1 × 4]> <opts[0]> <list [0]> <workflow>
## 4 neighborhood_lm <tibble [1 × 4]> <opts[0]> <list [0]> <workflow>
location_models$fit[[1]]
## ══ Workflow [trained] ═══════════════════════════════════════════════════════════════
## Preprocessor: Formula
## Model: linear_reg()
## 
## ── Preprocessor ─────────────────────────────────────────────────────────────────────
## Sale_Price ~ Longitude
## 
## ── Model ────────────────────────────────────────────────────────────────────────────
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Coefficients:
## (Intercept)    Longitude  
##     -184.40        -2.02

Usamos una función purrr aquí para mapear nuestros modelos, pero existe un enfoque mejor y más fácil para ajustar conjuntos de flujo de trabajo que se presentará en Sección 11.1.

En general, ¡hay mucho más en los conjuntos de flujos de trabajo! Si bien hemos cubierto los conceptos básicos aquí, los matices y ventajas de los conjuntos de flujo de trabajo no se ilustrarán hasta el Capítulo 15.

7.6 Evaluación Del Conjunto De Prueba

Digamos que hemos concluido el desarrollo de nuestro modelo y nos hemos decidido por un modelo final. Hay una función de conveniencia llamada last_fit() que ajustará el modelo a todo el conjunto de entrenamiento y lo evaluará con el conjunto de prueba.

Usando lm_wflow como ejemplo, podemos pasar el modelo y la división inicial de entrenamiento/prueba a la función:

final_lm_res <- last_fit(lm_wflow, ames_split)
final_lm_res
## # Resampling results
## # Manual resampling 
## # A tibble: 1 × 6
##   splits             id               .metrics .notes   .predictions .workflow 
##   <list>             <chr>            <list>   <list>   <list>       <list>    
## 1 <split [2342/588]> train/test split <tibble> <tibble> <tibble>     <workflow>

Observe que last_fit() toma una división de datos como entrada, no un marco de datos. Esta función utiliza la división para generar los conjuntos de entrenamiento y prueba para el ajuste y la evaluación finales.

La columna .workflow contiene el flujo de trabajo ajustado y se puede extraer de los resultados usando:

fitted_lm_wflow <- extract_workflow(final_lm_res)

De manera similar, collect_metrics() y collect_predictions() proporcionan acceso a las métricas de rendimiento y predicciones, respectivamente.

collect_metrics(final_lm_res)
collect_predictions(final_lm_res) %>% slice(1:5)

Veremos más sobre last_fit() en acción y cómo usarlo nuevamente en Sección 16.6.

Cuando se usan conjuntos de validación, last_fit() tiene un argumento llamado add_validation_set para especificar si debemos entrenar el modelo final únicamente en el conjunto de entrenamiento (el predeterminado) o la combinación de los conjuntos de entrenamiento y validación.

7.7 Resumen Del capítulo

En este capítulo, aprendió que el proceso de modelado abarca más que simplemente estimar los parámetros de un algoritmo que conecta los predictores con un resultado. Este proceso también incluye pasos de preprocesamiento y operaciones realizadas después de que se ajusta un modelo. Introdujimos un concepto llamado flujo de trabajo modelo que puede capturar los componentes importantes del proceso de modelado. También se pueden crear múltiples flujos de trabajo dentro de un conjunto de flujos de trabajo. La función last_fit() es conveniente para ajustar un modelo final al conjunto de entrenamiento y evaluar con el conjunto de prueba.

Para los datos de Ames, el código relacionado que veremos usado nuevamente es:

library(tidymodels)
data(ames)

ames <- mutate(ames, Sale_Price = log10(Sale_Price))

set.seed(502)
ames_split <- initial_split(ames, prop = 0.80, strata = Sale_Price)
ames_train <- training(ames_split)
ames_test  <-  testing(ames_split)

lm_model <- linear_reg() %>% set_engine("lm")

lm_wflow <- 
  workflow() %>% 
  add_model(lm_model) %>% 
  add_variables(outcome = Sale_Price, predictors = c(Longitude, Latitude))

lm_fit <- fit(lm_wflow, ames_train)