# Ver las primeras filas del dataset
head(diabetes)
## # A tibble: 6 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 6 148 72 35 0 33.6
## 2 1 85 66 29 0 26.6
## 3 8 183 64 0 0 23.3
## 4 1 89 66 23 94 28.1
## 5 0 137 40 35 168 43.1
## 6 5 116 74 0 0 25.6
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
# Resumen estadístico de las variables
summary(diabetes)
## 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
Glucose, BloodPressure, SkinThickness, Insulin y BMI tienen valores mínimos de 0.0, lo cual no es realista en datos médicos. Estos ceros deberían tratarse como valores faltantes (NA).
# Reemplazar valores 0 por NA en variables donde no tiene sentido un 0
diabetes <- diabetes %>%
mutate(
Glucose = ifelse(Glucose == 0, NA, Glucose),
BloodPressure = ifelse(BloodPressure == 0, NA, BloodPressure),
SkinThickness = ifelse(SkinThickness == 0, NA, SkinThickness),
Insulin = ifelse(Insulin == 0, NA, Insulin),
BMI = ifelse(BMI == 0, NA, BMI)
)
# Verificar si hay valores NA ahora
# Verificar valores faltantes
colSums(is.na(diabetes))
## Pregnancies Glucose BloodPressure
## 0 5 35
## SkinThickness Insulin BMI
## 227 374 11
## DiabetesPedigreeFunction Age Outcome
## 0 0 0
#¿Por qué hacemos esto? En variables como Glucose o BMI, un valor de 0 no es realista en datos médicos. mutate() nos permite modificar valores en columnas específicas. ifelse() convierte los 0 en NA, sin afectar otros valores.
# 1. Mapa de datos faltantes con VIM
# Este gráfico muestra la proporción de datos faltantes en cada variable.
aggr(diabetes, numbers = TRUE, col = c("navyblue", "red"),
cex.axis = 0.7, gap = 3, ylab = c("Proporción de datos faltantes", "Patrón de datos"))
La variable “Insulin” (Insulina) tiene la mayor proporción de datos faltantes, aproximadamente 0.4 (40%)
“SkinThickness” (Grosor de la piel) tiene alrededor de 0.3 (30%) de datos faltantes
“BloodPressure” (Presión sanguínea) tiene una proporción menor de datos faltantes
Pregnancies, Age y Outcome no tienen valores faltantes.
Los cuadros rojos representan combinaciones de valores faltantes en distintas variables. Se puede notar que los valores faltantes no ocurren al azar; por ejemplo, muchas observaciones tienen Insulin y SkinThickness faltantes al mismo tiempo, lo que podría indicar un patrón relacionado con la toma de mediciones o con el tipo de paciente.
# 2. Gráfico de valores faltantes con naniar
# Este gráfico de barras muestra qué porcentaje de datos faltan en cada variable.
gg_miss_var(diabetes, show_pct = TRUE)
Se confirma que Insulin tiene el mayor porcentaje de valores faltantes (~50%).
SkinThickness sigue con un porcentaje alto (~30%).
BloodPressure tiene alrededor de 5% de valores faltantes.
BMI y Glucose tienen porcentajes bajos, pero no despreciables.
Otras variables como Pregnancies, Age y Outcome tienen 0% de valores faltantes.
# Aplicar imputación
imputed_data <- mice(diabetes, method = "pmm", m = 5)
##
## iter imp variable
## 1 1 Glucose BloodPressure SkinThickness Insulin BMI
## 1 2 Glucose BloodPressure SkinThickness Insulin BMI
## 1 3 Glucose BloodPressure SkinThickness Insulin BMI
## 1 4 Glucose BloodPressure SkinThickness Insulin BMI
## 1 5 Glucose BloodPressure SkinThickness Insulin BMI
## 2 1 Glucose BloodPressure SkinThickness Insulin BMI
## 2 2 Glucose BloodPressure SkinThickness Insulin BMI
## 2 3 Glucose BloodPressure SkinThickness Insulin BMI
## 2 4 Glucose BloodPressure SkinThickness Insulin BMI
## 2 5 Glucose BloodPressure SkinThickness Insulin BMI
## 3 1 Glucose BloodPressure SkinThickness Insulin BMI
## 3 2 Glucose BloodPressure SkinThickness Insulin BMI
## 3 3 Glucose BloodPressure SkinThickness Insulin BMI
## 3 4 Glucose BloodPressure SkinThickness Insulin BMI
## 3 5 Glucose BloodPressure SkinThickness Insulin BMI
## 4 1 Glucose BloodPressure SkinThickness Insulin BMI
## 4 2 Glucose BloodPressure SkinThickness Insulin BMI
## 4 3 Glucose BloodPressure SkinThickness Insulin BMI
## 4 4 Glucose BloodPressure SkinThickness Insulin BMI
## 4 5 Glucose BloodPressure SkinThickness Insulin BMI
## 5 1 Glucose BloodPressure SkinThickness Insulin BMI
## 5 2 Glucose BloodPressure SkinThickness Insulin BMI
## 5 3 Glucose BloodPressure SkinThickness Insulin BMI
## 5 4 Glucose BloodPressure SkinThickness Insulin BMI
## 5 5 Glucose BloodPressure SkinThickness Insulin BMI
# Extraer los datos imputados
diabetes_imputed <- complete(imputed_data)
# Revisar si aún hay NAs
colSums(is.na(diabetes_imputed))
## Pregnancies Glucose BloodPressure
## 0 0 0
## SkinThickness Insulin BMI
## 0 0 0
## DiabetesPedigreeFunction Age Outcome
## 0 0 0
par(mfrow=c(2,3)) # Para ver múltiples gráficos en una sola ventana
hist(diabetes$Glucose, main="Glucose Antes", col="purple")
hist(diabetes_imputed$Glucose, main="Glucose Después", col="pink")
hist(diabetes$BloodPressure, main="BloodPressure Antes", col="purple")
hist(diabetes_imputed$BloodPressure, main="BloodPressure Después", col="pink")
hist(diabetes$Insulin, main="Insulin Antes", col="purple")
hist(diabetes_imputed$Insulin, main="Insulin Después", col="pink")
hist(diabetes$SkinThickness, main="SkinThickness Antes", col="purple")
hist(diabetes_imputed$SkinThickness, main="SkinThickness Después", col="pink")
hist(diabetes$BMI, main="BMI Antes", col="purple")
hist(diabetes_imputed$BMI, main="BMI Después", col="pink")
par(mfrow=c(1,1)) # Volver a un solo gráfico
La imputación de valores faltantes parece haberse realizado de manera correcta, ya que las distribuciones antes y después son muy similares en todas las variables. No se observa la creación de valores atípicos o patrones extraños que puedan indicar una imputación incorrecta.
# Resumen antes de la imputación
print("Resumen antes de la imputación")
## [1] "Resumen antes de la imputación"
summary(diabetes[, c("Glucose", "BloodPressure", "Insulin", "SkinThickness", "BMI")])
## Glucose BloodPressure Insulin SkinThickness
## Min. : 44.0 Min. : 24.00 Min. : 14.00 Min. : 7.00
## 1st Qu.: 99.0 1st Qu.: 64.00 1st Qu.: 76.25 1st Qu.:22.00
## Median :117.0 Median : 72.00 Median :125.00 Median :29.00
## Mean :121.7 Mean : 72.41 Mean :155.55 Mean :29.15
## 3rd Qu.:141.0 3rd Qu.: 80.00 3rd Qu.:190.00 3rd Qu.:36.00
## Max. :199.0 Max. :122.00 Max. :846.00 Max. :99.00
## NA's :5 NA's :35 NA's :374 NA's :227
## BMI
## Min. :18.20
## 1st Qu.:27.50
## Median :32.30
## Mean :32.46
## 3rd Qu.:36.60
## Max. :67.10
## NA's :11
print("Resumen después de la imputación")
## [1] "Resumen después de la imputación"
# Resumen después de la imputación
summary(diabetes_imputed[, c("Glucose", "BloodPressure", "Insulin", "SkinThickness", "BMI")])
## Glucose BloodPressure Insulin SkinThickness BMI
## Min. : 44.0 Min. : 24.00 Min. : 14 Min. : 7.00 Min. :18.20
## 1st Qu.: 99.0 1st Qu.: 64.00 1st Qu.: 77 1st Qu.:21.00 1st Qu.:27.50
## Median :117.0 Median : 72.00 Median :125 Median :29.00 Median :32.35
## Mean :121.6 Mean : 72.28 Mean :155 Mean :28.83 Mean :32.48
## 3rd Qu.:141.0 3rd Qu.: 80.00 3rd Qu.:190 3rd Qu.:36.00 3rd Qu.:36.73
## Max. :199.0 Max. :122.00 Max. :846 Max. :99.00 Max. :67.10
Las estadísticas descriptivas antes y después de la imputación son casi idénticas. Se observan diferencias leves en la media y la mediana de algunas variables como Insulin y SkinThickness, pero en general, los valores se mantienen similares.
# Prueba de Kolmogorov-Smirnov para comparar distribuciones
ks.test(diabetes$Glucose, diabetes_imputed$Glucose)
##
## Asymptotic two-sample Kolmogorov-Smirnov test
##
## data: diabetes$Glucose and diabetes_imputed$Glucose
## D = 0.0031127, p-value = 1
## alternative hypothesis: two-sided
ks.test(diabetes$BloodPressure, diabetes_imputed$BloodPressure)
##
## Asymptotic two-sample Kolmogorov-Smirnov test
##
## data: diabetes$BloodPressure and diabetes_imputed$BloodPressure
## D = 0.0071037, p-value = 1
## alternative hypothesis: two-sided
ks.test(diabetes$Insulin, diabetes_imputed$Insulin)
##
## Asymptotic two-sample Kolmogorov-Smirnov test
##
## data: diabetes$Insulin and diabetes_imputed$Insulin
## D = 0.019042, p-value = 1
## alternative hypothesis: two-sided
ks.test(diabetes$SkinThickness, diabetes_imputed$SkinThickness)
##
## Asymptotic two-sample Kolmogorov-Smirnov test
##
## data: diabetes$SkinThickness and diabetes_imputed$SkinThickness
## D = 0.01931, p-value = 0.9998
## alternative hypothesis: two-sided
ks.test(diabetes$BMI, diabetes_imputed$BMI)
##
## Asymptotic two-sample Kolmogorov-Smirnov test
##
## data: diabetes$BMI and diabetes_imputed$BMI
## D = 0.0046682, p-value = 1
## alternative hypothesis: two-sided
Los valores p de Kolmogorov-Smirnov son todos altos (p > 0.05), lo que indica que no hay una diferencia significativa entre las distribuciones originales e imputadas. Esto sugiere que la imputación no alteró la forma de la distribución de los datos.
#Variables numéricas a analizar
vars_numericas <- c("Glucose", "BloodPressure", "SkinThickness", "Insulin", "BMI")
# Histogramas
histogramas <- lapply(vars_numericas, function(var) {
ggplot(diabetes, aes_string(x = var)) +
geom_histogram(bins = 30, fill = "steelblue", color = "black") +
theme_minimal() +
labs(title = paste("Histograma de", var), x = var, y = "Frecuencia")
})
# Mostrar gráficos en una cuadrícula
grid.arrange(grobs = histogramas, ncol = 2)
Se puede observar que las variables Glucose, BloodPressure y BMI tienen distribuciones aproximadamente normales, aunque con algunos valores extremos.
SkinThickness e Insulin presentan sesgo a la derecha, con una concentración de valores en la parte baja del histograma y colas largas.
# Boxplots
boxplots <- lapply(vars_numericas, function(var) {
ggplot(diabetes, aes_string(y = var)) +
geom_boxplot(fill = "tomato", color = "black", outlier.color = "red", outlier.shape = 16) +
theme_minimal() +
labs(title = paste("Boxplot de", var), y = var)
})
# Mostrar gráficos en una cuadrícula
grid.arrange(grobs = boxplots, ncol = 2)
Se observan valores atípicos en Glucose, BloodPressure, SkinThickness, Insulin y BMI.
Insulin tiene muchos valores atípicos por encima del tercer cuartil.
SkinThickness y BMI presentan valores extremos en la parte superior.
Para abordar la presencia de valores atípicos en los datos, se implementó una estrategia basada en el uso de percentiles y el rango intercuartílico (IQR). Se identificaron como atípicos aquellos valores que se encontraban por debajo del primer cuartil menos 1.5 veces el IQR, o por encima del tercer cuartil más 1.5 veces el IQR.
Q1 <- quantile(diabetes_imputed$BloodPressure, 0.25, na.rm = TRUE)
Q3 <- quantile(diabetes_imputed$BloodPressure, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
diabetes_imputed$BloodPressure <- ifelse(diabetes_imputed$BloodPressure < lower_bound, lower_bound, ifelse(diabetes_imputed$BloodPressure > upper_bound, upper_bound, diabetes_imputed$BloodPressure))
Q1 <- quantile(diabetes_imputed$BMI, 0.25, na.rm = TRUE)
Q3 <- quantile(diabetes_imputed$BMI, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
diabetes_imputed$BMI <- ifelse(diabetes_imputed$BMI < lower_bound, lower_bound, ifelse(diabetes_imputed$BMI > upper_bound, upper_bound, diabetes_imputed$BMI))
Q1 <- quantile(diabetes_imputed$Insulin, 0.25, na.rm = TRUE)
Q3 <- quantile(diabetes_imputed$Insulin, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
diabetes_imputed$Insulin <- ifelse(diabetes_imputed$Insulin < lower_bound, lower_bound, ifelse(diabetes_imputed$Insulin > upper_bound, upper_bound, diabetes_imputed$Insulin))
Q1 <- quantile(diabetes_imputed$SkinThickness, 0.25, na.rm = TRUE)
Q3 <- quantile(diabetes_imputed$SkinThickness, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
diabetes_imputed$SkinThickness <- ifelse(diabetes_imputed$SkinThickness < lower_bound, lower_bound, ifelse(diabetes_imputed$SkinThickness > upper_bound, upper_bound, diabetes_imputed$SkinThickness))
# Gráfico de valores faltantes con porcentaje
gg_miss_var(diabetes_imputed, show_pct = TRUE) +
labs(title = "Porcentaje de Datos atipicos por Variable") +
theme_minimal()
Vemos que después de la imputación de los datos ya no tenemos ningun dato atípico.
ggplot(diabetes_imputed, aes(y = BMI)) + geom_boxplot(fill = "purple", alpha = 0.5) + theme_minimal()
ggplot(diabetes_imputed, aes(y = Insulin)) + geom_boxplot(fill = "purple", alpha = 0.5) + theme_minimal()
ggplot(diabetes_imputed, aes(y = BloodPressure)) + geom_boxplot(fill = "purple", alpha = 0.5) + theme_minimal()
ggplot(diabetes_imputed, aes(y = SkinThickness)) + geom_boxplot(fill = "purple", alpha = 0.5) + theme_minimal()