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 enmutate/summarisecuando 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:
- 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.
- {{ }} (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.
- group_by({{ group_var }}):
- Agrupa el conjunto de datos por la variable indicada.
- Ejemplo: Si group_var = especie, agrupa por especie.
- 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.
## [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
## # 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>
##
## 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
## [[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
## [[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
##
## 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