Capítulo31 Temas Avanzados en Data Science con Tidyverse

31.1 Introducción

Este documento presenta temas avanzados en el ecosistema tidyverse con ejemplos prácticos en R.

31.1.1 1. Manipulación avanzada con dplyr

Evaluación tidy: {{ }} y := — funciones que reciben nombres de columnas.

  • {{ var }} (“embrace”): permite pasar el nombre de una columna como argumento a una función que usa dplyr por dentro.
  • :=: se usa en mutate/summarise cuando el nombre de la nueva columna también es una variable.
  • Para qué: escribir tus propias funciones reutilizables sobre pipelines de dplyr.

Explicación: Uso de tidy evaluation para funciones personalizadas.

library(dplyr)

# Función personalizada con tidy evaluation
mean_by_group <- function(data, group_var, value_var) {
  data %>%
    group_by({{ group_var }}) %>%
    summarise(mean_value = mean({{ value_var }}, na.rm = TRUE))
}
mean_by_group
## function (data, group_var, value_var) 
## {
##     data %>% group_by({
##         {
##             group_var
##         }
##     }) %>% summarise(mean_value = mean({
##         {
##             value_var
##         }
##     }, na.rm = TRUE))
## }
df <- tibble(grupo = c("A", "A", "B", "B"), 
             valor = c(10, 20, 30, 40)) # los datos

mean_by_group(df, grupo, valor) # El uso de la función nueva
## # A tibble: 2 × 2
##   grupo mean_value
##   <chr>      <dbl>
## 1 A             15
## 2 B             35

Otro ejemplo

dfnew= tibble(especie = c("setosa", "setosa", "versicolor", "versicolor"),
              longitud_sepalo = c(5.1, 4.9, 7.0, 6.4))

mean_by_group(dfnew, especie, longitud_sepalo)
## # A tibble: 2 × 2
##   especie    mean_value
##   <chr>           <dbl>
## 1 setosa            5  
## 2 versicolor        6.7
mean_sd_by_group <- function(data, group_var, value_var) {
  data %>%
    group_by({{ group_var }}) %>%
    summarise(sd_value = sd({{ value_var }}, na.rm = TRUE),
              mean_value = mean({{ value_var }}, na.rm = TRUE))
}

mean_sd_by_group(dfnew, especie, longitud_sepalo)
## # A tibble: 2 × 3
##   especie    sd_value mean_value
##   <chr>         <dbl>      <dbl>
## 1 setosa        0.141        5  
## 2 versicolor    0.424        6.7

31.1.2 Componentes clave:

  1. Definición de la función

mean_by_group <- function(data, group_var, value_var) { … }

  • data: El data frame o tibble que contiene los datos.
  • group_var: La variable por la que se agruparán los datos (por ejemplo, categoría).
  • value_var: La variable numérica de la que se calculará la media.
  1. {{ }} (Curly-curly operator):
  • Es parte del tidy evaluation en dplyr.
  • Permite que los argumentos group_var y value_var se pasen como nombres de columna sin comillas.
  • Sin esto, la función no podría interpretar correctamente los nombres de columna.
  1. group_by({{ group_var }}):
  • Agrupa el conjunto de datos por la variable indicada.
  • Ejemplo: Si group_var = especie, agrupa por especie.
  1. summarise(mean_value = mean({{ value_var }}, na.rm = TRUE)):
  • Calcula la media de la columna indicada (value_var) dentro de cada grupo.
  • na.rm = TRUE elimina valores faltantes (NA) para evitar errores.

Si olvidas na.rm = TRUE, funciones como mean() o sd() devuelven NA en cuanto la columna tiene un solo valor faltante, en vez de calcular el promedio.

datos=c(1, NA, 3:8, NA, 10:12)
mean(datos, na.rm=TRUE)
## [1] 6.7

31.2 2. Modelado con tidymodels

Explicación: Flujo reproducible para regresión lineal.

library(tidymodels)
data(mtcars)

# Convertir variables a factores
mtcars <- mtcars %>%
  mutate(cyl = factor(cyl),
         gear = factor(gear))


receta <- recipe(mpg ~ wt + hp+ cyl + gear, data = mtcars)
modelo <- linear_reg() %>%
          set_engine("lm")

workflow() %>%
  add_recipe(receta) %>%
  add_model(modelo) %>%
  fit(data = mtcars)
## ══ Workflow [trained] ══════════════════════════════════════════════════════════
## Preprocessor: Recipe
## Model: linear_reg()
## 
## ── Preprocessor ────────────────────────────────────────────────────────────────
## 0 Recipe Steps
## 
## ── Model ───────────────────────────────────────────────────────────────────────
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Coefficients:
## (Intercept)           wt           hp         cyl6         cyl8        gear4  
##    34.46173     -2.79186     -0.03424     -2.93920     -1.33080      1.42125  
##       gear5  
##     2.08577

Ver los resultados del modelo y hacer predicciones.

# Ajustar el modelo
ajuste <- workflow() %>%
  add_recipe(receta) %>%
  add_model(modelo) %>%
  fit(data = mtcars)


# Extraer el modelo ajustado
modelo_ajustado <- ajuste %>% extract_fit_parsnip()


# Ver coeficientes

modelo_ajustado %>% tidy()      # Coeficientes en formato tibble
## # A tibble: 7 × 5
##   term        estimate std.error statistic  p.value
##   <chr>          <dbl>     <dbl>     <dbl>    <dbl>
## 1 (Intercept)  34.5       2.46      14.0   2.52e-13
## 2 wt           -2.79      0.856     -3.26  3.18e- 3
## 3 hp           -0.0342    0.0177    -1.93  6.44e- 2
## 4 cyl6         -2.94      1.47      -1.99  5.71e- 2
## 5 cyl8         -1.33      2.78      -0.479 6.36e- 1
## 6 gear4         1.42      1.51       0.941 3.56e- 1
## 7 gear5         2.09      2.14       0.972 3.40e- 1
modelo_ajustado %>% glance()    # Métricas globales (R², AIC, etc.)
## # A tibble: 1 × 12
##   r.squared adj.r.squared sigma statistic       p.value    df logLik   AIC   BIC
##       <dbl>         <dbl> <dbl>     <dbl>         <dbl> <dbl>  <dbl> <dbl> <dbl>
## 1     0.864         0.831  2.48      26.4 0.00000000113     6  -70.5  157.  169.
## # ℹ 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>
summary(modelo_ajustado$fit)    # Resumen clásico del modelo lm
## 
## Call:
## stats::lm(formula = ..y ~ ., data = data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.4215 -1.2428 -0.3401  0.8961  5.3657 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 34.46173    2.46379  13.987 2.52e-13 ***
## wt          -2.79186    0.85567  -3.263  0.00318 ** 
## hp          -0.03424    0.01770  -1.935  0.06444 .  
## cyl6        -2.93920    1.47362  -1.995  0.05710 .  
## cyl8        -1.33080    2.77885  -0.479  0.63617    
## gear4        1.42125    1.51065   0.941  0.35580    
## gear5        2.08577    2.14490   0.972  0.34015    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.477 on 25 degrees of freedom
## Multiple R-squared:  0.8638, Adjusted R-squared:  0.8311 
## F-statistic: 26.42 on 6 and 25 DF,  p-value: 1.128e-09
# Predicciones y métricas
predicciones <- predict(modelo_ajustado, mtcars)

bind_cols(mtcars, predicciones) %>%
  metrics(truth = mpg, estimate = .pred)
## # A tibble: 3 × 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 rmse    standard       2.19 
## 2 rsq     standard       0.864
## 3 mae     standard       1.68
  • extract_fit_parsnip() obtiene el modelo ajustado.
  • tidy() muestra coeficientes y errores estándar.
  • metrics() calcula métricas como RMSE, R², MAE.

31.3 3. Visualización avanzada con ggplot2

Explicación: Facetas y escalas personalizadas.

library(ggplot2)

ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  facet_wrap(~ cyl) +
  scale_y_log10() +
  theme_minimal()


31.4 4. Datos anidados y listas con purrr

Explicación: Ajustar modelos por grupo y extraer coeficientes.

library(tidyr)
library(purrr)
library(broom)

nested <- mtcars %>%
  group_by(cyl) %>%
  nest()

nested <- nested %>%
  mutate(modelo = purrr::map(data, ~ lm(mpg ~ wt, data = .x)),
         coeficientes = purrr::map(modelo, tidy))

nested$data
## [[1]]
## # A tibble: 7 × 10
##     mpg  disp    hp  drat    wt  qsec    vs    am gear   carb
##   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
## 1  21    160    110  3.9   2.62  16.5     0     1 4         4
## 2  21    160    110  3.9   2.88  17.0     0     1 4         4
## 3  21.4  258    110  3.08  3.22  19.4     1     0 3         1
## 4  18.1  225    105  2.76  3.46  20.2     1     0 3         1
## 5  19.2  168.   123  3.92  3.44  18.3     1     0 4         4
## 6  17.8  168.   123  3.92  3.44  18.9     1     0 4         4
## 7  19.7  145    175  3.62  2.77  15.5     0     1 5         6
## 
## [[2]]
## # A tibble: 11 × 10
##      mpg  disp    hp  drat    wt  qsec    vs    am gear   carb
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
##  1  22.8 108      93  3.85  2.32  18.6     1     1 4         1
##  2  24.4 147.     62  3.69  3.19  20       1     0 4         2
##  3  22.8 141.     95  3.92  3.15  22.9     1     0 4         2
##  4  32.4  78.7    66  4.08  2.2   19.5     1     1 4         1
##  5  30.4  75.7    52  4.93  1.62  18.5     1     1 4         2
##  6  33.9  71.1    65  4.22  1.84  19.9     1     1 4         1
##  7  21.5 120.     97  3.7   2.46  20.0     1     0 3         1
##  8  27.3  79      66  4.08  1.94  18.9     1     1 4         1
##  9  26   120.     91  4.43  2.14  16.7     0     1 5         2
## 10  30.4  95.1   113  3.77  1.51  16.9     1     1 5         2
## 11  21.4 121     109  4.11  2.78  18.6     1     1 4         2
## 
## [[3]]
## # A tibble: 14 × 10
##      mpg  disp    hp  drat    wt  qsec    vs    am gear   carb
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
##  1  18.7  360    175  3.15  3.44  17.0     0     0 3         2
##  2  14.3  360    245  3.21  3.57  15.8     0     0 3         4
##  3  16.4  276.   180  3.07  4.07  17.4     0     0 3         3
##  4  17.3  276.   180  3.07  3.73  17.6     0     0 3         3
##  5  15.2  276.   180  3.07  3.78  18       0     0 3         3
##  6  10.4  472    205  2.93  5.25  18.0     0     0 3         4
##  7  10.4  460    215  3     5.42  17.8     0     0 3         4
##  8  14.7  440    230  3.23  5.34  17.4     0     0 3         4
##  9  15.5  318    150  2.76  3.52  16.9     0     0 3         2
## 10  15.2  304    150  3.15  3.44  17.3     0     0 3         2
## 11  13.3  350    245  3.73  3.84  15.4     0     0 3         4
## 12  19.2  400    175  3.08  3.84  17.0     0     0 3         2
## 13  15.8  351    264  4.22  3.17  14.5     0     1 5         4
## 14  15    301    335  3.54  3.57  14.6     0     1 5         8
nested$modelo
## [[1]]
## 
## Call:
## lm(formula = mpg ~ wt, data = .x)
## 
## Coefficients:
## (Intercept)           wt  
##       28.41        -2.78  
## 
## 
## [[2]]
## 
## Call:
## lm(formula = mpg ~ wt, data = .x)
## 
## Coefficients:
## (Intercept)           wt  
##      39.571       -5.647  
## 
## 
## [[3]]
## 
## Call:
## lm(formula = mpg ~ wt, data = .x)
## 
## Coefficients:
## (Intercept)           wt  
##      23.868       -2.192
nested$coeficientes
## [[1]]
## # A tibble: 2 × 5
##   term        estimate std.error statistic p.value
##   <chr>          <dbl>     <dbl>     <dbl>   <dbl>
## 1 (Intercept)    28.4       4.18      6.79 0.00105
## 2 wt             -2.78      1.33     -2.08 0.0918 
## 
## [[2]]
## # A tibble: 2 × 5
##   term        estimate std.error statistic    p.value
##   <chr>          <dbl>     <dbl>     <dbl>      <dbl>
## 1 (Intercept)    39.6       4.35      9.10 0.00000777
## 2 wt             -5.65      1.85     -3.05 0.0137    
## 
## [[3]]
## # A tibble: 2 × 5
##   term        estimate std.error statistic    p.value
##   <chr>          <dbl>     <dbl>     <dbl>      <dbl>
## 1 (Intercept)    23.9      3.01       7.94 0.00000405
## 2 wt             -2.19     0.739     -2.97 0.0118

La alternativa es hacer cada factor individualmente

  • Hacemos un modelo lm(mpg ~ wt) para cada subconjunto de datos agrupados por cyl == 6
modelo_cyl6 <- lm(mpg ~ wt, data = filter(mtcars, cyl == 6))

summary(modelo_cyl6)
## 
## Call:
## lm(formula = mpg ~ wt, data = filter(mtcars, cyl == 6))
## 
## Residuals:
##      Mazda RX4  Mazda RX4 Wag Hornet 4 Drive        Valiant       Merc 280 
##        -0.1250         0.5840         1.9292        -0.6897         0.3547 
##      Merc 280C   Ferrari Dino 
##        -1.0453        -1.0080 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)   
## (Intercept)   28.409      4.184   6.789  0.00105 **
## wt            -2.780      1.335  -2.083  0.09176 . 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.165 on 5 degrees of freedom
## Multiple R-squared:  0.4645, Adjusted R-squared:  0.3574 
## F-statistic: 4.337 on 1 and 5 DF,  p-value: 0.09176