🎯 Objetivo

Este documento guía paso a paso la construcción de un modelo de regresión lineal usando el framework tidymodels. El objetivo es predecir la masa corporal (body_mass_g) de pingüinos del Archipiélago Palmer a partir de sus características físicas.

Dataset: palmerpenguins — una alternativa moderna y amigable al clásico Iris dataset.


1. Instalación y Carga de Librerías

El siguiente bloque detecta automáticamente si las librerías necesarias están instaladas; si no, las descarga e instala antes de cargarlas.

paquetes <- c("tidyverse", "tidymodels", "palmerpenguins", "vip")

faltantes <- paquetes[!paquetes %in% rownames(installed.packages())]
if (length(faltantes) > 0) {
  install.packages(faltantes)
}

library(tidyverse)
library(tidymodels)
library(palmerpenguins)
library(vip)
Paquete Rol en este ejercicio
tidyverse Manipulación y visualización de datos
tidymodels Framework unificado para modelado (split, receta, workflow, métricas)
palmerpenguins Dataset de entrenamiento
vip Visualización de importancia de variables

2. Preparación de los Datos

Cargamos el dataset penguins y eliminamos las filas con valores faltantes (NA), que representan una fracción pequeña del total y podrían sesgar el modelo.

df_penguins <- penguins %>%
  drop_na()

glimpse(df_penguins)
## Rows: 333
## Columns: 8
## $ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
## $ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
## $ bill_length_mm    <dbl> 39.1, 39.5, 40.3, 36.7, 39.3, 38.9, 39.2, 41.1, 38.6…
## $ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, 19.3, 20.6, 17.8, 19.6, 17.6, 21.2…
## $ flipper_length_mm <int> 181, 186, 195, 193, 190, 181, 195, 182, 191, 198, 18…
## $ body_mass_g       <int> 3750, 3800, 3250, 3450, 3650, 3625, 4675, 3200, 3800…
## $ sex               <fct> male, female, female, female, male, female, male, fe…
## $ year              <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

Tras la limpieza, contamos con 333 observaciones y 8 variables. Las variables que usaremos como predictores son:

  • flipper_length_mm — Longitud de la aleta
  • bill_length_mm — Longitud del pico
  • species — Especie del pingüino
  • sex — Sexo del individuo

3. Exploración Visual (EDA)

Antes de modelar, visualizamos las relaciones más importantes entre las variables.

3.1 Longitud de aleta vs. peso por especie

ggplot(df_penguins, aes(x = flipper_length_mm, y = body_mass_g, color = species)) +
  geom_point(alpha = 0.6, size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.8) +
  scale_color_brewer(palette = "Set1") +
  labs(
    title   = "Longitud de aleta vs. masa corporal",
    subtitle = "Separado por especie — cada una sigue su propia tendencia lineal",
    x       = "Longitud de aleta (mm)",
    y       = "Masa corporal (g)",
    color   = "Especie"
  ) +
  theme_minimal(base_size = 13)

3.2 Distribución del peso por sexo

ggplot(df_penguins, aes(x = sex, y = body_mass_g, fill = sex)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "grey40") +
  scale_fill_manual(values = c("female" = "#F4A2A2", "male" = "#A2C4F4")) +
  labs(
    title    = "Distribución de masa corporal por sexo",
    subtitle = "Los machos tienden a ser significativamente más pesados",
    x        = "Sexo",
    y        = "Masa corporal (g)"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none")


4. División de Datos (Train / Test Split)

Separamos el dataset en 80% entrenamiento y 20% prueba, usando estratificación por especie para garantizar una distribución proporcional en ambas particiones.

set.seed(123)  # Semilla para reproducibilidad

penguin_split <- initial_split(df_penguins, prop = 0.80, strata = species)

train_data <- training(penguin_split)
test_data  <- testing(penguin_split)

cat("Observaciones en entrenamiento:", nrow(train_data), "\n")
## Observaciones en entrenamiento: 265
cat("Observaciones en prueba:       ", nrow(test_data),  "\n")
## Observaciones en prueba:        68

5. Modelado con tidymodels

El workflow de tidymodels separa claramente tres responsabilidades: preprocesamiento (receta), especificación del modelo y ensamblado (workflow).

5.1 Receta de preprocesamiento

penguin_recipe <- recipe(
  body_mass_g ~ flipper_length_mm + bill_length_mm + species + sex,
  data = train_data
) %>%
  step_dummy(all_nominal_predictors())  # Convierte variables categóricas a dummies

penguin_recipe

5.2 Especificación del modelo

lm_spec <- linear_reg() %>%
  set_engine("lm") %>%
  set_mode("regression")

lm_spec
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

5.3 Workflow y entrenamiento

penguin_wf <- workflow() %>%
  add_recipe(penguin_recipe) %>%
  add_model(lm_spec)

penguin_fit <- penguin_wf %>%
  fit(data = train_data)

tidy(penguin_fit) %>%
  arrange(desc(abs(estimate)))

6. Evaluación del Rendimiento

Aplicamos el modelo entrenado sobre el conjunto de prueba y calculamos las métricas principales.

results <- test_data %>%
  bind_cols(predict(penguin_fit, test_data))

# Métricas: RMSE, R² y MAE
metrics(results, truth = body_mass_g, estimate = .pred)

6.1 Gráfica Predicción vs. Realidad

La línea punteada roja representa el ajuste perfecto (predicción = valor real). Cuanto más cercanos estén los puntos a esa línea, mejor el modelo.

ggplot(results, aes(x = body_mass_g, y = .pred)) +
  geom_point(alpha = 0.6, color = "#3A7DC9", size = 2) +
  geom_abline(lty = 2, color = "red", linewidth = 0.8) +
  labs(
    title    = "Predicción vs. Realidad",
    subtitle = "Los puntos deben alinearse sobre la diagonal para un buen modelo",
    x        = "Masa corporal real (g)",
    y        = "Masa corporal predicha (g)"
  ) +
  theme_minimal(base_size = 13)


7. Importancia de las Variables

¿Qué características fueron las más determinantes para el modelo?

penguin_fit %>%
  extract_fit_parsnip() %>%
  vip(num_features = 10, aesthetics = list(fill = "#3A7DC9", alpha = 0.85)) +
  labs(
    title    = "Importancia de Variables",
    subtitle = "Basada en el valor absoluto de los coeficientes estandarizados"
  ) +
  theme_minimal(base_size = 13)


8. Conclusiones

El modelo de regresión lineal entrenado con tidymodels logró un R² de 0.888 y un RMSE de 283.4 g, lo que indica que explica la mayoría de la varianza en la masa corporal de los pingüinos.

Los puntos clave del ejercicio son:

  1. La longitud de la aleta resultó ser el predictor continuo más fuerte.
  2. La especie tiene un efecto considerable; cada una tiene una masa base distinta.
  3. El sexo también aporta poder predictivo: los machos son más pesados en promedio.
  4. El pipeline recipe → workflow → fit → predict de tidymodels hace el proceso reproducible y fácil de escalar a modelos más complejos.

Generado automáticamente con R 4.5.3 y tidymodels 1.4.1.