Reto de gestión. Prever una medida de progresión de diabetes un año después de una evaluación basal puede contribuir a investigar criterios de seguimiento y planificación de servicios. Se propone estimar esta variable continua a partir de factores iniciales. El ejercicio es estadístico y académico: no debe utilizarse como algoritmo de decisión clínica sin validación adicional.
Objetivo general: desarrollar y validar preliminarmente una regresión lineal múltiple para estimar la progresión de diabetes al año.
Objetivos específicos: (i) explorar y depurar
variables; (ii) reservar el 25 % de observaciones para prueba; (iii)
ajustar un modelo con lm(); (iv) evaluar residuos, RMSE y
R²; (v) proponer mejoras.
Metas didácticas: RMSE de prueba inferior a 60 unidades, R² de prueba positivo y diferencia relativa de RMSE entrenamiento/prueba inferior al 20 %. Estos umbrales no equivalen a criterios médicos. El AUC/ROC no corresponde a una respuesta cuantitativa continua.
Datos: base real Diabetes incluida en
scikit-learn (442 pacientes, predictores estandarizados y respuesta
cuantitativa de progresión al año). Se suministra
datos_diabetes.csv junto con este informe. Como referencia
conceptual se revisa Regresión lineal múltiple: predicción de gastos
médicos, https://rpubs.com/DavidGS/rlm; aquí se estudia un
desenlace distinto.
| Variable | Función y fundamento |
|---|---|
target |
Respuesta continua: progresión de diabetes al año. |
bmi |
Índice de masa corporal basal estandarizado. |
bp |
Presión arterial promedio basal estandarizada. |
s5 |
Medición sérica basal estandarizada (log de triglicéridos). |
age |
Edad basal estandarizada. |
sex |
Sexo codificado y estandarizado. |
Esquema: Datos basales → exploración →
selección/depuración → entrenamiento (75 %) y prueba (25 %) → regresión
lm() → predicción → residuos y métricas → mejora.
Modelo: \(target=\beta_0+\beta_1 bmi+\beta_2 bp+\beta_3 s5+\beta_4 age+\beta_5 sex+\varepsilon\). Los coeficientes representan asociaciones condicionales en escalas estandarizadas; no son efectos causales.
datos <- read.csv('datos_diabetes.csv')
dplyr::glimpse(datos)
## Rows: 442
## Columns: 11
## $ age <dbl> 0.038075906, -0.001882017, 0.085298906, -0.089062939, 0.0053830…
## $ sex <dbl> 0.05068012, -0.04464164, 0.05068012, -0.04464164, -0.04464164, …
## $ bmi <dbl> 0.061696207, -0.051474061, 0.044451213, -0.011595015, -0.036384…
## $ bp <dbl> 0.021872386, -0.026327528, -0.005670422, -0.036656081, 0.021872…
## $ s1 <dbl> -0.044223498, -0.008448724, -0.045599451, 0.012190569, 0.003934…
## $ s2 <dbl> -3.482076e-02, -1.916334e-02, -3.419447e-02, 2.499059e-02, 1.55…
## $ s3 <dbl> -0.043400846, 0.074411564, -0.032355932, -0.036037570, 0.008142…
## $ s4 <dbl> -0.002592262, -0.039493383, -0.002592262, 0.034308859, -0.00259…
## $ s5 <dbl> 0.019907486, -0.068331547, 0.002861309, 0.022687745, -0.0319876…
## $ s6 <dbl> -0.017646125, -0.092204050, -0.025930339, -0.009361911, -0.0466…
## $ target <dbl> 151, 75, 141, 206, 135, 97, 138, 63, 110, 310, 101, 69, 179, 18…
skimr::skim(datos)
| Name | datos |
| Number of rows | 442 |
| Number of columns | 11 |
| _______________________ | |
| Column type frequency: | |
| numeric | 11 |
| ________________________ | |
| Group variables | None |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| age | 0 | 1 | 0.00 | 0.05 | -0.11 | -0.04 | 0.01 | 0.04 | 0.11 | ▃▆▇▆▂ |
| sex | 0 | 1 | 0.00 | 0.05 | -0.04 | -0.04 | -0.04 | 0.05 | 0.05 | ▇▁▁▁▇ |
| bmi | 0 | 1 | 0.00 | 0.05 | -0.09 | -0.03 | -0.01 | 0.03 | 0.17 | ▅▇▅▂▁ |
| bp | 0 | 1 | 0.00 | 0.05 | -0.11 | -0.04 | -0.01 | 0.04 | 0.13 | ▂▇▇▅▁ |
| s1 | 0 | 1 | 0.00 | 0.05 | -0.13 | -0.03 | 0.00 | 0.03 | 0.15 | ▁▆▇▃▁ |
| s2 | 0 | 1 | 0.00 | 0.05 | -0.12 | -0.03 | 0.00 | 0.03 | 0.20 | ▂▇▆▁▁ |
| s3 | 0 | 1 | 0.00 | 0.05 | -0.10 | -0.04 | -0.01 | 0.03 | 0.18 | ▂▇▅▁▁ |
| s4 | 0 | 1 | 0.00 | 0.05 | -0.08 | -0.04 | 0.00 | 0.03 | 0.19 | ▇▆▆▁▁ |
| s5 | 0 | 1 | 0.00 | 0.05 | -0.13 | -0.03 | 0.00 | 0.03 | 0.13 | ▁▇▇▅▁ |
| s6 | 0 | 1 | 0.00 | 0.05 | -0.14 | -0.03 | 0.00 | 0.03 | 0.14 | ▁▅▇▃▁ |
| target | 0 | 1 | 152.13 | 77.09 | 25.00 | 87.00 | 140.50 | 211.50 | 346.00 | ▇▇▆▅▂ |
datos_modelo <- datos |>
dplyr::select(target, bmi, bp, s5, age, sex) |>
tidyr::drop_na()
cat('Registros originales:', nrow(datos),
'| registros completos:', nrow(datos_modelo), '\n')
## Registros originales: 442 | registros completos: 442
La partición 75/25 permite ajustar los parámetros sin incorporar la información de prueba. Se fija una semilla para lograr reproducibilidad dentro de R.
set.seed(123)
particion <- rsample::initial_split(datos_modelo, prop = 0.75)
entrenamiento <- rsample::training(particion)
prueba <- rsample::testing(particion)
modelo <- lm(target ~ bmi + bp + s5 + age + sex,
data = entrenamiento)
print(round(coef(modelo), 3))
## (Intercept) bmi bp s5 age sex
## 153.076 626.809 264.268 538.162 -4.399 -112.181
Para el diagnóstico preliminar de supuestos,
broom::augment() suministra valores ajustados y residuos.
La gráfica de residuos permite explorar heterocedasticidad y no
linealidad; el gráfico Q–Q, desviaciones de normalidad.
ggplot2 no incluye por defecto una función
geom_residuals(); se utiliza geom_point() con
la columna .resid, que representa correctamente el gráfico
solicitado.
diag <- broom::augment(modelo)
ggplot(diag, aes(x = .fitted, y = .resid)) +
geom_point(alpha = .55) +
geom_hline(yintercept = 0, linetype = 'dashed') +
labs(title = 'Residuos frente a predicciones',
x = 'Valor ajustado', y = 'Residuo') +
theme_minimal(base_size=9)
ggplot(diag, aes(sample = .resid)) +
stat_qq(alpha = .5) + stat_qq_line() +
labs(title = 'Normalidad aproximada de residuos') +
theme_minimal(base_size=9)
pred_train <- predict(modelo, newdata = entrenamiento)
pred_test <- predict(modelo, newdata = prueba)
metricas <- data.frame(
conjunto = c('Entrenamiento','Prueba'),
n = c(nrow(entrenamiento), nrow(prueba)),
RMSE = c(yardstick::rmse_vec(entrenamiento$target, pred_train),
yardstick::rmse_vec(prueba$target, pred_test)),
MAE = c(yardstick::mae_vec(entrenamiento$target, pred_train),
yardstick::mae_vec(prueba$target, pred_test)),
R2 = c(yardstick::rsq_vec(entrenamiento$target, pred_train),
yardstick::rsq_vec(prueba$target, pred_test))
)
knitr::kable(metricas, digits=3, caption='Indicadores por conjunto')
| conjunto | n | RMSE | MAE | R2 |
|---|---|---|---|---|
| Entrenamiento | 331 | 54.681 | 45.189 | 0.495 |
| Prueba | 111 | 56.723 | 46.203 | 0.464 |
diferencia_rmse <- 100 * abs(metricas$RMSE[2] - metricas$RMSE[1]) /
metricas$RMSE[1]
exito <- metricas$RMSE[2] < 60 && metricas$R2[2] > 0 &&
diferencia_rmse < 20
El RMSE de prueba es 56.72 unidades de progresión; el R² de prueba es 0.464. La diferencia relativa de RMSE entrenamiento/prueba es 3.7 %. Por tanto, el modelo cumple los umbrales didácticos declarados. Los resultados indican capacidad predictiva limitada por las variables y población incluidas; no prueban utilidad clínica ni generalización a nuevos hospitales.
Mejora 1 — variables y especificación. Explorar
términos cuadráticos e interacciones justificadas (por ejemplo,
I(bmi^2)), revisar colinealidad y contrastar con validación
cruzada en entrenamiento.
Mejora 2 — datos externos y calidad. Ampliar la base con muestras recientes y de otras instituciones; comprobar calidad de mediciones, valores faltantes, subgrupos y transportabilidad antes de uso operativo.
Mejora 3 — algoritmos. Comparar regresión ridge/lasso con el modelo inicial, sin escoger el algoritmo en función del desempeño de la muestra de prueba.
Conclusión. El ejercicio cumple el ciclo de conceptualización, selección, ajuste, diagnóstico y evaluación de un modelo analítico, con separación explícita entre uso académico y eventual aplicación institucional.
Referencias: García Sabaté, Regresión lineal
múltiple: predicción de gastos médicos (RPubs). scikit-learn,
documentación del conjunto load_diabetes.