Visualización de datos en R: Datos faltantes
## 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
data$Glucose <- replace(data$Glucose, data$Glucose == '0', NA)
data$BloodPressure <- replace(data$BloodPressure, data$BloodPressure == '0', NA)
data$SkinThickness <- replace(data$SkinThickness, data$SkinThickness == '0', NA)
data$Insulin <- replace(data$Insulin, data$Insulin == '0', NA)
data$BMI <- replace(data$BMI, data$BMI == '0', NA)## 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
## 'data.frame': 768 obs. of 9 variables:
## $ Pregnancies : int 6 1 8 1 0 5 3 10 2 8 ...
## $ Glucose : int 148 85 183 89 137 116 78 115 197 125 ...
## $ BloodPressure : int 72 66 64 66 40 74 50 NA 70 96 ...
## $ SkinThickness : int 35 29 NA 23 35 NA 32 NA 45 NA ...
## $ Insulin : int NA NA NA 94 168 NA 88 NA 543 NA ...
## $ BMI : num 33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 NA ...
## $ DiabetesPedigreeFunction: num 0.627 0.351 0.672 0.167 2.288 ...
## $ Age : int 50 31 32 21 33 30 26 29 53 54 ...
## $ Outcome : int 1 0 1 0 1 0 1 0 1 1 ...
Vemos que todas las variables son numéricas, siendo Outcome una variable categórica binaria.
Ahora vamos a visualizar los datos faltantes:
## Pregnancies DiabetesPedigreeFunction Age Outcome Glucose BMI BloodPressure
## 392 1 1 1 1 1 1 1
## 140 1 1 1 1 1 1 1
## 192 1 1 1 1 1 1 1
## 2 1 1 1 1 1 1 0
## 26 1 1 1 1 1 1 0
## 1 1 1 1 1 1 0 1
## 1 1 1 1 1 1 0 1
## 2 1 1 1 1 1 0 1
## 7 1 1 1 1 1 0 0
## 1 1 1 1 1 0 1 1
## 4 1 1 1 1 0 1 1
## 0 0 0 0 5 11 35
## SkinThickness Insulin
## 392 1 1 0
## 140 1 0 1
## 192 0 0 2
## 2 1 0 2
## 26 0 0 3
## 1 1 1 1
## 1 1 0 2
## 2 0 0 3
## 7 0 0 4
## 1 1 1 1
## 4 1 0 2
## 227 374 652
Podemos visualizar que las variables Glucose, BMI, Bloodpressure, SkinThickness e Insulin tienes datos faltantes. En la muestra de 768 observaciones, hay 140 filas con datos faltantes de insulin, 192 con dos datos faltantes, 28 con 3 datos faltantes y 7 filas con hasta 4 datos faltantes.
## 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.:22.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :29.00
## Mean : 3.845 Mean :121.7 Mean : 72.41 Mean :29.15
## 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
## NA's :5 NA's :35 NA's :227
## Insulin BMI DiabetesPedigreeFunction Age
## Min. : 14.00 Min. :18.20 Min. :0.0780 Min. :21.00
## 1st Qu.: 76.25 1st Qu.:27.50 1st Qu.:0.2437 1st Qu.:24.00
## Median :125.00 Median :32.30 Median :0.3725 Median :29.00
## Mean :155.55 Mean :32.46 Mean :0.4719 Mean :33.24
## 3rd Qu.:190.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
## NA's :374 NA's :11
## Outcome
## Min. :0.000
## 1st Qu.:0.000
## Median :0.000
## Mean :0.349
## 3rd Qu.:1.000
## Max. :1.000
##
vemos que las columnas con más datos faltantes son “insulin” y “skinthickness”.
Imputación de datos faltantes
Método de imputación por emparejamiento predictivo medio (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
Ahora visualizamos los datos luego de la imputación:
## 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
Podemos ver que:
Glucose: hay registros entre 44 hasta 199, con una media aproximada de 121.7.
Los registros de insulina en promedio son 148.57
Las personas encuestadas tienen un rango de edad entre 21 y 81 años.
library(gridExtra)
ggp1 <- ggplot(data.frame(value=data$SkinThickness), aes(x=value)) +
geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab('Skinthickness') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=imp_df$SkinThickness), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
ggtitle("PMM imputation") +
xlab('Skinthickness') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)podemos visualizar cierta similitud en la distribución de los datos para la variable Skinthickness a pesar de la imputación realizada.
library(gridExtra)
ggp1 <- ggplot(data.frame(value=data$Glucose), aes(x=value)) +
geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab('Glucose') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=imp_df$Glucose), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
ggtitle("PMM imputation") +
xlab('Glucose') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)Vamos a comparar las distribuciones de los datos originales e imputados utilizando el gráfico de densidad, Lo que queremos ver es que la forma de los puntos rojos (imputados) coincida con la de los azules (observados).
La densidad de los datos imputados para cada conjunto de datos imputados se muestra en color rojo, mientras que la densidad de los datos observados se muestra en azul. De nuevo, según nuestros supuestos anteriores, esperamos que las distribuciones sean similares
La coincidencia de la forma en la Variable SkinThickness e insulin, nos indican que la imputación por el método de emparejamiento medio fue apropiada en estas variables. Lo mismo ocurre en BloodPressure y BMI. en la variable Glucosa se ve variabilidad entre los datos reales y los imputados.
Comprobamos visualmente la convergencia, mostrando gráficos de seguimiento de la media y desviación estándar de todas las variables implicadas en las imputaciones.
Como se puede ver en el gráfico de trazado anterior sobre imp, no hay tendencias claras y las variables se superponen de una iteración a la siguiente. Se ha logrado la convergencia.
imputación por regresión
data1 <- data[, c("SkinThickness", "Glucose")]
imp.regress <- mice(data1, method="norm.predict", m=1, maxit=1)##
## iter imp variable
## 1 1 SkinThickness Glucose
## 1
## 76 113.2393
## 183 113.2393
## 343 126.9971
## 350 124.2455
## 503 132.5002
## 1
## 3 34.01699
## 6 28.77089
## 8 28.69259
## 10 29.47559
## 11 28.30109
## 12 32.84249
## 13 30.57179
## 16 27.51810
## 18 28.06619
## 22 27.43980
## 23 35.03488
## 27 31.19819
## 30 28.84919
## 34 26.89170
## 37 30.49349
## 42 30.10199
## 45 32.13779
## 47 31.11989
## 50 27.90959
## 59 31.11989
## 61 26.26530
## 62 30.10199
## 63 23.13330
## 65 28.61429
## 68 28.22279
## 73 29.55389
## 77 24.54270
## 79 29.94539
## 82 25.48230
## 85 30.41519
## 91 25.95210
## 94 30.18029
## 101 32.45099
## 102 31.51139
## 103 29.47559
## 105 26.34360
## 107 27.20490
## 114 25.63890
## 116 31.11989
## 117 29.39729
## 118 25.79550
## 124 30.02369
## 125 28.53599
## 130 27.90959
## 132 29.24069
## 139 29.78879
## 141 29.71049
## 144 28.14449
## 149 31.19819
## 152 28.61429
## 155 34.40849
## 165 29.94539
## 168 29.08409
## 169 28.30109
## 171 27.67470
## 177 26.34360
## 179 30.88499
## 180 29.86709
## 181 26.50020
## 184 25.40400
## 185 30.72839
## 191 28.37939
## 193 32.13779
## 194 30.25859
## 197 27.90959
## 202 30.49349
## 208 32.37269
## 220 28.45769
## 222 32.05949
## 223 29.00579
## 227 27.59640
## 231 30.80669
## 234 29.24069
## 236 33.07739
## 240 27.83129
## 243 30.57179
## 247 29.24069
## 251 27.98789
## 252 29.78879
## 262 30.72839
## 265 29.31899
## 267 30.49349
## 269 27.67470
## 270 31.11989
## 273 29.24069
## 275 27.98789
## 279 28.61429
## 281 31.11989
## 284 32.29439
## 285 28.14449
## 295 32.29439
## 300 28.45769
## 301 32.76419
## 304 28.69259
## 305 31.43309
## 318 33.93869
## 320 34.87828
## 328 33.70379
## 333 33.78209
## 334 27.98789
## 337 28.84919
## 338 28.69259
## 340 33.62549
## 344 29.24069
## 345 27.12660
## 348 28.77089
## 351 26.89170
## 352 30.41519
## 355 26.73510
## 356 32.60759
## 362 32.05949
## 364 31.11989
## 367 29.39729
## 379 31.90289
## 392 32.68589
## 395 32.05949
## 399 26.10870
## 401 27.12660
## 402 30.41519
## 405 32.84249
## 407 28.69259
## 408 27.59640
## 409 35.11318
## 419 26.18700
## 427 27.04830
## 431 27.43980
## 434 30.57179
## 436 30.72839
## 438 31.19819
## 440 28.06619
## 444 28.14449
## 452 30.18029
## 454 29.00579
## 457 30.25859
## 462 25.24740
## 465 28.69259
## 469 29.08409
## 474 30.33689
## 475 28.61429
## 485 31.04159
## 490 34.87828
## 495 25.95210
## 496 32.68589
## 497 28.30109
## 506 25.56060
## 510 29.08409
## 513 26.81340
## 514 26.81340
## 518 29.47559
## 519 25.63890
## 523 28.61429
## 524 29.86709
## 525 29.47559
## 530 28.37939
## 532 28.06619
## 534 26.81340
## 536 30.02369
## 537 27.90959
## 538 24.15120
## 553 28.61429
## 558 28.30109
## 560 26.34360
## 561 29.47559
## 565 26.81340
## 571 25.79550
## 572 29.86709
## 578 28.92749
## 579 30.10199
## 584 27.51810
## 587 30.88499
## 588 27.75299
## 590 25.40400
## 593 30.02369
## 597 24.93420
## 599 33.23399
## 602 27.20490
## 605 34.01699
## 616 27.98789
## 617 28.84919
## 620 29.00579
## 623 34.01699
## 625 28.14449
## 627 29.47559
## 628 30.02369
## 629 29.71049
## 631 28.61429
## 633 28.37939
## 635 26.89170
## 636 27.83129
## 637 27.83129
## 642 29.71049
## 643 31.19819
## 644 26.73510
## 654 29.08409
## 659 29.63219
## 661 32.37269
## 675 26.81340
## 676 34.95658
## 677 31.90289
## 678 26.97000
## 679 29.16239
## 684 29.47559
## 685 30.33689
## 687 29.86709
## 691 28.06619
## 692 32.05949
## 695 26.73510
## 698 27.43980
## 700 28.92749
## 704 29.78879
## 707 28.69259
## 709 32.52929
## 715 27.67470
## 725 28.37939
## 729 33.39059
## 730 26.89170
## 732 29.08409
## 735 27.90959
## 740 27.67470
## 744 30.65009
## 750 32.37269
## 751 30.33689
## 758 29.31899
## 759 27.98789
## 760 34.56509
## 763 26.65680
## 767 29.55389
Imputación de regresión estocástica
imp2 <- mice(data, m=5, maxit=50, method ='norm.nob', seed=500, printFlag = FALSE)
imp_df1 <- complete(imp2)
head(imp_df1)## 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
library(gridExtra)
ggp1 <- ggplot(data.frame(value=data$Glucose), aes(x=value)) +
geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab('Glucose') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=imp_df1$Glucose), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
ggtitle("Regresión estocástica") +
xlab('Glucose') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)Las distribuciones en la variable Glucose tanto para los datos reales como los imputados son parecidas.
ggp1 <- ggplot(data.frame(value=data$Glucose), aes(x=value)) +
geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab('Skinthickness') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=imp_df1$Glucose), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
ggtitle("Regresión estocástica") +
xlab('Skinthickness') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)Vamos a comparar las distribuciones de los datos originales e imputados utilizando el gráfico de densidad:
Puede verse que la imputación para la variable SkinThickness con la técnica de regresión estocástica es bastante buena. Se espera que las distribuciones para las demás variables sean similares.
visualizando la convergencia, no se ve una tendencia entre las variables y se superponen de una iteración a la siguiente. Se ha logrado la convergencia.
imputación de regresión estocástica Bayesiana
imp3 <- mice(data, m=5, maxit=50, method ='norm', seed=500, printFlag = FALSE)
imp_df3 <- complete(imp3)
head(imp_df1)## 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
ggp1 <- ggplot(data.frame(value=data$SkinThickness), aes(x=value)) +
geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab('Skinthickness') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=imp_df3$SkinThickness), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
ggtitle("Reg Estocástica bayesiana") +
xlab('Skinthickness') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)Se visualizan diferencias entre las dos distribuciones para la variable Skinthickness.
ggp1 <- ggplot(data.frame(value=data$Glucose), aes(x=value)) +
geom_histogram(fill="#FBD000", color="#E52521", alpha=0.9) +
ggtitle("Original data") +
xlab('Glucose') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
ggp2 <- ggplot(data.frame(value=imp_df3$Glucose), aes(x=value)) +
geom_histogram(fill="#43B047", color="#049CD8", alpha=0.9) +
ggtitle("Regresión estocástica bayesiana") +
xlab('Glucose') + ylab('Frequency') +
theme_classic() +
theme(plot.title = element_text(size=15))
grid.arrange(ggp1, ggp2, ncol = 2)Hay cierta similitud entre las distribuciones de la variable glucosa.
Posiblemente esta técnica fue apropiada en la variable glucose, pero no tanto en la variable Skinthickness. Visualicemos la similitud en todas las variables:
El resto de variables muestran cierta similitud, La variable glucosa muestra diferencias entre la distribución de los datos reales y los imputados. Analicemos la convergencia:
No se observan tendencias claras y hay superposición en las variables. Se ha logrado la convergencia.
Detección de valores atípicos
Identifique datos atípicos para cada variable en el dataset usando las técnicas estudiadas en clase. Además, realice imputación de los datos atípicos con base en lo desarrollado en el ítem anterior.
Estadística descriptiva:
## Pregnancies Glucose BloodPressure SkinThickness
## Min. : 0.000 Min. : 44.0 Min. : 24.00 Min. : 5.032
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 64.00 1st Qu.:21.000
## Median : 3.000 Median :117.0 Median : 72.00 Median :28.155
## Mean : 3.845 Mean :121.7 Mean : 72.25 Mean :28.752
## 3rd Qu.: 6.000 3rd Qu.:141.0 3rd Qu.: 80.00 3rd Qu.:36.000
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.000
## Insulin BMI DiabetesPedigreeFunction Age
## Min. :-211.5 Min. :18.20 Min. :0.0780 Min. :21.00
## 1st Qu.: 76.0 1st Qu.:27.50 1st Qu.:0.2437 1st Qu.:24.00
## Median : 135.6 Median :32.30 Median :0.3725 Median :29.00
## Mean : 158.8 Mean :32.45 Mean :0.4719 Mean :33.24
## 3rd Qu.: 210.2 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. : 846.0 Max. :67.10 Max. :2.4200 Max. :81.00
## Outcome
## Min. :0.000
## 1st Qu.:0.000
## Median :0.000
## Mean :0.349
## 3rd Qu.:1.000
## Max. :1.000
Histograma:
hist(imp_df3$DiabetesPedigreeFunction, xlab = "DiabetePedigreeFunction", col="pink", main="Histograma")Para este caso (DiabetePedigreeFunction) se ven algunos datos con registros elevados, posibles datos atípicos.
Boxplot:
data2 <- imp_df3 %>% select(-Outcome)
lapply(names(data2), function(column_name) {
# Crea el boxplot horizontal
boxplot(data2[[column_name]], horizontal = TRUE, main = column_name, col = "skyblue", border = "black")
# Identifica y etiqueta los valores atípicos
out <- boxplot(data2[[column_name]], plot = FALSE)$out
if(length(out) > 0) {
mtext(paste("Outliers: ", paste(out, collapse = ", ")), side = 1, line = 2)
}
})## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
##
## [[6]]
## NULL
##
## [[7]]
## NULL
##
## [[8]]
## NULL
Las observaciones consideradas como posibles valores atípicos según el criterio IQR se muestran como puntos en el diagrama de caja. Se visualiza la presencia de posibles datos atípicos en las variables Pregnancies, BoodPressure, skinthickness, insulin, BMI, DiabetesPedigreeFunction, y Age. Vemos que la salida de los boxplot nos permite identificar esos datos atípicos
También es posible extraer los valores de los posibles valores atípicos basándose en el criterio IQR:
## [1] 60.00000 58.74558 63.00000 99.00000
Como puede verse, el boxplot identifica 4 datos atípicos , y el criterio IQR identifica 4 datos atípicos en la variable Skinthickness.
De la misma manera se peude hacer para el resto de variables:
## numeric(0)
No se observan datos atípicos para la variable Glucose.
## [1] 69 67 72 81 67 67 70 68 69
Se identifican 9 datos atípicos en la variable “age”, mientras que el boxplot solo había identificado 6.
## [1] 53.2 55.0 67.1 52.3 52.3 52.9 59.4 57.3
Los datos atípicos con el criterio IQR coinciden con los detectados por el boxplot para la variable BMI.
## [1] 2.288 1.441 1.390 1.893 1.781 1.222 1.400 1.321 1.224 2.329 1.318 1.213
## [13] 1.353 1.224 1.391 1.476 2.137 1.731 1.268 1.600 2.420 1.251 1.699 1.258
## [25] 1.282 1.698 1.461 1.292 1.394
Vemos que para la variable DiabetesPedigreeFunction se encontró varios datos atípicos, el boxplot de esta variable también evidenciaba varios puntos como posibles atípicos.
Detección de datos atípicos mediante percentiles:
Con el método de los percentiles, todas las observaciones que se encuentren fuera del intervalo formado por los percentiles 2.5 y 97.5 se considerarán como posibles valores atípicos. También pueden considerarse otros percentiles, como el 1 y el 99, o el 5 y el 95, para construir el intervalo.
- Pregnancies:
## 2.5%
## 0
## 97.5%
## 12
Según este método, todas las observaciones por debajo de 0 y por encima de 12 se considerarán posibles valores atípicos
outlier_ind <- which(imp_df3$Pregnancies < lower_bound | imp_df3$Pregnancies > upper_bound)
outlier_ind## [1] 29 73 87 89 160 275 299 324 358 456 519 636 692 745
Se detectan 14 datos atípicos para la variable “Pregnancies”
- Glucose:
## 2.5%
## 73.175
## 97.5%
## 189
## [1] 9 23 48 56 63 77 98 147 183 184 186 207 229 259 261 274 320 353 360
## [20] 400 404 409 462 490 499 521 538 562 580 590 597 618 662 673 676 681 738 760
Se detectan varios datos atípicos en la variable glucose, las técnicas aplciadas anteriormente no detectaron datos atípicos.
- BloodPressure:
## 2.5%
## 50
## 97.5%
## 96
outlier_ind <- which(imp_df3$BloodPressure < lower_bound | imp_df3$BloodPressure > upper_bound)
outlier_ind## [1] 5 19 44 76 81 85 98 107 118 126 178 188 208 270 294 301 304 347 363
## [20] 370 380 388 406 431 441 465 550 576 577 598 600 659 663 673 674 692 708 742
Vemos que se detectaron bastantes datos atípicos para la variable “BloodPressure”. Los métodos aplicados anteriormente también detectaron datos atípicos (8 datos ).
- Skinthickness:
## 2.5%
## 10.84915
## 97.5%
## 49
outlier_ind <- which(imp_df3$SkinThickness < lower_bound | imp_df3$SkinThickness > upper_bound)
outlier_ind## [1] 56 58 61 68 87 100 121 151 152 179 212 255 274 276 280 304 314 320 333
## [20] 348 379 383 431 435 446 462 467 520 533 572 580 590 592 599 602 637 644 672
Vemos que esta técnica detecta aproximadamente 30 datos atípicos en la variable Skinthickness.
Otra técnica que se puede aplicar para detectar datos atípicos es el Filtro de Hampel.
Filtro de Hampel
Otro método, conocido como filtro de Hampel, 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
- BloodPressure:
lower_bound <- median(imp_df3$BloodPressure) - 3 * mad(imp_df3$BloodPressure, constant = 1)
lower_bound## [1] 48
upper_bound <- median(imp_df3$BloodPressure) + 3 * mad(imp_df3$BloodPressure, constant = 1)
upper_bound## [1] 96
Según este método, todas las observaciones por debajo de 48 y por encima de 96 se considerarán como posibles valores atípicos
outlier_ind <- which(imp_df3$BloodPressure < lower_bound | imp_df3$BloodPressure > upper_bound)
outlier_ind## [1] 5 19 44 81 85 107 126 178 188 208 301 304 347 363 370 380 388 441 465
## [20] 550 576 577 598 600 659 663 673 674 692 708 742
Vemos que esta técnica detectó bastantes datos atípicos en la variable BloodPressure, 30 datos en total.
- SkinThickness
lower_bound <- median(imp_df3$SkinThickness) - 3 * mad(imp_df3$SkinThickness, constant = 1)
lower_bound## [1] 5.697524
upper_bound <- median(imp_df3$SkinThickness) + 3 * mad(imp_df3$SkinThickness, constant = 1)
upper_bound## [1] 50.61176
outlier_ind <- which(imp_df3$SkinThickness < lower_bound | imp_df3$SkinThickness > upper_bound)
outlier_ind## [1] 58 68 87 100 121 179 212 276 348 379 446 533 580 599 637
Se detectaron 15 datos atípicos en esta variable, mientras que la técnica anterior había detectado muchos más.
- Insulin
lower_bound <- median(imp_df3$Insulin) - 3 * mad(imp_df3$Insulin, constant = 1)
upper_bound <- median(imp_df3$Insulin) + 3 * mad(imp_df3$Insulin, constant = 1)
outlier_ind <- which(imp_df3$Insulin < lower_bound | imp_df3$Insulin > upper_bound)
outlier_ind## [1] 1 9 11 14 16 23 30 45 46 47 55 59 63 73 85 101 102 112 124
## [20] 154 155 187 201 208 212 213 221 229 232 238 248 249 258 259 267 281 287 295
## [39] 297 318 328 333 340 350 371 393 399 409 410 416 436 472 487 496 497 580 585
## [58] 599 623 628 630 635 646 656 662 676 696 704 708 711 716 721 729 754 760
Para el caso de la variable insulin, se detectaron 59 datos atípicos, el boxplot había mostrado también la presencia de varios datos atípicos en esta variable.
- BMI:
lower_bound <- median(imp_df3$BMI) - 3 * mad(imp_df3$BMI, constant = 1)
upper_bound <- median(imp_df3$BMI) + 3 * mad(imp_df3$BMI, constant = 1)
outlier_ind <- which(imp_df3$BMI< lower_bound | imp_df3$BMI > upper_bound)
outlier_ind## [1] 58 85 93 100 121 126 155 156 178 194 232 240 248 304 336 379 419 439 446
## [20] 488 527 559 591 674 682 747 748
Aunque el boxplot había detectado solo 8 datos atípicos, esta técnica detectó otros más.
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## 58 0 100 88.00000 60.00000 110.00000 46.8
## 85 5 137 108.00000 35.33011 390.28136 48.8
## 93 7 81 78.00000 40.00000 48.00000 46.7
## 100 1 122 90.00000 51.00000 220.00000 49.7
## 121 0 162 76.00000 56.00000 100.00000 53.2
## 126 1 88 30.00000 42.00000 99.00000 55.0
## 155 8 188 78.00000 47.21192 391.89411 47.9
## 156 7 152 88.00000 44.00000 259.59083 50.0
## 178 0 129 110.00000 46.00000 130.00000 67.1
## 194 11 135 84.42399 41.74915 198.13698 52.3
## 232 6 134 80.00000 37.00000 370.00000 46.2
## 240 0 104 76.00000 19.14591 166.37571 18.4
## 248 0 165 90.00000 33.00000 680.00000 52.3
## 304 5 115 98.00000 50.38516 15.63523 52.9
## 336 0 165 76.00000 43.00000 255.00000 47.9
## 379 4 156 75.00000 54.63718 154.59617 48.3
## 419 1 83 68.00000 24.03987 121.56703 18.2
## 439 1 97 70.00000 15.00000 -44.94707 18.2
## 446 0 180 78.00000 63.00000 14.00000 59.4
## 488 0 173 78.00000 32.00000 265.00000 46.5
## 527 1 97 64.00000 19.00000 82.00000 18.2
## 559 11 103 68.00000 40.00000 42.98788 46.2
## 591 11 111 84.00000 40.00000 78.90455 46.8
## 674 3 123 100.00000 35.00000 240.00000 57.3
## 682 0 162 76.00000 36.00000 235.29728 49.6
## 747 1 147 94.00000 41.00000 264.90316 49.3
## 748 1 81 74.00000 41.00000 57.00000 46.3
## DiabetesPedigreeFunction Age Outcome
## 58 0.962 31 0
## 85 0.227 37 1
## 93 0.261 42 0
## 100 0.325 31 1
## 121 0.759 25 1
## 126 0.496 26 1
## 155 0.137 43 1
## 156 0.337 36 1
## 178 0.319 26 1
## 194 0.578 40 1
## 232 0.238 46 1
## 240 0.582 27 0
## 248 0.427 23 0
## 304 0.209 28 1
## 336 0.259 26 0
## 379 0.238 32 1
## 419 0.624 27 0
## 439 0.147 21 0
## 446 2.420 25 1
## 488 1.159 58 0
## 527 0.299 21 0
## 559 0.126 42 0
## 591 0.925 45 1
## 674 0.880 22 0
## 682 0.364 26 1
## 747 0.358 27 1
## 748 1.096 32 0
La tabla anterior nos muestra los datos atípicos detectados en la variable BMI mediante según el filtro de Hambel.
Prueba de 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.
H0: El valor más alto/bajo no es un valor atípico
H1: El valor más alto/bajo es un valor atípico
- BloodPressure
##
## Grubbs test for one outlier
##
## data: imp_df3$BloodPressure
## G = 3.99446, U = 0.97917, p-value = 0.02291
## alternative hypothesis: highest value 122 is an outlier
Dado que el p-valor es menor que el nivel de significancia (0.05), se rechaza la hipótesis nula y se concluye que el valor más bajo/más alto (122) es un valor atípico en la variable BloodPressure
- SkinThickness
##
## Grubbs test for one outlier
##
## data: imp_df3$SkinThickness
## G = 6.6311, U = 0.9426, p-value = 6.646e-09
## alternative hypothesis: highest value 99 is an outlier
Dado que el p-valor es menor que el nivel de significancia (0.05), se rechaza la hipótesis nula y se concluye que el valor más bajo/más alto (99) es un valor atípico en la variable SkinThickness.
Hacemos la verificación para el valor más bajo:
##
## Grubbs test for one outlier
##
## data: imp_df3$SkinThickness
## G = 2.23905, U = 0.99346, p-value = 1
## alternative hypothesis: lowest value 5.03161526330395 is an outlier
Vemos que la prueba considera al valor más bajo como un dato no atípico. (p-valor = 1)
- Glucose:
##
## Grubbs test for one outlier
##
## data: imp_df3$Glucose
## G = 2.54503, U = 0.99154, p-value = 1
## alternative hypothesis: lowest value 44 is an outlier
Para el caso de la variable glucose, la prueba no considera que este valor (44) sea un dato atípico, lo cual coindice con las otras técnicas donde se concluyó que no había datos atípicos en esta variable.
Prueba de Dixon
Al igual que la prueba de Grubbs, la prueba de Dixon se utiliza para comprobar si un único valor bajo o alto es un valor atípico. Por lo tanto, si se sospecha que hay más de un valor atípico, la prueba tiene que realizarse en estos valores atípicos sospechosos individualmente.
- Glucose:
##
## Dixon test for outliers
##
## data: subdat$Glucose
## Q = 0.10476, p-value = 0.2898
## alternative hypothesis: lowest value 78 is an outlier
Los datos muestran que el valor más bajo, 78 no es un dato atípico en la variable Glucose.
out <- boxplot.stats(subdat$Glucose)$out
boxplot(subdat$Glucose, ylab = "Glucose")
mtext(paste("Outliers: ", paste(out, collapse = ", ")))El boxplot de la variable nos muestra que en efecto, este dato no se considera atípico.
- SkinThickness
##
## Dixon test for outliers
##
## data: subdat$SkinThickness
## Q = 0.083333, p-value = 0.1886
## alternative hypothesis: highest value 47 is an outlier
Para el caso de la variable skinthickness , la prueba no consideró el valor más alto (47) como un dato atípico.
out <- boxplot.stats(subdat$SkinThickness)$out
boxplot(subdat$SkinThickness, ylab = "SkinThickness")
mtext(paste("Outliers: ", paste(out, collapse = ", ")))lo cual podemos evidenciar en el boxplot anterior, donde no se muestran registros de datos atípicos.
Prueba de Rosner
- SkinThickness
## i Mean.i SD.i Value Obs.Num R.i+1 lambda.i+1 Outlier
## 1 0 28.75169 10.59382 99 580 6.631066 3.974092 TRUE
## 2 1 28.66010 10.29198 63 446 3.336570 3.973762 FALSE
## 3 2 28.61527 10.22349 60 58 3.069865 3.973432 FALSE
Basándonos en esta prueba, vemos que solo detecta un dato atípico, la observación número 580.
- insulin:
## i Mean.i SD.i Value Obs.Num R.i+1 lambda.i+1 Outlier
## 1 0 158.8214 122.2810 846 14 5.619669 3.974092 TRUE
## 2 1 157.9254 119.8119 744 229 4.891623 3.973762 TRUE
## 3 2 157.1603 118.0003 680 248 4.430834 3.973432 TRUE
mientras que para el caso de la variable Insulin, considera 3 datos atípicos.
- Glucose:
## i Mean.i SD.i Value Obs.Num R.i+1 lambda.i+1 Outlier
## 1 0 121.7102 30.53414 44 63 2.545026 3.974092 FALSE
## 2 1 121.8115 30.42461 199 662 2.537041 3.973762 FALSE
## 3 2 121.7107 30.31614 198 562 2.516457 3.973432 FALSE
Ésta prueba coíncide con otras aplicadas en no considerar datos atípicos en la variable Glucose.
Tratamiento de los valores atípicos
CAPPING:
Para los valores que se encuentran fuera de los límites de 15⋅IQR, podríamos poner un tope sustituyendo las observaciones que se encuentran fuera del límite inferior por el valor del 5th percentíl y las que se encuentran por encima del límite superior, por el valor del 95th percentíl:
- SkinThickness
x <- imp_df3$SkinThickness
qnt <- quantile(x, probs=c(.25, .75), na.rm = T)
caps <- quantile(x, probs=c(.05, .95), na.rm = T)## [1] 35.00000 29.00000 16.75604 23.00000 35.00000 23.76877
- BMI
x <- imp_df3$BMI
qnt <- quantile(x, probs=c(.25, .75), na.rm = T)
caps <- quantile(x, probs=c(.05, .95), na.rm = T)## [1] 33.6 26.6 23.3 28.1 43.1 25.6
- BloodPressure
x <- imp_df3$BloodPressure
qnt <- quantile(x, probs=c(.25, .75), na.rm = T)
caps <- quantile(x, probs=c(.05, .95), na.rm = T)## [1] 72 66 64 66 40 74
Imputación de datos atípicos mediante predicción
Primeramente identificamos el valor atípico y lo reemplazamos por NA:
## 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
primero aplicamos la técnica de percentiles a la data para identificar los datos atípicos:
lower_bound <- quantile(imp_df$Glucose, 0.025)
upper_bound <- quantile(imp_df$Glucose, 0.975)
outlier_ind <- which(imp_df$Glucose < lower_bound | imp_df$Glucose > upper_bound)
imp_df$Glucose[outlier_ind]## [1] 197 196 71 73 44 62 71 57 71 73 194 196 197 193 191 71 194 61 196
## [20] 193 72 197 71 194 195 198 68 57 198 197 73 67 68 199 68 195 56 65
## [39] 190
estas son las filas con datos atípicos para la variable Glucose.
Ahora procedemos a cambiar estos datos por NA:
## [1] 197 196 71 73 44 62 71 57 71 73 194 196 197 193 191 71 194 61 196
## [20] 193 72 197 71 194 195 198 68 57 198 197 73 67 68 199 68 195 56 65
## [39] 190
Repetimos el mismo proceso para el resto de variables:
lower_bound <- quantile(imp_df$BloodPressure, 0.025)
upper_bound <- quantile(imp_df$BloodPressure, 0.975)
outlier_ind <- which(imp_df$BloodPressure < lower_bound | imp_df$BloodPressure > upper_bound)
imp_df$BloodPressure[outlier_ind]<-NAlower_bound <- quantile(imp_df$SkinThickness, 0.025)
upper_bound <- quantile(imp_df$SkinThickness, 0.975)
outlier_ind <- which(imp_df$SkinThickness < lower_bound | imp_df$Glucose > upper_bound)
imp_df$BloodPressure[outlier_ind]<-NAlower_bound <- quantile(imp_df$Insulin, 0.025)
upper_bound <- quantile(imp_df$Insulin, 0.975)
outlier_ind <- which(imp_df$Insulin < lower_bound | imp_df$Insulin > upper_bound)
imp_df$Insulin[outlier_ind]<-NAlower_bound <- quantile(imp_df$BMI, 0.025)
upper_bound <- quantile(imp_df$BMI, 0.975)
outlier_ind <- which(imp_df$BMI < lower_bound | imp_df$BMI > upper_bound)
imp_df$BMI[outlier_ind]<-NAlower_bound <- quantile(imp_df$DiabetesPedigreeFunction, 0.025)
upper_bound <- quantile(imp_df$DiabetesPedigreeFunction, 0.975)
outlier_ind <- which(imp_df$DiabetesPedigreeFunction < lower_bound | imp_df$DiabetesPedigreeFunction > upper_bound)
imp_df$DiabetesPedigreeFunction[outlier_ind]<-NAlower_bound <- quantile(imp_df$Pregnancies, 0.025)
upper_bound <- quantile(imp_df$Pregnancies, 0.975)
outlier_ind <- which(imp_df$Pregnancies < lower_bound | imp_df$Pregnancies > upper_bound)
imp_df$Pregnancies[outlier_ind]<-NAlower_bound <- quantile(imp_df$Age, 0.025)
upper_bound <- quantile(imp_df$Age, 0.975)
outlier_ind <- which(imp_df$Age < lower_bound | imp_df$Age > upper_bound)
imp_df$Age[outlier_ind]<-NAAhora tenemos todos los datos atípicos como registros NA. Esto puede verificarse con un summary:
## Pregnancies Glucose BloodPressure SkinThickness
## Min. : 0.000 Min. : 74.0 Min. :50.00 Min. : 7.00
## 1st Qu.: 1.000 1st Qu.:100.0 1st Qu.:68.00 1st Qu.:21.00
## Median : 3.000 Median :117.0 Median :70.00 Median :29.00
## Mean : 3.664 Mean :121.3 Mean :71.39 Mean :28.82
## 3rd Qu.: 6.000 3rd Qu.:139.0 3rd Qu.:76.50 3rd Qu.:36.00
## Max. :12.000 Max. :189.0 Max. :92.00 Max. :99.00
## NA's :14 NA's :39 NA's :732
## Insulin BMI DiabetesPedigreeFunction Age
## Min. : 29.0 Min. :21.00 Min. :0.1260 Min. :21.00
## 1st Qu.: 76.0 1st Qu.:27.60 1st Qu.:0.2480 1st Qu.:24.00
## Median :120.0 Median :32.30 Median :0.3725 Median :29.00
## Mean :140.5 Mean :32.29 Mean :0.4490 Mean :32.46
## 3rd Qu.:180.0 3rd Qu.:36.30 3rd Qu.:0.6050 3rd Qu.:40.00
## Max. :480.0 Max. :46.50 Max. :1.2920 Max. :63.00
## NA's :39 NA's :39 NA's :40 NA's :17
## Outcome
## Min. :0.000
## 1st Qu.:0.000
## Median :0.000
## Mean :0.349
## 3rd Qu.:1.000
## Max. :1.000
##
puede verse que ahora la data tiene datos faltantes, los cuales imputaremos con el método de predicción.
## 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
## 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
puede verse que los datos atípicos fueron imputados.