La diabetes es una de las enfermedades crónicas más comunes y
representa un reto importante para la salud pública.
Este informe busca explorar las características de los pacientes en la
base de datos y analizar los factores asociados con la presencia de
diabetes.
¿Cuáles son las variables clínicas y demográficas que muestran mayor relación con el diagnóstico de diabetes?
Se procede a realizar una vista general del dataset en el cual se evidencia que hay 768 registros y 9 variables, entre las cuales se encuentran características clínicas como el número de embarazos, niveles de glucosa, presión arterial, grosor de la piel, insulina, índice de masa corporal (BMI), edad y el resultado del diagnóstico de diabetes (Outcome).
summary(datos)
## Pregnancies Glucose BloodPressure SkinThickness
## Min. : 0.000 Min. : 0.0 Min. : 0.00 Min. : 0.00
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 62.00 1st Qu.: 0.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :23.00
## Mean : 3.845 Mean :120.9 Mean : 69.11 Mean :20.54
## 3rd Qu.: 6.000 3rd Qu.:140.2 3rd Qu.: 80.00 3rd Qu.:32.00
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.00
## Insulin BMI DiabetesPedigreeFunction Age
## Min. : 0.0 Min. : 0.00 Min. :0.0780 Min. :21.00
## 1st Qu.: 0.0 1st Qu.:27.30 1st Qu.:0.2437 1st Qu.:24.00
## Median : 30.5 Median :32.00 Median :0.3725 Median :29.00
## Mean : 79.8 Mean :31.99 Mean :0.4719 Mean :33.24
## 3rd Qu.:127.2 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.0 Max. :67.10 Max. :2.4200 Max. :81.00
## Outcome
## Min. :0.000
## 1st Qu.:0.000
## Median :0.000
## Mean :0.349
## 3rd Qu.:1.000
## Max. :1.000
table(datos$Outcome)
##
## 0 1
## 500 268
prop.table(table(datos$Outcome))
##
## 0 1
## 0.6510417 0.3489583
library(tidyr)
library(ggplot2)
# Preparar datos en formato largo y normalizar (0-100%)
datos_density <- datos %>%
mutate(Outcome = ifelse(Outcome == "Diabetes", 1, 0)) %>%
select(Glucose, BMI, Age, Pregnancies,
DiabetesPedigreeFunction, Insulin) %>%
mutate(across(everything(), ~ (. - min(., na.rm=TRUE)) /
(max(., na.rm=TRUE) - min(., na.rm=TRUE)) * 100)) %>%
pivot_longer(everything(),
names_to = "Variable",
values_to = "Valor") %>%
mutate(Variable = recode(Variable,
"Glucose" = "Glucosa",
"BMI" = "IMC (BMI)",
"Age" = "Edad",
"Pregnancies" = "Embarazos",
"DiabetesPedigreeFunction" = "Pedigree Diabético",
"Insulin" = "Insulina"
))
# Gráfico de densidad
ggplot(datos_density, aes(x = Valor, fill = Variable, color = Variable)) +
geom_density(alpha = 0.35, linewidth = 0.8) +
scale_x_continuous(labels = function(x) paste0(x, "%")) +
labs(
title = "Distribución de variables clínicas y demográficas",
subtitle = "Dataset Pima Indians Diabetes | Variables normalizadas (0–100%)",
x = "Porcentaje (valor normalizado)",
y = "Densidad (Frecuencia por porcentaje de desigualdad)",
fill = "Variable",
color = "Variable",
caption = "Fuente: Pima Indians Diabetes Dataset"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50"),
plot.caption = element_text(hjust = 1, color = "gray50"),
legend.position = "right",
panel.grid.minor = element_blank()
)
Este gráfico de densidad revela que Glucosa es la variable con
distribución más amplia y centrada, lo que explica su alto poder
discriminatorio entre pacientes diabéticos y no diabéticos. Variables
como Insulina y Embarazos presentan distribuciones muy sesgadas hacia
valores bajos, con colas largas que indican presencia de valores
extremos. Este panorama inicial justifica la necesidad de un análisis
multivariado para controlar estas diferencias de distribución.
Se procede a convertir la variable Outcome en un factor con etiquetas más descriptivas para facilitar su interpretación en los análisis posteriores.
datos <- datos %>%
mutate(Outcome = factor(Outcome, levels = c(0,1),
labels = c("No Diabetes", "Diabetes")))
datos %>%
count(Outcome) %>%
mutate(porcentaje = round(n / sum(n) * 100, 1))
## Outcome n porcentaje
## 1 No Diabetes 500 65.1
## 2 Diabetes 268 34.9
Se realiza el siguiente analisis para determinar en cuáles variables difieren más los pacientes con y sin diabetes.
datos %>%
group_by(Outcome) %>%
summarise(
Glucosa = mean(Glucose, na.rm = TRUE),
PresionArterial = mean(BloodPressure, na.rm = TRUE),
BMI = mean(BMI, na.rm = TRUE),
Insulina = mean(Insulin, na.rm = TRUE),
Edad = mean(Age, na.rm = TRUE),
Embarazos = mean(Pregnancies, na.rm = TRUE),
Pedigree = mean(DiabetesPedigreeFunction, na.rm = TRUE)
) %>%
pivot_longer(-Outcome, names_to = "Variable", values_to = "Media") %>%
pivot_wider(names_from = Outcome, values_from = Media) %>%
mutate(Diferencia_pct = round((Diabetes - `No Diabetes`) / `No Diabetes` * 100, 1))
## # A tibble: 7 × 4
## Variable `No Diabetes` Diabetes Diferencia_pct
## <chr> <dbl> <dbl> <dbl>
## 1 Glucosa 110. 141. 28.4
## 2 PresionArterial 68.2 70.8 3.9
## 3 BMI 30.3 35.1 16
## 4 Insulina 68.8 100. 45.9
## 5 Edad 31.2 37.1 18.8
## 6 Embarazos 3.30 4.87 47.5
## 7 Pedigree 0.430 0.550 28.1
En conjunto, las variables clínicas con mayor relación al diagnóstico de diabetes son Glucosa, Insulina y BMI, mientras que entre las variables demográficas destacan Edad y Embarazos. La Presión Arterial sería la variable de menor utilidad predictiva en este dataset.
# Seleccionar variables numéricas y convertir a formato largo
datos %>%
select(Outcome, Glucose, BloodPressure, BMI, Insulin,
Age, Pregnancies, DiabetesPedigreeFunction) %>%
pivot_longer(-Outcome, names_to = "Variable", values_to = "Valor") %>%
ggplot(aes(x = Outcome, y = Valor, fill = Outcome)) +
geom_boxplot(alpha = 0.7, outlier.colour = "red", outlier.size = 1.5) +
facet_wrap(~ Variable, scales = "free_y", ncol = 3) +
scale_fill_manual(values = c("#2196F3", "#F44336")) +
labs(
title = "Distribución de variables clínicas y demográficas por diagnóstico de diabetes",
x = "Diagnóstico",
y = "Valor",
fill = "Diagnóstico"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50"),
legend.position = "bottom",
strip.text = element_text(face = "bold")
)
Glucose es visualmente la variable más discriminativa. Le siguen BMI y
Age. BloodPressure confirma ser la variable de menor utilidad
diagnóstica. Insulin muestra diferencias pero con mucha variabilidad, lo
que puede afectar su peso en el modelo.
se evidencia graficamente que Glucose es visualmente la variable más discriminativa. Le siguen BMI y Age. BloodPressure confirma ser la variable de menor utilidad diagnóstica. Insulina muestra diferencias pero con mucha variabilidad, lo que puede afectar su peso en el modelo.
El BMI muestra una asociación clara y consistente con el diagnóstico de diabetes. Los pacientes diabéticos presentan en promedio un IMC en rango de obesidad, mientras que los no diabéticos se ubican en sobrepeso. La separación entre ambas distribuciones, aunque con cierto solapamiento, confirma al BMI como una variable clínicamente relevante para el diagnóstico de diabetes en esta muestra. Este hallazgo es coherente con la evidencia científica que establece la obesidad como uno de los principales factores de riesgo para diabetes tipo 2.
ggplot(datos, aes(x = Age, y = Glucose, color = factor(Outcome))) +
geom_point(alpha = 0.6, size = 2) +
geom_smooth(method = "lm", se = TRUE, linewidth = 1) +
scale_color_manual(values = c("steelblue", "tomato"),
labels = c("No Diabetes", "Diabetes")) +
labs(
title = "Relación entre Edad y Glucosa según diagnóstico de diabetes",
subtitle = "Cada punto representa un paciente | Línea de tendencia por grupo",
x = "Edad (años)",
y = "Glucosa (mg/dL)",
color = "Diagnóstico"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50"),
legend.position = "bottom"
)
La glucosa mantiene una separación consistente entre grupos en todos los rangos de edad, siendo mayor en pacientes diabéticos a lo largo de toda la distribución etaria. Sin embargo, la brecha se amplía progresivamente con la edad, lo que sugiere que la combinación de edad avanzada + glucosa elevada es un indicador especialmente fuerte para el diagnóstico de diabetes. Este gráfico refuerza la necesidad de incluir ambas variables en el modelo predictivo.
# Convertir Outcome a numérico para la regresión
datos_modelo <- datos %>%
mutate(Outcome = ifelse(Outcome == "Diabetes", 1, 0))
# Modelo de regresión logística con todas las variables
modelo <- glm(Outcome ~ Glucose + BloodPressure + BMI +
Insulin + Age + Pregnancies +
DiabetesPedigreeFunction,
data = datos_modelo,
family = binomial)
# Ver resultados
summary(modelo)
##
## Call:
## glm(formula = Outcome ~ Glucose + BloodPressure + BMI + Insulin +
## Age + Pregnancies + DiabetesPedigreeFunction, family = binomial,
## data = datos_modelo)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -8.4051362 0.7167033 -11.727 < 2e-16 ***
## Glucose 0.0351123 0.0036625 9.587 < 2e-16 ***
## BloodPressure -0.0132136 0.0051537 -2.564 0.010350 *
## BMI 0.0900886 0.0144619 6.229 4.68e-10 ***
## Insulin -0.0011570 0.0008142 -1.421 0.155275
## Age 0.0147888 0.0092897 1.592 0.111393
## Pregnancies 0.1231724 0.0320688 3.841 0.000123 ***
## DiabetesPedigreeFunction 0.9475954 0.2980063 3.180 0.001474 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 993.48 on 767 degrees of freedom
## Residual deviance: 723.45 on 760 degrees of freedom
## AIC: 739.45
##
## Number of Fisher Scoring iterations: 5
# Odds Ratios con intervalos de confianza
exp(cbind(OR = coef(modelo), confint(modelo)))
## Waiting for profiling to be done...
## OR 2.5 % 97.5 %
## (Intercept) 0.0002237153 5.217689e-05 0.0008687979
## Glucose 1.0357359660 1.028526e+00 1.0434178749
## BloodPressure 0.9868733421 9.768200e-01 0.9968229716
## BMI 1.0942712200 1.064449e+00 1.1266101512
## Insulin 0.9988436337 9.972460e-01 1.0004466634
## Age 1.0148987338 9.965014e-01 1.0335586474
## Pregnancies 1.1310794588 1.062820e+00 1.2054181681
## DiabetesPedigreeFunction 2.5794994240 1.447469e+00 4.6581035431
La Insulina mostró diferencias grandes en el análisis bivariado (+45.9%) pero no es significativa en la regresión logística. Esto se explica porque su efecto está capturado por la Glucosa, con la que tiene alta correlación.
tidy(modelo, exponentiate = TRUE, conf.int = TRUE) %>%
filter(term != "(Intercept)") %>%
mutate(
term = recode(term,
"Glucose" = "Glucosa",
"BloodPressure" = "Presión Arterial",
"BMI" = "IMC (BMI)",
"Insulin" = "Insulina",
"Age" = "Edad",
"Pregnancies" = "Embarazos",
"DiabetesPedigreeFunction" = "Pedigree Diabético"
),
significativo = ifelse(p.value < 0.05, "Significativo", "No significativo"),
term = reorder(term, estimate)
) %>%
ggplot(aes(x = estimate, y = term, color = significativo)) +
geom_point(size = 4) +
geom_errorbarh(aes(xmin = conf.low, xmax = conf.high), height = 0.3, linewidth = 0.8) +
geom_vline(xintercept = 1, linetype = "dashed", color = "gray40", linewidth = 0.8) +
scale_color_manual(values = c("Significativo" = "#E53935", "No significativo" = "#90A4AE")) +
labs(
title = "Odds Ratios de variables asociadas al diagnóstico de diabetes",
subtitle = "Regresión logística multivariada | IC 95% | Línea punteada = OR de referencia (1.0)",
x = "Odds Ratio (OR)",
y = "Variable",
color = "Significancia estadística"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50"),
legend.position = "bottom"
)
## Warning: `geom_errorbarh()` was deprecated in ggplot2 4.0.0.
## ℹ Please use the `orientation` argument of `geom_errorbar()` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `height` was translated to `width`.
El gráfico confirma visualmente que Pedigree Diabético, Embarazos, BMI y
Glucosa son las variables con asociación estadísticamente significativa
y positiva con el diagnóstico de diabetes. Pedigree Diabético destaca
como el predictor más fuerte aunque con mayor incertidumbre, mientras
que Glucosa y BMI ofrecen estimaciones más precisas y consistentes.
Insulina y Edad no logran demostrar un efecto independiente en el modelo
multivariado.
# Obtener probabilidades predichas del modelo
datos_modelo$prob_pred <- predict(modelo, type = "response")
# Calcular la curva ROC
roc_obj <- roc(datos_modelo$Outcome, datos_modelo$prob_pred)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
# Ver el AUC
auc(roc_obj)
## Area under the curve: 0.8396
Grafico de la curva de ROC
# Convertir a dataframe para ggplot
roc_df <- data.frame(
Especificidad = 1 - roc_obj$specificities,
Sensibilidad = roc_obj$sensitivities
)
# Valor AUC para el gráfico
auc_valor <- round(auc(roc_obj), 3)
# Gráfico
ggplot(roc_df, aes(x = Especificidad, y = Sensibilidad)) +
geom_line(color = "#E53935", linewidth = 1.2) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed",
color = "gray50", linewidth = 0.8) +
geom_area(fill = "#E53935", alpha = 0.1) +
annotate("text", x = 0.65, y = 0.25,
label = paste0("AUC = ", auc_valor),
size = 5, fontface = "bold", color = "#E53935") +
labs(
title = "Curva ROC — Modelo de Regresión Logística",
subtitle = "Diagnóstico de diabetes | Línea punteada = clasificador aleatorio",
x = "1 - Especificidad (Tasa de Falsos Positivos)",
y = "Sensibilidad (Tasa de Verdaderos Positivos)"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "gray50")
)
roc_obj <- roc(datos_modelo$Outcome,
datos_modelo$prob_pred,
direction = "<")
Con un AUC de 0.84, el modelo de regresión logística construido con las variables Glucosa, BMI, Pedigree Diabético, Embarazos y Presión Arterial demuestra una buena capacidad diagnóstica para identificar pacientes con diabetes. Este resultado valida y respalda las conclusiones del análisis, confirmando que las variables identificadas como significativas no solo tienen asociación estadística, sino que en conjunto constituyen un modelo predictivo clínicamente útil.