Dataset

df = read.csv("C:/Users/johan/Downloads/diabetes.csv", sep=",", header=TRUE, fileEncoding = "UTF-8")

Variables

  • Pregnancies: Número de embarazos.
  • Glucose: Concentración de glucosa.
  • BloodPressure: Presión arterial diastólica.
  • SkinThickness: Grosor del pliegue cutáneo del tríceps.
  • Insulin: Insulina sérica.
  • BMI: Índice de masa corporal (peso en kg / (altura en m)^2).
  • DiabetesPedigreeFunction: Una función que pondera genéticamente el riesgo de diabetes en relación con la historia familiar.
  • Age: Edad del paciente.
  • Outcome: La variable de resultado, donde 1 indica que el paciente tiene diabetes y 0 indica que no la tiene.

suppressWarnings({

require(dplyr)
require(tibble)
library(pracma)
require(stringr)
require(ggplot2)
require(ggpubr)
require(e1071)
require(psych)
library(reshape2)
library(Hmisc)
library(Amelia)
library(mice)
library(foreign)
library(ggplot2)
library(gridExtra)
library(hrbrthemes)
library(outliers)
library(ggplot2)
library(dplyr)
library(psych)
library(reshape2)
library(GGally)
library(factoextra)
library(EnvStats)
library(tidyr)
        
})
## Cargando paquete requerido: dplyr
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Cargando paquete requerido: tibble
## Cargando paquete requerido: stringr
## Cargando paquete requerido: ggplot2
## Cargando paquete requerido: ggpubr
## Cargando paquete requerido: e1071
## 
## Adjuntando el paquete: 'e1071'
## The following object is masked from 'package:pracma':
## 
##     sigmoid
## Cargando paquete requerido: psych
## 
## Adjuntando el paquete: 'psych'
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
## The following objects are masked from 'package:pracma':
## 
##     logit, polar
## 
## Adjuntando el paquete: 'Hmisc'
## The following object is masked from 'package:psych':
## 
##     describe
## The following object is masked from 'package:e1071':
## 
##     impute
## The following object is masked from 'package:pracma':
## 
##     ceil
## The following objects are masked from 'package:dplyr':
## 
##     src, summarize
## The following objects are masked from 'package:base':
## 
##     format.pval, units
## Cargando paquete requerido: Rcpp
## ## 
## ## Amelia II: Multiple Imputation
## ## (Version 1.8.3, built: 2024-11-07)
## ## Copyright (C) 2005-2025 James Honaker, Gary King and Matthew Blackwell
## ## Refer to http://gking.harvard.edu/amelia/ for more information
## ##
## 
## Adjuntando el paquete: 'mice'
## The following object is masked from 'package:stats':
## 
##     filter
## The following objects are masked from 'package:base':
## 
##     cbind, rbind
## 
## Adjuntando el paquete: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
## 
## Adjuntando el paquete: 'outliers'
## The following object is masked from 'package:psych':
## 
##     outlier
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
## 
## Adjuntando el paquete: 'EnvStats'
## The following object is masked from 'package:Hmisc':
## 
##     stripChart
## The following objects are masked from 'package:e1071':
## 
##     kurtosis, skewness
## The following objects are masked from 'package:stats':
## 
##     predict, predict.lm
## The following object is masked from 'package:base':
## 
##     print.default
## 
## Adjuntando el paquete: 'tidyr'
## The following object is masked from 'package:reshape2':
## 
##     smiths

Mostramos las primeras y ultimas filas de la base de datos para ver como esta estructurado.

head(df)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 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
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0
tail(df)
##     Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 763           9      89            62             0       0 22.5
## 764          10     101            76            48     180 32.9
## 765           2     122            70            27       0 36.8
## 766           5     121            72            23     112 26.2
## 767           1     126            60             0       0 30.1
## 768           1      93            70            31       0 30.4
##     DiabetesPedigreeFunction Age Outcome
## 763                    0.142  33       0
## 764                    0.171  63       0
## 765                    0.340  27       0
## 766                    0.245  30       0
## 767                    0.349  47       1
## 768                    0.315  23       0

Ahora analizaremos la naturaleza de las variables de nuestra base de datos.

glimpse(df)
## Rows: 768
## Columns: 9
## $ Pregnancies              <int> 6, 1, 8, 1, 0, 5, 3, 10, 2, 8, 4, 10, 10, 1, …
## $ Glucose                  <int> 148, 85, 183, 89, 137, 116, 78, 115, 197, 125…
## $ BloodPressure            <int> 72, 66, 64, 66, 40, 74, 50, 0, 70, 96, 92, 74…
## $ SkinThickness            <int> 35, 29, 0, 23, 35, 0, 32, 0, 45, 0, 0, 0, 0, …
## $ Insulin                  <int> 0, 0, 0, 94, 168, 0, 88, 0, 543, 0, 0, 0, 0, …
## $ BMI                      <dbl> 33.6, 26.6, 23.3, 28.1, 43.1, 25.6, 31.0, 35.…
## $ DiabetesPedigreeFunction <dbl> 0.627, 0.351, 0.672, 0.167, 2.288, 0.201, 0.2…
## $ Age                      <int> 50, 31, 32, 21, 33, 30, 26, 29, 53, 54, 30, 3…
## $ Outcome                  <int> 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, …

Vemos que tenemos 9 columnas de variables con 768 observaciones, de las cuales 7 columnas son de tipo entero y 2 de tipo decimal.


Reemplazaremos los valores 0.0 por Na para luego realizar el tratamiento de estos datos.

df$Glucose[df$Glucose == 0.0] <- NA
df$BloodPressure[df$BloodPressure == 0.0] <- NA
df$SkinThickness[df$SkinThickness == 0.0] <- NA
df$Insulin[df$Insulin == 0.0] <- NA
df$BMI[df$BMI == 0.0] <- NA

Calculamos el número de valores faltantes para cada variable del DataFrame.

colSums(is.na(df))
##              Pregnancies                  Glucose            BloodPressure 
##                        0                        5                       35 
##            SkinThickness                  Insulin                      BMI 
##                      227                      374                       11 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                        0                        0                        0
colMeans(is.na(df)) * 100
##              Pregnancies                  Glucose            BloodPressure 
##                0.0000000                0.6510417                4.5572917 
##            SkinThickness                  Insulin                      BMI 
##               29.5572917               48.6979167                1.4322917 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                0.0000000                0.0000000                0.0000000
missmap(df, col = c("red", "#FBD000"), legend = TRUE)

Vemos que la variable Glucose tiene 5 datos faltantes, Bloodpressure tiene 35, SkinThickness tiene 227, Insulin tiene 374 y BMI tiene 11 datos faltantes. Estos equivalen a un 9% de datos faltantes del total de datos.


Imputación de datos

Vamos a realizar la imputación de los datos usando diversas tecnicas.

Las variables a las que le vamos a aplicar las tecnicas de imputacion son las siguientes:

  • SkinThickness: 29.55 % de datos faltantes
  • Insulin: 48.69 % de datos faltantes
  • Glucose: 0.65 % de datos faltantes
  • BloodPressure: 4.55 % de datos faltantes
  • BMI: 1.43 % de datos faltantes

Pruebas de normalidad

Guardamos el dataframe original y verificamos sus distribuciones para luego compararlos con los nuevos datos.

#dataset original
previo_df <- df
# Pregnancies
shapiro_pregnancies <- shapiro.test(df$Pregnancies)
print(shapiro_pregnancies)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$Pregnancies
## 
## Test Statistic:                  W = 0.9042813
## 
## P-value:                         1.609257e-21

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# Glucose
shapiro_glucose <- shapiro.test(df$Glucose)
print(shapiro_glucose)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$Glucose
## 
## Test Statistic:                  W = 0.9696409
## 
## P-value:                         1.720326e-11

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# BloodPressure
shapiro_bloodpressure <- shapiro.test(df$BloodPressure)
print(shapiro_bloodpressure)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$BloodPressure
## 
## Test Statistic:                  W = 0.9903145
## 
## P-value:                         9.45138e-05

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# SkinThickness
shapiro_skinthickness <- shapiro.test(df$SkinThickness)
print(shapiro_skinthickness)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$SkinThickness
## 
## Test Statistic:                  W = 0.9679992
## 
## P-value:                         1.775691e-09

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# Insulin
shapiro_insulin <- shapiro.test(df$Insulin)
print(shapiro_insulin)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$Insulin
## 
## Test Statistic:                  W = 0.8040996
## 
## P-value:                         1.698218e-21

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# BMI
shapiro_bmi <- shapiro.test(df$BMI)
print(shapiro_bmi)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$BMI
## 
## Test Statistic:                  W = 0.9795543
## 
## P-value:                         8.557785e-09

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# DiabetesPedigreeFunction
shapiro_dpf <- shapiro.test(df$DiabetesPedigreeFunction)
print(shapiro_dpf)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$DiabetesPedigreeFunction
## 
## Test Statistic:                  W = 0.8365181
## 
## P-value:                         2.477506e-27

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

# Age
shapiro_age <- shapiro.test(df$Age)
print(shapiro_age)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df$Age
## 
## Test Statistic:                  W = 0.8747669
## 
## P-value:                         2.402274e-24

Vemos que el p-valor es menor que el nivel de significancia (0.05), por lo que la variable no tiene una distribución normal.

Todas nuestras variables coinciden en que no siguen una distribución normal.


Imputación por PMM

Este metodo reemplaza los valores faltantes con valores observados que son similares en términos de predicción, manteniendo la coherencia y la distribución original de los datos. Este enfoque es especialmente útil para evitar imputaciones irreales y preservar las características estadísticas del conjunto de datos.

mostramos nuevamente la tabla para ver como se ven las primeras filas de SKinThickess y Insulin

head(previo_df)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35      NA 33.6
## 2           1      85            66            29      NA 26.6
## 3           8     183            64            NA      NA 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74            NA      NA 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0

Aplicamos ahora el metodo de imputación por emparejamiento predictivo medio.

imp <- mice(df, m=5, maxit=50, method ='pmm', seed=500, printFlag = FALSE)

df_pmm <- complete(imp, 1)

Luego de aplicado este metodo, vamos a ver las primeras filas del dataset ya imputado para comprobar que no tenemos NA

head(df_pmm)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35      83 33.6
## 2           1      85            66            29      55 26.6
## 3           8     183            64            20     175 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74            24     175 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0
colSums(is.na(df_pmm))
##              Pregnancies                  Glucose            BloodPressure 
##                        0                        0                        0 
##            SkinThickness                  Insulin                      BMI 
##                        0                        0                        0 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                        0                        0                        0

Con el Comando Colsums comprobamos que se aplico el metodo de forma correcta, obteniendo 0 datos faltantes en cada variable.

Análisis de Distribución

  • Realizaremos un histograma para verificar inicialmente de forma grafica si nuestra variable SkinThickness mantuvo o no la distribución, esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp1 <- ggplot(data.frame(value=previo_df$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp2 <- ggplot(data.frame(value=df_pmm$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp1, ggp2, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_pmm <- shapiro.test(df_pmm$SkinThickness)
print(shapiro_pmm)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_pmm$SkinThickness
## 
## Test Statistic:                  W = 0.9731303
## 
## P-value:                         1.121809e-10

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no parametrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para SkinThickness- PMM

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$SkinThickness, df_pmm$SkinThickness)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$SkinThickness and df_pmm$SkinThickness
## D = 0.017481, p-value = 1
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


  • Ahora realizaremos el analisis anterior a la variable Insulin, estos es, un histograma para verificar inicialmente de forma grafica si nuestra imputación afecto o no la distribución, esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp3 <- ggplot(data.frame(value=previo_df$Insulin), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp4 <- ggplot(data.frame(value=df_pmm$Insulin), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp3, ggp4, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_pmm_2 <- shapiro.test(df_pmm$Insulin)
print(shapiro_pmm_2)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_pmm$Insulin
## 
## Test Statistic:                  W = 0.7981324
## 
## P-value:                         7.952825e-30

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para Insulin- PMM

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$Insulin, df_pmm$Insulin)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$Insulin and df_pmm$Insulin
## D = 0.034218, p-value = 0.9206
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


Imputación por norm.predict

Este método utiliza un modelo de regresión lineal para predecir los valores faltantes. Para cada variable con datos faltantes, se ajusta un modelo de regresión lineal que usa las otras variables del conjunto de datos como predictores.

mostramos nuevamente la tabla para ver como se ven las primeras filas de SKinThickess y Insulin

head(previo_df)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35      NA 33.6
## 2           1      85            66            29      NA 26.6
## 3           8     183            64            NA      NA 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74            NA      NA 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0

Aplicamos ahora el metodo de norm.predict

imp_norm <- mice(df, m=5, maxit=50, method = 'norm.predict', seed = 500, printFlag = FALSE)

df_norm_predict <- complete(imp_norm, 1)

Luego de aplicado este método, vamos a ver las primeras filas del dataset ya imputado para comprobar que no tenemos NA

head(df_norm_predict)
##   Pregnancies Glucose BloodPressure SkinThickness   Insulin  BMI
## 1           6     148            72      35.00000 220.41825 33.6
## 2           1      85            66      29.00000  69.60061 26.6
## 3           8     183            64      21.44380 256.23203 23.3
## 4           1      89            66      23.00000  94.00000 28.1
## 5           0     137            40      35.00000 168.00000 43.1
## 6           5     116            74      21.87459 117.51189 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0
colSums(is.na(df_norm_predict))
##              Pregnancies                  Glucose            BloodPressure 
##                        0                        0                        0 
##            SkinThickness                  Insulin                      BMI 
##                        0                        0                        0 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                        0                        0                        0

Con el Comando Colsums comprobamos que se aplico el metodo de forma correcta, obteniendo 0 datos faltantes en cada variable.

Análisis de Distribución

  • Realizaremos un histograma para verificar inicialmente de forma grafica si nuestra variable SkinThickness mantuvo o no la distribución, esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp1 <- ggplot(data.frame(value=previo_df$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp2 <- ggplot(data.frame(value=df_norm_predict$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp1, ggp2, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_norm_predict <- shapiro.test(df_norm_predict$SkinThickness)
print(shapiro_norm_predict)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_norm_predict$SkinThickness
## 
## Test Statistic:                  W = 0.9709169
## 
## P-value:                         3.126631e-11

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para SkinThickness- Norm.predict

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$SkinThickness, df_norm_predict$SkinThickness)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$SkinThickness and df_norm_predict$SkinThickness
## D = 0.045395, p-value = 0.53
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


  • Ahora realizaremos el analisis anterior a la variable Insulin, estos es, un histograma para verificar inicialmente de forma grafica si nuestra imputación afecto o no la distribución. Esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp3 <- ggplot(data.frame(value=previo_df$Insulin), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp4 <- ggplot(data.frame(value=df_norm_predict$Insulin), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp3, ggp4, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_norm_predict_2 <- shapiro.test(df_norm_predict$Insulin)
print(shapiro_norm_predict_2)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_norm_predict$Insulin
## 
## Test Statistic:                  W = 0.8478726
## 
## P-value:                         1.654757e-26

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para Insulin- Norm.predict

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$Insulin, df_norm_predict$Insulin)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$Insulin and df_norm_predict$Insulin
## D = 0.064212, p-value = 0.2332
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


Imputación por norm.nob

Este método utiliza un modelo de regresión lineal para predecir los valores faltantes. La principal diferencia con norm.predict es que norm.nob agrega un residuo aleatorio a cada valor predicho. Este residuo se extrae de la distribución de los residuos del modelo de regresión.

mostramos nuevamente la tabla para ver como se ven las primeras filas de SKinThickess y Insulin

head(previo_df)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35      NA 33.6
## 2           1      85            66            29      NA 26.6
## 3           8     183            64            NA      NA 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74            NA      NA 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0

Aplicamos ahora el metodo de norm.nob

imp_norm_nob <- mice(df, m=5, maxit=50, method = 'norm.nob', seed = 500, printFlag = FALSE)

df_norm_nob <- complete(imp_norm_nob, 1)

Luego de aplicado este método, vamos a ver las primeras filas del dataset ya imputado para comprobar que no tenemos NA.

head(df_norm_nob)
##   Pregnancies Glucose BloodPressure SkinThickness   Insulin  BMI
## 1           6     148            72      35.00000  282.7451 33.6
## 2           1      85            66      29.00000  130.6682 26.6
## 3           8     183            64      10.33126  253.1314 23.3
## 4           1      89            66      23.00000   94.0000 28.1
## 5           0     137            40      35.00000  168.0000 43.1
## 6           5     116            74      20.24396 -130.7138 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0
colSums(is.na(df_norm_nob))
##              Pregnancies                  Glucose            BloodPressure 
##                        0                        0                        0 
##            SkinThickness                  Insulin                      BMI 
##                        0                        0                        0 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                        0                        0                        0

Con el Comando Colsums comprobamos que se aplico el metodo de forma correcta, obteniendo 0 datos faltantes en cada variable.

Análisis de Distribución

  • Realizaremos un histograma para verificar inicialmente de forma grafica si nuestra variable SkinThickness mantuvo o no la distribución, esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp1 <- ggplot(data.frame(value=previo_df$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp2 <- ggplot(data.frame(value=df_norm_nob$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp1, ggp2, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_norm_nob <- shapiro.test(df_norm_nob$SkinThickness)
print(shapiro_norm_nob)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_norm_nob$SkinThickness
## 
## Test Statistic:                  W = 0.9790628
## 
## P-value:                         4.944505e-09

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para SkinThickness- Norm.nob

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$SkinThickness, df_norm_nob$SkinThickness)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$SkinThickness and df_norm_nob$SkinThickness
## D = 0.028725, p-value = 0.9559
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


  • Ahora realizaremos el analisis anterior a la variable Insulin, estos es, un histograma para verificar inicialmente de forma grafica si nuestra imputación afecto o no la distribución. esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp3 <- ggplot(data.frame(value=previo_df$Insulin), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp4 <- ggplot(data.frame(value=df_norm_nob$Insulin), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp3, ggp4, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_norm_nob_2 <- shapiro.test(df_norm_nob$Insulin)
print(shapiro_norm_nob_2)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_norm_nob$Insulin
## 
## Test Statistic:                  W = 0.9274439
## 
## P-value:                         8.41167e-19

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para Insulin- Norm.nob

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$Insulin, df_norm_nob$Insulin)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$Insulin and df_norm_nob$Insulin
## D = 0.06324, p-value = 0.2487
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


Imputación por norm

Este método utiliza un modelo de regresión lineal para predecir los valores faltantes. La diferencia principal es cómo genera ese error. Mientras norm.nob usa los residuos del modelo de regresión, norm usa un método de “muestreo bayesiano” para la distribución de los parámetros del modelo.

Mostramos nuevamente la tabla para ver como se ven las primeras filas de SKinThickess y Insulin del dataset original.

head(previo_df)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35      NA 33.6
## 2           1      85            66            29      NA 26.6
## 3           8     183            64            NA      NA 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74            NA      NA 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0

Aplicamos ahora el metodo de norm.nob

imp_norm <- mice(df, m=5, maxit=50, method = 'norm', seed = 500, printFlag = FALSE)

df_norm <- complete(imp_norm, 1)

Luego de aplicado este método, vamos a ver las primeras filas del dataset ya imputado para comprobar que no tenemos NA.

head(df_norm)
##   Pregnancies Glucose BloodPressure SkinThickness   Insulin  BMI
## 1           6     148            72      35.00000 456.01723 33.6
## 2           1      85            66      29.00000  60.66381 26.6
## 3           8     183            64      16.75604 186.58545 23.3
## 4           1      89            66      23.00000  94.00000 28.1
## 5           0     137            40      35.00000 168.00000 43.1
## 6           5     116            74      23.76877 299.81798 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0
colSums(is.na(df_norm))
##              Pregnancies                  Glucose            BloodPressure 
##                        0                        0                        0 
##            SkinThickness                  Insulin                      BMI 
##                        0                        0                        0 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                        0                        0                        0

Con el Comando Colsums comprobamos que se aplico el metodo de forma correcta, obteniendo 0 datos faltantes en cada variable.

Análisis de Distribución

  • Realizaremos un histograma para verificar inicialmente de forma grafica si nuestra variable SkinThickness mantuvo o no la distribución, esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp1 <- ggplot(data.frame(value=previo_df$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp2 <- ggplot(data.frame(value=df_norm$SkinThickness), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('SkinThickness') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp1, ggp2, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_norm <- shapiro.test(df_norm$SkinThickness)
print(shapiro_norm_nob)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_norm_nob$SkinThickness
## 
## Test Statistic:                  W = 0.9790628
## 
## P-value:                         4.944505e-09

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para SkinThickness- Norm

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$SkinThickness, df_norm$SkinThickness)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$SkinThickness and df_norm$SkinThickness
## D = 0.033031, p-value = 0.8792
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


  • Ahora realizaremos el analisis anterior a la variable Insulin, estos es, un histograma para verificar inicialmente de forma grafica si nuestra imputación afecto o no la distribución. esto lo verificaremos luego con una prueba.
suppressWarnings({
ggp3 <- ggplot(data.frame(value=previo_df$Insulin), aes(x=value)) +
  geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
  ggtitle("Original") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

ggp4 <- ggplot(data.frame(value=df_norm$Insulin), aes(x=value)) +
  geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
  ggtitle("Imputación") +
  xlab('Insulin') + ylab('Frequency') +
  theme_ipsum() +
  theme(plot.title = element_text(size=15))

grid.arrange(ggp3, ggp4, ncol = 2)
})
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

shapiro_norm_2 <- shapiro.test(df_norm$Insulin)
print(shapiro_norm_nob_2)
## 
## Results of Hypothesis Test
## --------------------------
## 
## Alternative Hypothesis:          
## 
## Test Name:                       Shapiro-Wilk normality test
## 
## Data:                            df_norm_nob$Insulin
## 
## Test Statistic:                  W = 0.9274439
## 
## P-value:                         8.41167e-19

Visualmente parece que la distribución no se afecto, esto lo comprobaremos con una prueba no paramétrica debido a que el p-valor es menor que (0.05).

Prueba no Parametrica para Insulin- Norm

Para evaluar si la imputación mantuvo la forma original de la distribución de las variables, se emplea la prueba de Kolmogorov–Smirnov, la cual permite comparar estadísticamente dos muestras y determinar si provienen de la misma distribución.

Hipótesis nula: ambas muestras provienen de la misma distribución.

Hipótesis alternativa: las muestras provienen de distribuciones diferentes.

suppressWarnings({
  
ks.test(previo_df$Insulin, df_norm$Insulin)

  })
## 
##  Asymptotic two-sample Kolmogorov-Smirnov test
## 
## data:  previo_df$Insulin and df_norm$Insulin
## D = 0.067147, p-value = 0.1909
## alternative hypothesis: two-sided

Como el p-valor es mayor que el nivel de significancia, no hay evidencia significativa para rechazar H_0, por lo que ambas muestras provienen de la misma distribución.


Metodo Seleccionado

Los analisis de datos atipicos y el eda lo voy a realizar con la base de datos que se encuentra imputada con la tecnica PMM debido a que los datos no tienen distribucion normal, y en este caso PMM se adapta mejor porque no hace suposiciones sobre la distribución de la variable y utiliza valores reales del dataset, a diferencia de las demas porque estos otros metodos utilizan regresión lineal y tienden a imputar valores que se ajustan a una distribución normal, lo que es un problema debido a que tiende a cambiar la forma de la distribución aunque verificamos y todas mantienen la distribución.

Analisis de Datos Faltantes

En esta sección vamos a identificar los valores atipicos de las variables de la base de datos utilizando las tecnicas que aprendimos en clase.


Resumen Descriptivo

Resumen descriptivo inicial para identificar outliers en los datos.

summary(df_pmm)
##   Pregnancies        Glucose      BloodPressure    SkinThickness  
##  Min.   : 0.000   Min.   : 44.0   Min.   : 24.00   Min.   : 7.00  
##  1st Qu.: 1.000   1st Qu.: 99.0   1st Qu.: 64.00   1st Qu.:21.00  
##  Median : 3.000   Median :117.0   Median : 72.00   Median :29.00  
##  Mean   : 3.845   Mean   :121.7   Mean   : 72.42   Mean   :28.82  
##  3rd Qu.: 6.000   3rd Qu.:141.0   3rd Qu.: 80.00   3rd Qu.:36.00  
##  Max.   :17.000   Max.   :199.0   Max.   :122.00   Max.   :99.00  
##     Insulin            BMI        DiabetesPedigreeFunction      Age       
##  Min.   : 14.00   Min.   :18.20   Min.   :0.0780           Min.   :21.00  
##  1st Qu.: 73.75   1st Qu.:27.50   1st Qu.:0.2437           1st Qu.:24.00  
##  Median :120.00   Median :32.30   Median :0.3725           Median :29.00  
##  Mean   :148.57   Mean   :32.47   Mean   :0.4719           Mean   :33.24  
##  3rd Qu.:182.00   3rd Qu.:36.60   3rd Qu.:0.6262           3rd Qu.:41.00  
##  Max.   :846.00   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

En este resumen de la base de datos podemos identificar lo siguiente, varibles como Pregnancies tiene un maximo de 17, lo que puede ser un outlier dentro de esta variable. La variable Glucose que tiene un valor maximo de 199, que es un nivel alto para esa medida. LA variable Insulin tiene un valor de 846 que muy por encima del promedio.


Histograma

Resumen visual con histograma para identificar outliers.

df_long <- pivot_longer(df_pmm, 
                        cols = c(Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction, Age),
                        names_to = "Variable",
                        values_to = "Valor")

ggplot(df_long, aes(x = Valor)) +
  geom_histogram(bins = 30, fill = "#FBD000", color = "red") +
  facet_wrap(~ Variable, scales = "free", nrow = 2, ncol = 4) +
  labs(title = "Histogramas de las variables",
       x = "Valores",
       y = "Frecuencia") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

En los histogramas podemos identificar variables como age que tienen valores distantes como 81, otra es BMI que tiene un valor cercano a 70 que esta distante de los otros, otra variable que vemos en el histograma es Insulin que habiamos detectado con el resumen anterior con un valor en 846.


Boxplot

Realizamos un boxplot multiple para saber que variables tienen datos atipicos.

df_analisis <- df_pmm[, c('Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age')]
df_melted <- melt(df_analisis)
## No id variables; using all as measure variables
ggplot(df_melted, aes(x = "", y = value)) +
  geom_boxplot(fill = "#FBD000", color = "red") +
  theme_minimal() +
  labs(y = "Valor", x = "") +
  facet_wrap(~variable, scales = "free_y", ncol = 4) +
  theme(panel.grid.major = element_line(color = "gray80", linetype = "dotted"),
        panel.grid.minor = element_blank())

Del boxplot podemos identificar que la variable Pregnancies tiene 3 outliers, Bloodpressure tiene aproximadamente 5, SkinThikensstiene 3 outliers y aparte de esas vemos 4 variables mas como Ìnsulin, BMI, Diabetes, Age tienen outliers.


Metodo de percentiles

Con estemetodo vamos a calcular los valores que se encuentren por debajo del 2.5% y por encima del 97.5% de los datos detectandolos como outliers.

variables_predictores <- setdiff(names(df_pmm), "Outcome")

percentil_bajo <- 0.025
percentil_alto <- 0.975

cat("Valores atípicos detectados por el método de percentiles (", percentil_bajo * 100, "% y ", percentil_alto * 100, "%):\n\n")
## Valores atípicos detectados por el método de percentiles ( 2.5 % y  97.5 %):
for (col in variables_predictores) {

  lower_bound <- quantile(df_pmm[[col]], percentil_bajo, na.rm = TRUE)
  upper_bound <- quantile(df_pmm[[col]], percentil_alto, na.rm = TRUE)
  

  outliers_low <- df_pmm[[col]][df_pmm[[col]] < lower_bound]
  outliers_high <- df_pmm[[col]][df_pmm[[col]] > upper_bound]

  total_outliers <- length(outliers_low) + length(outliers_high)
  
  cat("---", col, "---\n")
  cat("Límite inferior (", percentil_bajo * 100, "%):", lower_bound, "\n")
  cat("Límite superior (", percentil_alto * 100, "%):", upper_bound, "\n")
  
  if (length(outliers_low) > 0) {
    cat("Valores por debajo del límite inferior:\n")
    print(outliers_low)
  }
  
  if (length(outliers_high) > 0) {
    cat("Valores por encima del límite superior:\n")
    print(outliers_high)
  }
  
  cat("Total de outliers encontrados:", total_outliers, "\n")
  cat("\n")

}
## --- Pregnancies ---
## Límite inferior ( 2.5 %): 0 
## Límite superior ( 97.5 %): 12 
## Valores por encima del límite superior:
##  [1] 13 13 13 15 17 13 14 13 13 14 13 13 13 13
## Total de outliers encontrados: 14 
## 
## --- Glucose ---
## Límite inferior ( 2.5 %): 73.175 
## Límite superior ( 97.5 %): 189 
## Valores por debajo del límite inferior:
##  [1] 71 73 44 62 71 57 71 73 71 61 72 71 68 57 73 67 68 68 56 65
## Valores por encima del límite superior:
##  [1] 197 196 194 196 197 193 191 194 196 193 197 194 195 198 198 197 199 195 190
## Total de outliers encontrados: 39 
## 
## --- BloodPressure ---
## Límite inferior ( 2.5 %): 50 
## Límite superior ( 97.5 %): 97.65 
## Valores por debajo del límite inferior:
##  [1] 40 30 48 44 48 48 30 48 46 48 44 44 24 38 44 46 44
## Valores por encima del límite superior:
##  [1] 110 108 122 110  98 104  98 100 108 102 100 100 104  98 110 106 106 106 100
## [20] 114
## Total de outliers encontrados: 37 
## 
## --- SkinThickness ---
## Límite inferior ( 2.5 %): 11 
## Límite superior ( 97.5 %): 48 
## Valores por debajo del límite inferior:
##  [1] 10 10  7  7 10 10  8  8 10  8  7 10  7
## Valores por encima del límite superior:
##  [1] 49 60 54 51 56 50 54 50 52 60 49 49 63 52 49 99 50 60 49
## Total de outliers encontrados: 32 
## 
## --- Insulin ---
## Límite inferior ( 2.5 %): 25.7 
## Límite superior ( 97.5 %): 480 
## Valores por debajo del límite inferior:
##  [1] 23 23 15 18 23 23 15 14 16 23 18 25 25 25 15 18 23 23 22 16
## Valores por encima del límite superior:
##  [1] 543 545 846 495 485 495 744 680 680 545 540 579 540 543 600 540 846 510 510
## Total de outliers encontrados: 39 
## 
## --- BMI ---
## Límite inferior ( 2.5 %): 21 
## Límite superior ( 97.5 %): 46.665 
## Valores por debajo del límite inferior:
##  [1] 19.9 19.4 19.6 19.1 20.4 20.4 18.4 20.8 19.3 20.0 18.2 18.2 19.6 20.8 19.6
## [16] 18.2 19.5 20.1 19.5
## Valores por encima del límite superior:
##  [1] 46.8 46.8 48.8 46.7 49.7 53.2 55.0 47.9 50.0 67.1 52.3 52.3 52.9 47.9 48.3
## [16] 59.4 46.8 57.3 49.6 49.3
## Total de outliers encontrados: 39 
## 
## --- DiabetesPedigreeFunction ---
## Límite inferior ( 2.5 %): 0.123525 
## Límite superior ( 97.5 %): 1.31345 
## Valores por debajo del límite inferior:
##  [1] 0.102 0.088 0.096 0.085 0.084 0.101 0.089 0.092 0.078 0.123 0.122 0.108
## [13] 0.107 0.121 0.085 0.088 0.100 0.115 0.118 0.121
## Valores por encima del límite superior:
##  [1] 2.288 1.441 1.390 1.893 1.781 1.400 1.321 2.329 1.318 1.353 1.391 1.476
## [13] 2.137 1.731 1.600 2.420 1.699 1.698 1.461 1.394
## Total de outliers encontrados: 40 
## 
## --- Age ---
## Límite inferior ( 2.5 %): 21 
## Límite superior ( 97.5 %): 63 
## Valores por encima del límite superior:
##  [1] 69 65 66 65 65 67 72 81 67 66 64 67 66 70 68 69 66
## Total de outliers encontrados: 17

Vemos que con este metodo para la variable Pregnancies detecta 14 otliers a diferencia del metodo del boxplot que solo identifica 3, para la variable Glucose detecta 39 outliers, para la variable BloodPressure detecta 37 outliers , para la variable SkinThickness detecta 32 outliers. Insulindetecta 39, BMI detecta 39, DiabetesPedigreeFunction detecta 40 outliers, Age detecta 17 outliers.


Filtro de Hampel

Este Metodo consiste en considerar como valores atípicos los valores fuera del intervalo formado por la mediana, más o menos 3 desviaciones absolutas de la mediana:

variables_predictores <- setdiff(names(df_pmm), "Outcome")

cat("Valores atípicos detectados por el método de Hampel manual:\n\n")
## Valores atípicos detectados por el método de Hampel manual:
for (col in variables_predictores) {
    mediana <- median(df_pmm[[col]])
    mad_valor <- mad(df_pmm[[col]], constant = 1)
    
    lower_bound <- mediana - (3 * mad_valor)
    upper_bound <- mediana + (3 * mad_valor)
    
    outliers <- df_pmm[[col]][df_pmm[[col]] < lower_bound | df_pmm[[col]] > upper_bound]
    total_outliers <- length(outliers)

    cat("---", col, "---\n")
    cat("Límite inferior:", lower_bound, "\n")
    cat("Límite superior:", upper_bound, "\n")
    
    if (total_outliers > 0) {
        cat("Valores atípicos:\n")
        print(outliers)
        cat("Total de outliers encontrados:", total_outliers, "\n")
    }
    
    cat("\n")
}
## --- Pregnancies ---
## Límite inferior: -3 
## Límite superior: 9 
## Valores atípicos:
##  [1] 10 10 10 11 10 13 10 11 13 13 15 10 17 11 12 10 12 11 10 13 10 14 10 13 10
## [26] 12 13 12 12 12 14 10 10 10 12 13 10 11 11 10 12 11 11 10 13 11 11 10 10 10
## [51] 13 10 10 10 11 13 12 10
## Total de outliers encontrados: 58 
## 
## --- Glucose ---
## Límite inferior: 57 
## Límite superior: 177 
## Valores atípicos:
##  [1] 183 197 189 196 180 180 187  44 188 179 194 181 196 184 179 197 181 179 184
## [20] 193 191 182 194 179 180 178 196 189 193 197 184 181 189 180 194 195 198 180
## [39] 186 187 189 198 197 188 183 181 183 179 199 195  56 187 187 181 190
## Total de outliers encontrados: 55 
## 
## --- BloodPressure ---
## Límite inferior: 48 
## Límite superior: 96 
## Valores atípicos:
##  [1]  40  30 110  44 108 122  30 110  98 104  98  46 100 108 102 100 100 104  98
## [20] 110  44  44  24  38 106 106 106 100 114  44  46  44
## Total de outliers encontrados: 32 
## 
## --- SkinThickness ---
## Límite inferior: 8 
## Límite superior: 50 
## Valores atípicos:
##  [1] 60 54 51 56  7 54  7 52 60 63  7 52 99 60  7
## Total de outliers encontrados: 15 
## 
## --- Insulin ---
## Límite inferior: -42 
## Límite superior: 282 
## Valores atípicos:
##  [1] 543 545 846 342 480 300 342 304 415 440 495 325 325 284 485 285 370 392 495
## [20] 285 318 300 478 744 330 370 680 285 680 402 375 293 480 545 360 330 480 325
## [39] 293 465 325 285 321 415 540 579 310 474 540 370 285 328 480 375 321 543 326
## [58] 330 370 600 321 293 321 440 540 846 318 510 321 480 335 387 291 392 480 480
## [77] 510 318
## Total de outliers encontrados: 78 
## 
## --- BMI ---
## Límite inferior: 18.5 
## Límite superior: 46.1 
## Valores atípicos:
##  [1] 46.8 46.8 48.8 46.7 49.7 53.2 55.0 47.9 50.0 67.1 52.3 46.2 18.4 52.3 52.9
## [16] 47.9 48.3 18.2 18.2 59.4 46.5 18.2 46.2 46.8 57.3 49.6 49.3 46.3
## Total de outliers encontrados: 28 
## 
## --- DiabetesPedigreeFunction ---
## Límite inferior: -0.13 
## Límite superior: 0.875 
## Valores atípicos:
##  [1] 2.288 1.441 0.966 1.390 1.893 0.962 1.781 1.222 0.930 1.114 1.400 1.189
## [13] 0.956 1.321 0.905 1.224 1.072 2.329 1.318 1.213 0.926 1.353 0.997 0.933
## [25] 1.101 1.136 0.881 1.224 1.391 1.127 1.476 0.932 0.893 0.962 2.137 1.731
## [37] 1.021 0.947 1.268 0.949 1.600 0.944 1.191 1.076 1.095 1.138 0.955 2.420
## [49] 1.001 1.022 1.159 1.144 0.968 0.917 1.251 0.968 1.034 0.892 1.154 0.925
## [61] 1.699 1.258 0.878 1.282 1.698 1.461 1.162 1.292 1.394 0.880 0.886 0.904
## [73] 0.905 0.970 1.174 1.096 1.182 1.057
## Total de outliers encontrados: 78 
## 
## --- Age ---
## Límite inferior: 8 
## Límite superior: 50 
## Valores atípicos:
##  [1] 53 54 57 59 51 51 57 60 56 54 58 54 60 61 69 62 55 65 60 55 57 52 60 66 61
## [26] 51 51 63 52 57 52 51 65 58 59 57 63 65 67 58 58 55 72 62 51 81 59 63 58 67
## [51] 66 55 64 58 53 51 60 67 56 53 66 58 54 62 62 52 52 54 51 54 70 68 53 69 52
## [76] 56 52 53 52 66 63
## Total de outliers encontrados: 81

Vemos que con este metodo se estan detectando mas outliers en unas variables y en otras encuentre menos que el metodo de los percentiles, para la variable Pregnancies detecta 58 outliers a diferencia del metodo anterior que detecto solamente 14 otliers, para la variable Glucose detecta 55 outliers a diferencia del metodo anterior que encontro 39 outliers, para la variable BloodPressure detecta 32 outliers a diferencia de 37 outliers que detecot el anterior, en este caso el metodo de los percentiles detecto 5 outliers mas que este metodo del filtro de Hampel, para la variable SkinThickness detecta 15 a diferencia del metodo anterior que encontro 32 outliers. Insulindetecta 78 a diferencia del metodo anterior que encontro 39, BMI detecta 28 con este metodo y con el anterior detecto 39, DiabetesPedigreeFunction detecta 78 outliers a diferencia de los 40 outliers que encontro en el anterior, Age detecta 81 outliers a diferencia de 17 outliers que encontro en el metodo anterior.


Prueba grubbs

La prueba de Grubbs permite detectar si el valor más alto o más bajo de un conjunto de datos es un valor atípico.

H_0: El valor más alto/bajo no es un valor atípico

H_1: El valor más alto/bajo es un valor atípico


Realizamos un resumen de nuestros datos debido a que Grubbs por defecto toma como valor objetivo el maximo de esa variable

summary(df_pmm)
##   Pregnancies        Glucose      BloodPressure    SkinThickness  
##  Min.   : 0.000   Min.   : 44.0   Min.   : 24.00   Min.   : 7.00  
##  1st Qu.: 1.000   1st Qu.: 99.0   1st Qu.: 64.00   1st Qu.:21.00  
##  Median : 3.000   Median :117.0   Median : 72.00   Median :29.00  
##  Mean   : 3.845   Mean   :121.7   Mean   : 72.42   Mean   :28.82  
##  3rd Qu.: 6.000   3rd Qu.:141.0   3rd Qu.: 80.00   3rd Qu.:36.00  
##  Max.   :17.000   Max.   :199.0   Max.   :122.00   Max.   :99.00  
##     Insulin            BMI        DiabetesPedigreeFunction      Age       
##  Min.   : 14.00   Min.   :18.20   Min.   :0.0780           Min.   :21.00  
##  1st Qu.: 73.75   1st Qu.:27.50   1st Qu.:0.2437           1st Qu.:24.00  
##  Median :120.00   Median :32.30   Median :0.3725           Median :29.00  
##  Mean   :148.57   Mean   :32.47   Mean   :0.4719           Mean   :33.24  
##  3rd Qu.:182.00   3rd Qu.:36.60   3rd Qu.:0.6262           3rd Qu.:41.00  
##  Max.   :846.00   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

Para la primera prueba usaremos la variable Pregnancies.

test <- grubbs.test(df_pmm$Pregnancies)
test
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$Pregnancies
## G = 3.9040, U = 0.9801, p-value = 0.03367
## alternative hypothesis: highest value 17 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 17 es un outliers.


Para la segunda prueba usaremos la variable Glucose.

test_2 <- grubbs.test(df_pmm$Glucose)
test_2
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$Glucose
## G = 2.53239, U = 0.99163, p-value = 1
## alternative hypothesis: lowest value 44 is an outlier

Como el p-valor es mayor que (0.05) no tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 199 no es un outliers.


Para la tercera prueba usaremos la variable BloodPressure.

test_3 <- grubbs.test(df_pmm$BloodPressure)
test_3
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$BloodPressure
## G = 4.01506, U = 0.97895, p-value = 0.02096
## alternative hypothesis: highest value 122 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 122 es un outliers.


Para la cuarta prueba usaremos la variable BloodPressure.

test_4 <- grubbs.test(df_pmm$SkinThickness)
test_4
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$SkinThickness
## G = 6.76548, U = 0.94025, p-value = 2.505e-09
## alternative hypothesis: highest value 99 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 99 es un outliers.


Para la quinta prueba usaremos la variable Insulin.

test_5 <- grubbs.test(df_pmm$Insulin)
test_5
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$Insulin
## G = 6.0952, U = 0.9515, p-value = 2.637e-07
## alternative hypothesis: highest value 846 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 9846 es un outliers.


Para la sexta prueba usaremos la variable BMI.

test_6 <- grubbs.test(df_pmm$BMI)
test_6
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$BMI
## G = 5.01023, U = 0.96723, p-value = 0.0001693
## alternative hypothesis: highest value 67.1 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 67 es un outliers.


Para la septima prueba usaremos la variable DiabetesPedigreeFunction.

test_7 <- grubbs.test(df_pmm$DiabetesPedigreeFunction)
test_7
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$DiabetesPedigreeFunction
## G = 5.87973, U = 0.95487, p-value = 1.056e-06
## alternative hypothesis: highest value 2.42 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 2.42 es un outliers.


Para la octava prueba usaremos la variable Age.

test_8 <- grubbs.test(df_pmm$Age)
test_8
## 
##  Grubbs test for one outlier
## 
## data:  df_pmm$Age
## G = 4.06107, U = 0.97847, p-value = 0.01716
## alternative hypothesis: highest value 81 is an outlier

Como el P-valor es menor que (0.05) tenemos evidencia estadisticamente significativa para rechazar H_0, por lo que 81 es un outliers.


Prueba de Dixon

Para realizar esta prueba, es necesario que el n<25 y en nuestro caso el dataset tiene 768 observaciones


Prueba de Rosner

Se utiliza para detectar varios valores atípicos a la vez (a diferencia de la prueba de Grubbs y Dixon, que debe realizarse de forma iterativa para detectar múltiples valores atípicos), y está diseñado para evitar el problema del enmascaramiento, en el que un valor atípico cercano a otro atípico puede pasar desapercibido.


Para la primera prueba usaremos la variable Pregnancies. El parametro k lo estamos tomando dependiendo el numero de outliers se vean en el boxplot de la variable respectiva.

testr <- rosnerTest(df_pmm$Pregnancies, k = 3)
testr$all.stats
##   i   Mean.i     SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1 0 3.845052 3.369578    17     160 3.904034   3.974092   FALSE
## 2 1 3.827901 3.338063    15      89 3.346880   3.973762   FALSE
## 3 2 3.813316 3.315699    14     299 3.072258   3.973432   FALSE

Con este metodo vemos que de los tres valores que esta encontrando, ninguno de estos es un outliers.


testr_2 <- rosnerTest(df_pmm$Glucose, k = 1)
testr_2$all.stats
##   i   Mean.i     SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1 0 121.6784 30.67391    44      63 2.532393   3.974092   FALSE

Con este metodo vemos que el valor que esta encontrando, no es un outliers.


testr_3 <- rosnerTest(df_pmm$BloodPressure, k = 5)
testr_3$all.stats
##   i   Mean.i     SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1 0 72.41536 12.34967   122     107 4.015058   3.974092    TRUE
## 2 1 72.35072 12.22700    24     598 3.954422   3.973762   FALSE
## 3 2 72.41384 12.10930    30      19 3.502585   3.973432   FALSE
## 4 3 72.46928 12.01954    30     126 3.533354   3.973102   FALSE
## 5 4 72.52487 11.92861   114     692 3.476947   3.972771   FALSE

Con este metodo vemos que de los cinco valores que esta encontrando, vemos que el 122 es un outliers.


testr_4 <- rosnerTest(df_pmm$SkinThickness, k = 3)
testr_4$all.stats
##   i   Mean.i      SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1 0 28.82161 10.373002    99     580 6.765485   3.974092    TRUE
## 2 1 28.73012 10.064877    63     446 3.404898   3.973762   FALSE
## 3 2 28.68538  9.994847    60      58 3.133077   3.973432   FALSE

Con este metodo vemos que de los tres valores que esta encontrando, vemos que el 99 es un outliers.


suppressWarnings({
testr_5 <- rosnerTest(df_pmm$Insulin, k = 15)
testr_5$all.stats
})
##     i   Mean.i      SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1   0 148.5651 114.42331   846      14 6.095217   3.974092    TRUE
## 2   1 147.6558 111.68685   846     662 6.252699   3.973762    TRUE
## 3   2 146.7441 108.86657   744     229 5.486128   3.973432    TRUE
## 4   3 145.9634 106.77045   680     238 5.001727   3.973102    TRUE
## 5   4 145.2644 105.07425   680     248 5.089121   3.972771    TRUE
## 6   5 144.5636 103.34091   600     585 4.407126   3.972440    TRUE
## 7   6 143.9659 102.08062   579     410 4.261672   3.972108    TRUE
## 8   7 143.3942 100.91986   545      12 3.979452   3.971776    TRUE
## 9   8 142.8658  99.92726   545     287 4.024269   3.971443    TRUE
## 10  9 142.3360  98.91921   543       9 4.050417   3.971110    TRUE
## 11 10 141.8074  97.90604   543     503 4.097731   3.970776    TRUE
## 12 11 141.2774  96.87666   540     405 4.115776   3.970442    TRUE
## 13 12 140.7500  95.84712   540     456 4.165488   3.970107    TRUE
## 14 13 140.2212  94.80067   540     656 4.217046   3.969772    TRUE
## 15 14 139.6910  93.73672   510     676 3.950523   3.969437   FALSE

Con este metodo vemos que de los quince valores que esta encontrando, todos a exepción de el 510 son outliers.


testr_6 <- rosnerTest(df_pmm$BMI, k = 6)
testr_6$all.stats
##   i   Mean.i     SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1 0 32.46745 6.912365  67.1     178 5.010232   3.974092    TRUE
## 2 1 32.42229 6.802596  59.4     446 3.965796   3.973762   FALSE
## 3 2 32.38708 6.736705  57.3     674 3.698088   3.973432   FALSE
## 4 3 32.35451 6.680506  55.0     126 3.389787   3.973102   FALSE
## 5 4 32.32487 6.634355  53.2     121 3.146520   3.972771   FALSE
## 6 5 32.29751 6.595438  52.9     304 3.123749   3.972440   FALSE

Con este metodo vemos que de los seis valores que esta encontrando, vemos que el 67 es un outliers.


testr_7 <- rosnerTest(df_pmm$DiabetesPedigreeFunction, k = 3)
testr_7$all.stats
##   i    Mean.i      SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1 0 0.4718763 0.3313286 2.420     446 5.879733   3.974092    TRUE
## 2 1 0.4693364 0.3239768 2.329     229 5.740114   3.973762    TRUE
## 3 2 0.4669086 0.3171301 2.288       5 5.742410   3.973432    TRUE

Con este metodo vemos que de los tres valores que esta encontrando, todos son outliers.


suppressWarnings({
testr_8 <- rosnerTest(df_pmm$Age, k = 18)
testr_8$all.stats
})
##     i   Mean.i     SD.i Value Obs.Num    R.i+1 lambda.i+1 Outlier
## 1   0 33.24089 11.76023    81     460 4.061069   3.974092    TRUE
## 2   1 33.17862 11.64053    72     454 3.335018   3.973762   FALSE
## 3   2 33.12794 11.56315    70     667 3.188755   3.973432   FALSE
## 4   3 33.07974 11.49346    69     124 3.125278   3.973102   FALSE
## 5   4 33.03272 11.42714    69     685 3.147531   3.972771   FALSE
## 6   5 32.98558 11.36006    68     675 3.082239   3.972440   FALSE
## 7   6 32.93963 11.29634    67     364 3.015167   3.972108   FALSE
## 8   7 32.89488 11.23596    67     490 3.035354   3.971776   FALSE
## 9   8 32.85000 11.17491    67     538 3.055953   3.971443   FALSE
## 10  9 32.80501 11.11318    66     222 2.986993   3.971110   FALSE
## 11 10 32.76121 11.05479    66     496 3.006731   3.970776   FALSE
## 12 11 32.71731 10.99576    66     553 3.026866   3.970442   FALSE
## 13 12 32.67328 10.93608    66     760 3.047411   3.970107   FALSE
## 14 13 32.62914 10.87572    65     149 2.976433   3.969772   FALSE
## 15 14 32.58621 10.81873    65     295 2.996080   3.969437   FALSE
## 16 15 32.54316 10.76112    65     363 3.016122   3.969101   FALSE
## 17 16 32.50000 10.70286    64     510 2.943138   3.968764   FALSE
## 18 17 32.45806 10.64797    63     264 2.868335   3.968427   FALSE

Con este metodo vemos que de los 18 valores que esta encontrando, solo el 21 es un outliers.

Metodo de Outliers seleccionado

Se aplicó la técnica de capping basada en percentiles para atenuar el efecto de valores atípicos extremos, reemplazándolos por los límites de los cuartiles y preservando así la estructura general de los datos sin eliminarlos.

capping_iqr <- function(x) {
  Q1 <- quantile(x, 0.25, na.rm = TRUE)
  Q3 <- quantile(x, 0.75, na.rm = TRUE)
  IQR_val <- Q3 - Q1
  
  lower <- Q1 - 1.5 * IQR_val
  upper <- Q3 + 1.5 * IQR_val
  
  x[x < lower] <- lower
  x[x > upper] <- upper
  return(x)
}

df_capped <- df_pmm
variables_predictores <- setdiff(names(df_capped), "Outcome")

df_melted <- melt(df_capped[, variables_predictores])
## No id variables; using all as measure variables
ggplot(df_melted, aes(x = "", y = value)) +
  geom_boxplot(fill = "#FBD000", color = "red") +
  theme_minimal() +
  labs(title = "Boxplot inicial", x = "", y = "Valor") +
  facet_wrap(~variable, scales = "free_y")

for (col in variables_predictores) {
  df_capped[[col]] <- capping_iqr(df_capped[[col]])
}

df_melted_final <- melt(df_capped[, variables_predictores])
## No id variables; using all as measure variables
ggplot(df_melted_final, aes(x = "", y = value)) +
  geom_boxplot(fill = "#FBD000", color = "red") +
  theme_minimal() +
  labs(title = "Boxplot después de capping por IQR", x = "", y = "Valor") +
  facet_wrap(~variable, scales = "free_y")

Tras aplicar el capping, los boxplots muestran una distribución más uniforme y sin valores atípicos extremos, lo que facilita un análisis más estable y representativo de las variables.

EDA - Analisis Exploratorio de Datos

Una vez imputados los valores faltantes y tratados los datos atípicos, procedemos a realizar el análisis exploratorio de datos para identificar patrones, relaciones y tendencias relevantes en el conjunto.

Se presenta un resumen detallado de todas las variables del dataset, incluyendo el tipo de dato (entero, punto flotante o carácter).

glimpse(df_capped)
## Rows: 768
## Columns: 9
## $ Pregnancies              <dbl> 6, 1, 8, 1, 0, 5, 3, 10, 2, 8, 4, 10, 10, 1, …
## $ Glucose                  <dbl> 148, 85, 183, 89, 137, 116, 78, 115, 197, 125…
## $ BloodPressure            <dbl> 72, 66, 64, 66, 40, 74, 50, 72, 70, 96, 92, 7…
## $ SkinThickness            <dbl> 35, 29, 20, 23, 35, 24, 32, 37, 45, 37, 32, 4…
## $ Insulin                  <dbl> 83.000, 55.000, 175.000, 94.000, 168.000, 175…
## $ BMI                      <dbl> 33.6, 26.6, 23.3, 28.1, 43.1, 25.6, 31.0, 35.…
## $ DiabetesPedigreeFunction <dbl> 0.627, 0.351, 0.672, 0.167, 1.200, 0.201, 0.2…
## $ Age                      <dbl> 50, 31, 32, 21, 33, 30, 26, 29, 53, 54, 30, 3…
## $ Outcome                  <int> 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, …

Se calcula el número de valores faltantes para cada variable del DataFrame.

colSums(is.na(df_capped))
##              Pregnancies                  Glucose            BloodPressure 
##                        0                        0                        0 
##            SkinThickness                  Insulin                      BMI 
##                        0                        0                        0 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                        0                        0                        0

missmap(df_capped, col = c("red", "#FBD000"), legend = TRUE)

Vemos que tenemos el 100% de las observaciones y ningun dato faltantes.


Se calcula el número de valores únicos para cada variable del DataFrame.

sapply(df_capped, function(x) length(unique(x)))
##              Pregnancies                  Glucose            BloodPressure 
##                       15                      135                       38 
##            SkinThickness                  Insulin                      BMI 
##                       48                      163                      241 
## DiabetesPedigreeFunction                      Age                  Outcome 
##                      490                       47                        2

Análisis Univariado

En esta sección analizaremos cada variable por separado para entender su distribución y características principales.

Variable Pregnancies (Número de embarazos)

summary(df_capped$Pregnancies)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   1.000   3.000   3.837   6.000  13.500
hist(df_capped$Pregnancies, main = "Distribución del número de embarazos", 
     xlab = "Número de embarazos", ylab = "Frecuencia", 
     col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$Pregnancies), "\n")
## Kurtosis: -0.07085283
cat("Skewness:", skewness(df_capped$Pregnancies), "\n")
## Skewness: 0.8539617

Interpretación

para nuestra variable tenemos un minimo de 0 y un maximo de 13 embarazos, vemos que el el 50% de los datos se encuentra por debajo de 3. Con un valor de skewness de 0.85, la distribución del número de embarazos presenta un sesgo positivo, lo que indica que la mayoría de los pacientes han tenido pocos embarazos y existe una cola larga de pacientes con un número mayor. El kurtosis de -0.07, un valor muy cercano a cero, sugiere que el grosor de las colas es similar al de una distribución normal.


Variable Glucose (Concentración de glucosa)

summary(df_capped$Glucose)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    44.0    99.0   117.0   121.7   141.0   199.0
hist(df_capped$Glucose, main = "Histograma de niveles de glucosa", 
     xlab = "Glucosa (mg/dL)", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$Glucose), "\n")
## Kurtosis: -0.2789814
cat("Skewness:", skewness(df_capped$Glucose), "\n")
## Skewness: 0.5339174

Interpretación

a variable Glucosa presenta un sesgo positivo de 0.53, lo que indica que la distribución de los datos se inclina hacia los valores bajos, con una cola de valores más altos que se extiende a la derecha. El valor de kurtosis de -0.28 sugiere que la distribución es más plana que una normal, con colas más ligeras. El resumen estadístico complementa esta información al mostrar que la media (121.7) es mayor que la mediana (117.0), lo que es una característica de las distribuciones con sesgo positivo. La mayoría de los pacientes tienen niveles de glucosa entre 99.0 y 141.0 mg/dL.


Variable BloodPressre

summary(df_capped$BloodPressure)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   40.00   64.00   72.00   72.39   80.00  104.00
hist(df_capped$BloodPressure, main = "Histograma de BloodPressure", 
     xlab = "BloodPressure (mm Hg)", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$BloodPressure), "\n")
## Kurtosis: 0.06444744
cat("Skewness:", skewness(df_capped$BloodPressure), "\n")
## Skewness: 0.0998705

Interpretación

La distribución de la variable BloodPressure es casi normal y simétrica, como lo indica su valor de skewness (sesgo) de 0.0998, que está muy cerca de cero. Esto se confirma visualmente en el histograma, que muestra una forma de campana centrada en el rango de 70-80 mm Hg. El valor de kurtosis (curtosis) de 0.064, también muy cercano a cero, sugiere que el pico de la distribución y el grosor de sus colas son similares a los de una distribución normal. Las estadísticas del summary respaldan esta simetría, ya que la media (72.39) y la mediana (72.00) son casi idénticas. La mayor parte de los datos se encuentra en un rango estrecho, del primer cuartil de 64.00 al tercer cuartil de 80.00, con un mínimo de 40.00 y un máximo de 104.00.


Variable SkinThickness

summary(df_capped$SkinThickness)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    7.00   21.00   29.00   28.76   36.00   58.50
hist(df_capped$SkinThickness, main = "Histograma de SkinThickness", 
     xlab = "SkinThickness (mm)", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$SkinThickness), "\n")
## Kurtosis: -0.3638711
cat("Skewness:", skewness(df_capped$SkinThickness), "\n")
## Skewness: 0.2147364

Interpretación

La distribución de la variable SkinThickness es ligeramente sesgada a la derecha, como lo indica el valor de skewness de 0.21. Aunque el sesgo es leve, se observa en el histograma una cola más larga hacia los valores altos. El valor de kurtosis es -0.36, lo que sugiere que la distribución es más plana que una distribución normal, con colas menos gruesas. Las estadísticas del summary muestran que la media (28.76) es ligeramente mayor que la mediana (29.00), lo cual es inusual para una distribución con sesgo positivo. Sin embargo, la mayor parte de los datos se concentra entre los 21.00 mm (primer cuartil) y 36.00 mm (tercer cuartil), con un rango total desde un mínimo de 7.00 mm hasta un máximo de 58.50 mm.


Variable Insulin

summary(df_capped$Insulin)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   14.00   73.75  120.00  139.76  182.00  344.38
hist(df_capped$Insulin, main = "Histograma de Insulin", 
     xlab = "Insulin (µU/mL)", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$Insulin), "\n")
## Kurtosis: 0.1450276
cat("Skewness:", skewness(df_capped$Insulin), "\n")
## Skewness: 0.9466988

Interpretación

La distribución de la variable Insulin presenta un sesgo positivo de 0.94, lo cual es considerable y se observa en el histograma. La mayoría de los valores de insulina se agrupan en el extremo inferior, y hay una cola larga de valores altos que se extiende hacia la derecha. La kurtosis de 0.14 es ligeramente positiva, sugiriendo que la distribución es un poco más puntiaguda que una distribución normal, con colas moderadamente más gruesas. Las estadísticas del summary confirman el sesgo, ya que la media (139.76) es notablemente mayor que la mediana (120.00). El rango intercuartílico, entre 73.75 y 182.00, contiene la mayoría de los datos, mientras que los valores de insulina alcanzan un máximo de 344.38.


Variable BMI

summary(df_capped$BMI)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   18.20   27.50   32.30   32.41   36.60   50.25
hist(df_capped$BMI, main = "Histograma de BMI", 
     xlab = "BMI", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$BMI), "\n")
## Kurtosis: -0.2328969
cat("Skewness:", skewness(df_capped$BMI), "\n")
## Skewness: 0.3495582

Interpretación

La distribución de la variable BMI muestra un sesgo positivo de 0.35, lo cual indica que la mayoría de los valores se concentran en el rango bajo a medio, con una cola más larga de pacientes con un IMC más alto. El histograma confirma esta ligera inclinación hacia la derecha. El valor de kurtosis de -0.23 sugiere que la distribución es más plana que una normal, con colas menos gruesas. Las estadísticas del summary muestran que la media (32.41) es ligeramente mayor que la mediana (32.30), lo cual es coherente con el sesgo positivo. La mayor parte de los pacientes tiene un IMC entre 27.50 y 36.60, con valores que oscilan entre un mínimo de 18.20 y un máximo de 50.25.


Variable DiabetesPedigreeFunction

summary(df_capped$DiabetesPedigreeFunction)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0780  0.2437  0.3725  0.4589  0.6262  1.2000
hist(df_capped$DiabetesPedigreeFunction, main = "Histograma de DiabetesPedigreeFunction", 
     xlab = "Diabetes Pedigree Function", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$DiabetesPedigreeFunction), "\n")
## Kurtosis: 0.2974468
cat("Skewness:", skewness(df_capped$DiabetesPedigreeFunction), "\n")
## Skewness: 1.024428

Interpretación

La distribución de la variable DiabetesPedigreeFunction muestra un sesgo positivo significativo con un valor de 1.02. Esto es claramente visible en el histograma, donde la mayoría de los valores se agrupan en el extremo inferior, y hay una cola larga que se extiende a la derecha, lo que indica que una pequeña cantidad de pacientes tiene una predisposición genética a la diabetes muy alta. El valor de kurtosis es 0.297, ligeramente positivo, lo que sugiere que la distribución es un poco más puntiaguda que una distribución normal, con colas moderadamente más gruesas. Las estadísticas del summary confirman el sesgo: la media (0.4589) es notablemente más alta que la mediana (0.3725). Los datos se concentran en gran medida entre el primer cuartil (0.2437) y el tercer cuartil (0.6262), con valores que van desde un mínimo de 0.0780 hasta un máximo de 1.2000.


Variable Age

summary(df_capped$Age)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    21.0    24.0    29.0    33.2    41.0    66.5
hist(df_capped$Age, main = "Histograma de Age", 
     xlab = "Edad (años)", col = "#FBD000", border = "red")

cat("Kurtosis:", kurtosis(df_capped$Age), "\n")
## Kurtosis: 0.3309699
cat("Skewness:", skewness(df_capped$Age), "\n")
## Skewness: 1.06717

Interpretación

La variable Age tiene un sesgo positivo considerable de 1.06, lo cual se visualiza en el histograma. La mayoría de los pacientes son jóvenes, con una alta concentración en el rango de los 20-30 años, y la frecuencia disminuye a medida que aumenta la edad, formando una larga cola hacia la derecha. El valor de kurtosis de 0.33 es ligeramente positivo, lo que indica que la distribución es un poco más puntiaguda con colas más gruesas que una distribución normal. El resumen estadístico confirma el sesgo, ya que la media (33.2) es superior a la mediana (29.0). El rango intercuartílico se encuentra entre los 24.0 y 41.0 años, con un mínimo de 21.0 y un máximo de 66.5.


Variable Outcome (Variable objetivo)

prop.table(table(df_capped$Outcome)) * 100
## 
##        0        1 
## 65.10417 34.89583
barplot(table(df_capped$Outcome), main = "Proporción de casos de diabetes",
        names.arg = c("No diabetes", "Diabetes"), 
        col = c("#FBD000", "red"), ylab = "Frecuencia")

Interpretación

La salida prop.table muestra que el 65.10% de los pacientes en el conjunto de datos no tienen diabetes (representado por el valor 0), mientras que el 34.90% de los pacientes sí tienen diabetes (representado por el valor 1). El gráfico de barras confirma visualmente esta distribución, mostrando una barra significativamente más alta para el grupo “No diabetes”.

Analisis Bivariado

El análisis bivariado sirve para explorar la relación entre dos variables a la vez, permitiendo identificar si existe una asociación, su dirección (positiva o negativa) y su fuerza.

Pregnancies vs Outcome

ggplot(df_capped, aes(x = factor(Outcome, labels = c("No diabetes", "Diabetes")),
                      y = Pregnancies,
                      fill = factor(Outcome))) +
  geom_boxplot(outlier.shape = 21, outlier.fill = "white", outlier.color = "black", width = 0.5) +
  scale_fill_manual(values = c("#FBD000", "red")) +
  labs(
    title = "Número de embarazos vs Diabetes",
    x = "",
    y = "Número de embarazos"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "none",
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_line(color = "gray90")
  )

Interpretación

El boxplot muestra una clara asociación entre el número de embarazos y el diagnóstico de diabetes. La mediana del número de embarazos en las pacientes con diabetes (aproximadamente 4) es más alta que la mediana de aquellas sin la enfermedad (aproximadamente 2). Esto sugiere que las pacientes con diabetes tienden a haber tenido un mayor número de embarazos y que esta variable podría ser un factor de riesgo.

Glucose vs Outcome

ggplot(df_capped, aes(x = factor(Outcome, labels = c("No diabetes", "Diabetes")),
                      y = Glucose,
                      fill = factor(Outcome))) +
  geom_boxplot(outlier.shape = 21, outlier.fill = "white", outlier.color = "black", width = 0.5) +
  scale_fill_manual(values = c("#FBD000", "red"),
                    name = "Diabetes",
                    labels = c("No", "Sí")) +
  labs(
    title = "Niveles de glucosa por condición de diabetes",
    x = "",
    y = "Glucosa"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_line(color = "gray90"),
    legend.position = "top"
  )

Interpretación

El boxplot de los niveles de glucosa por condición de diabetes muestra una clara y fuerte asociación entre la glucosa y el diagnóstico de diabetes. La mediana de glucosa para el grupo con diabetes (caja roja) es significativamente más alta que la mediana del grupo sin diabetes (caja amarilla). Además, el rango intercuartílico del grupo con diabetes se encuentra en un nivel considerablemente superior, lo que indica que los pacientes diabéticos tienden a tener niveles de glucosa persistentemente más altos. El grupo sin diabetes tiene valores más bajos y una distribución más estrecha, aunque con algunos valores atípicos.

BloodPressure vs Outcome

ggplot(df_capped, aes(x = factor(Outcome, labels = c("No diabetes", "Diabetes")),
                      y = BloodPressure,
                      fill = factor(Outcome))) +
  geom_boxplot(outlier.shape = 21, outlier.fill = "white", outlier.color = "black", width = 0.5) +
  scale_fill_manual(values = c("#FBD000", "red"),
                    name = "Diabetes",
                    labels = c("No", "Sí")) +
  labs(
    title = "Presión arterial por condición de diabetes",
    x = "",
    y = "Presión arterial (mmHg)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_line(color = "gray90"),
    legend.position = "top"
  )

Interpretación

El boxplot de la presión arterial por condición de diabetes muestra que, aunque hay un solapamiento en las distribuciones, los pacientes con diabetes (caja roja) tienden a tener una presión arterial ligeramente más alta. La mediana de la presión arterial en el grupo diabético está un poco por encima de la del grupo no diabético. Sin embargo, el rango intercuartílico (la caja) y la dispersión total de los datos son similares en ambos grupos, lo que sugiere que la presión arterial tiene una asociación más débil con la diabetes en comparación con otras variables como la glucosa.

SkinThickness vs Outcome

ggplot(df_capped, aes(x = factor(Outcome, labels = c("No diabetes", "Diabetes")),
                      y = SkinThickness,
                      fill = factor(Outcome))) +
  geom_boxplot(outlier.shape = 21, outlier.fill = "white", outlier.color = "black", width = 0.5) +
  scale_fill_manual(values = c("#FBD000", "red"),
                    name = "Diabetes",
                    labels = c("No", "Sí")) +
  labs(
    title = "Grosor del pliegue cutáneo por condición de diabetes",
    x = "",
    y = "Grosor (mm)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_line(color = "gray90"),
    legend.position = "top"
  )

Interpretación

El boxplot muestra que existe una asociación entre el grosor del pliegue cutáneo y la diabetes. El grupo de pacientes con diabetes (caja roja) tiene una mediana y un rango intercuartílico más altos en comparación con el grupo de pacientes sin diabetes (caja amarilla). Esto sugiere que un mayor grosor del pliegue cutáneo está asociado con la condición de diabetes.

BMI vs Outcome

ggplot(df_capped, aes(x = factor(Outcome, labels = c("No diabetes", "Diabetes")),
                      y = BMI,
                      fill = factor(Outcome))) +
  geom_boxplot(outlier.shape = 21, outlier.fill = "white", outlier.color = "black", width = 0.5) +
  scale_fill_manual(values = c("#FBD000", "red"),
                    name = "Diabetes",
                    labels = c("No", "Sí")) +
  labs(
    title = "BMI por condición de diabetes",
    x = "",
    y = "BMI"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_line(color = "gray90"),
    legend.position = "top"
  )

Interpretación

El boxplot del IMC (Índice de Masa Corporal) por condición de diabetes muestra una clara asociación entre ambas variables. La mediana del IMC es significativamente más alta en el grupo de pacientes con diabetes (caja roja) en comparación con el grupo sin diabetes (caja amarilla). Esto sugiere que un IMC más elevado es un factor de riesgo para el diagnóstico de la diabetes. Ambas distribuciones tienen una dispersión similar, pero la del grupo con diabetes se encuentra en un rango superior de valores.

DiabetesPedigreeFunction vs Outcome

ggplot(df_capped, aes(x = factor(Outcome, labels = c("No diabetes", "Diabetes")),
                      y = DiabetesPedigreeFunction,
                      fill = factor(Outcome))) +
  geom_boxplot(outlier.shape = 21, outlier.fill = "white", outlier.color = "black", width = 0.5) +
  scale_fill_manual(values = c("#FBD000", "red"),
                    name = "Diabetes",
                    labels = c("No", "Sí")) +
  labs(
    title = "Función de pedigrí de diabetes por condición",
    x = "",
    y = "Diabetes Pedigree Function"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_line(color = "gray90"),
    legend.position = "top"
  )

Interpretación

El boxplot de la Diabetes Pedigree Function muestra una clara asociación con el diagnóstico de diabetes. La mediana y el rango intercuartílico son significativamente más altos en el grupo de pacientes con diabetes (caja roja) en comparación con el grupo sin diabetes (caja amarilla). Esto indica que los pacientes con una mayor predisposición genética (valores más altos en esta función) tienen una mayor probabilidad de ser diagnosticados con diabetes.

Age vs Outcome

library(scales)
## Warning: package 'scales' was built under R version 4.4.1
## 
## Adjuntando el paquete: 'scales'
## The following objects are masked from 'package:psych':
## 
##     alpha, rescale
df_capped$AgeGroup <- cut(df_capped$Age, breaks = seq(20, 90, by = 10), right = FALSE)

ggplot(df_capped, aes(x = AgeGroup, fill = factor(Outcome, labels = c("No", "Sí")))) +
  geom_bar(position = "fill", color = "white", width = 0.7) +
  scale_fill_manual(values = c("#FBD000", "red"),
                    name = "Diabetes") +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(
    title = "Prevalencia de diabetes por grupo de edad",
    x = "Grupo de edad",
    y = "Proporción"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    axis.text = element_text(color = "black"),
    panel.grid.major = element_line(color = "gray80"),
    panel.grid.minor = element_blank(),
    legend.position = "top"
  )

Interpretación

El gráfico de barras apiladas sobre la prevalencia de diabetes por grupo de edad muestra una clara asociación positiva entre la edad y el diagnóstico de diabetes. La proporción de pacientes con diabetes (barra roja) aumenta consistentemente a medida que aumenta el grupo de edad, pasando de ser menos del 25% en el grupo de 20-30 años, a más del 50% en los grupos de 40-60 años. Esto indica que la edad es un factor de riesgo significativo para el desarrollo de la diabetes en este conjunto de datos.


Analisis Multivariado

El análisis multivariado sirve para explorar las relaciones complejas entre múltiples variables al mismo tiempo, permitiendo simplificar los datos y hacer predicciones más precisas.

library(corrplot)
## Warning: package 'corrplot' was built under R version 4.4.3
## corrplot 0.95 loaded
cor_matrix <- cor(df_capped[, sapply(df_capped, is.numeric)])
corrplot(cor_matrix, method = "color", 
         col = colorRampPalette(c("red", "white", "#FBD000"))(20),
         tl.col = "black", addCoef.col = "black")

Interpretación

Relación con la Variable Objetivo

  • Glucose (0.50): Esta variable tiene la correlación más fuerte y positiva con el Outcome. Esto significa que los niveles de glucosa son el predictor más importante de la diabetes, lo cual es lógicamente coherente.
  • BMI (0.32): El Índice de Masa Corporal tiene una correlación positiva moderada. Un BMI más alto está asociado con una mayor probabilidad de tener diabetes.
  • Insulin (0.33): La insulina sérica también tiene una correlación positiva moderada con el Outcome, lo que sugiere que niveles más altos de insulina están relacionados con la diabetes.
  • Age (0.24): La edad tiene una correlación positiva moderada, lo que indica que a mayor edad, mayor es la probabilidad de diagnóstico de diabetes.
  • SkinThickness (0.26): El grosor del pliegue cutáneo muestra una correlación positiva débil.
  • DiabetesPedigreeFunction (0.18): Esta función tiene una correlación positiva débil.

Relaciones entre Variables Predictoras

  • Glucose e Insulin (0.63): Hay una fuerte correlación positiva entre la glucosa y la insulina, lo cual es esperado, ya que el cuerpo produce insulina para regular los niveles de glucosa.
  • SkinThickness y BMI (0.67): Existe una correlación positiva muy fuerte entre el grosor del pliegue cutáneo y el BMI. Esto tiene sentido, ya que ambos son indicadores de la grasa corporal.
  • Pregnancies y Age (0.55): Hay una correlación positiva fuerte entre el número de embarazos y la edad. Es lógico que las mujeres mayores tiendan a haber tenido más embarazos.
  • BloodPressure y BMI (0.30): Existe una correlación positiva moderada. El aumento del peso corporal (BMI) suele estar asociado con un aumento de la presión arterial.

Conclusiones

El análisis exploratorio de datos reveló características clave en el conjunto de datos de diabetes. Primero, se observó que la variable objetivo, Outcome, está desbalanceada, con un 65% de pacientes sin diabetes y un 35% con la enfermedad. Este desequilibrio será un factor importante a considerar en la fase de modelado para evitar sesgos.

La mayoría de las variables predictoras, como Pregnancies, Glucose, Insulin, BMI, DiabetesPedigreeFunction y Age, presentan un sesgo positivo, indicando una alta concentración de valores en el extremo inferior y una cola larga de valores altos. Las distribuciones de Insulin y DiabetesPedigreeFunction son particularmente sesgadas y con valores atípicos (outliers), lo que justifica el uso de técnicas de preprocesamiento como el escalado o la transformación de datos. Por otro lado, variables como BloodPressure y SkinThickness muestran una distribución más cercana a la normal.

En cuanto a la correlación, los niveles de Glucose y el BMI son los predictores más fuertemente correlacionados con la diabetes. También se observaron relaciones importantes entre otras variables, como la fuerte correlación entre SkinThickness y BMI, y entre Pregnancies y Age. Sin embargo, en general, las correlaciones entre los predictores son de leves a moderadas, lo que minimiza el riesgo de multicolinealidad.

En resumen, el EDA ha proporcionado una comprensión profunda de la estructura de los datos, identificando la necesidad de manejar el desbalance de clases, el sesgo de algunas variables y la importancia de Glucose, Insulin, BMI y Age como predictores clave de la diabetes.