true

Explorar los datos

# 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).

Remplazar 0 por 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.

Visualizar datos faltantes

# 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"))

# 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)

Imputación de datos faltantes con el método PMM

# 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.

Detección de los valores atípicos

#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)

# 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)

Imputación de los valores atípicos

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()