Librerías utilizadas:
library(readr)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ purrr 1.1.0
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(kableExtra)
##
## Attaching package: 'kableExtra'
##
## The following object is masked from 'package:dplyr':
##
## group_rows
library(Amelia)
## Loading required package: 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
## ##
library(mice)
##
## Attaching package: 'mice'
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following objects are masked from 'package:base':
##
## cbind, rbind
A través de readr se importan la base de datos *diabetes.csv:
datos <- read_csv("diabetes.csv")
## Rows: 768 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (9): Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, D...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#View(datos)
A manera de descriptivo se genera una tabla con los primeros 10 registros de la base de datos:
head(datos, 10)
## # A tibble: 10 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 6 148 72 35 0 33.6
## 2 1 85 66 29 0 26.6
## 3 8 183 64 0 0 23.3
## 4 1 89 66 23 94 28.1
## 5 0 137 40 35 168 43.1
## 6 5 116 74 0 0 25.6
## 7 3 78 50 32 88 31
## 8 10 115 0 0 0 35.3
## 9 2 197 70 45 543 30.5
## 10 8 125 96 0 0 0
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
Gracias a la función dim(), es posible verificar el número total de filas y columnas del dataframe:
dim(datos)
## [1] 768 9
Este dataset está compuesto por un total de 768 filas y 9 columnas.
Haciendo uso de la función kableExtra(), se construye una tabla de caracterización de variables:
descripciones <- c(
"Número de embarazos que ha tenido la paciente",
"Concentración de glucosa en la sangre",
"Presión arterial",
"Espesor del pliegue cutáneo",
"Nivel de insulina",
"Índice de masa corporal",
"Función de pedigrí de diabetes",
"Edad de la paciente (años)",
"Variable objetivo: 1 = diagnóstico positivo de diabetes, 0 = diagnóstico negativo"
)
tipo_variable <- c(
"Cuantitativa discreta", # Pregnancies
"Cuantitativa continua", # Glucose
"Cuantitativa continua", # BloodPressure
"Cuantitativa continua", # SkinThickness
"Cuantitativa continua", # Insulin
"Cuantitativa continua", # BMI
"Cuantitativa continua", # DiabetesPedigreeFunction
"Cuantitativa discreta", # Age
"Categórica dicotómica" # Outcome
)
tabla_vars <- data.frame(
`Nombre de Variable` = names(datos),
`Tipo de Variable` = tipo_variable,
`Descripción` = descripciones
)
tabla_vars %>%
kable("html", caption = "Caracterización de Variables") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed", "responsive"))
Nombre.de.Variable | Tipo.de.Variable | Descripción |
---|---|---|
Pregnancies | Cuantitativa discreta | Número de embarazos que ha tenido la paciente |
Glucose | Cuantitativa continua | Concentración de glucosa en la sangre |
BloodPressure | Cuantitativa continua | Presión arterial |
SkinThickness | Cuantitativa continua | Espesor del pliegue cutáneo |
Insulin | Cuantitativa continua | Nivel de insulina |
BMI | Cuantitativa continua | Índice de masa corporal |
DiabetesPedigreeFunction | Cuantitativa continua | Función de pedigrí de diabetes |
Age | Cuantitativa discreta | Edad de la paciente (años) |
Outcome | Categórica dicotómica | Variable objetivo: 1 = diagnóstico positivo de diabetes, 0 = diagnóstico negativo |
Luego, utilizando la función summary(), se hace un resumen general de las varibles presentes en el dataset:
summary(datos)
## Pregnancies Glucose BloodPressure SkinThickness
## Min. : 0.000 Min. : 0.0 Min. : 0.00 Min. : 0.00
## 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 62.00 1st Qu.: 0.00
## Median : 3.000 Median :117.0 Median : 72.00 Median :23.00
## Mean : 3.845 Mean :120.9 Mean : 69.11 Mean :20.54
## 3rd Qu.: 6.000 3rd Qu.:140.2 3rd Qu.: 80.00 3rd Qu.:32.00
## Max. :17.000 Max. :199.0 Max. :122.00 Max. :99.00
## Insulin BMI DiabetesPedigreeFunction Age
## Min. : 0.0 Min. : 0.00 Min. :0.0780 Min. :21.00
## 1st Qu.: 0.0 1st Qu.:27.30 1st Qu.:0.2437 1st Qu.:24.00
## Median : 30.5 Median :32.00 Median :0.3725 Median :29.00
## Mean : 79.8 Mean :31.99 Mean :0.4719 Mean :33.24
## 3rd Qu.:127.2 3rd Qu.:36.60 3rd Qu.:0.6262 3rd Qu.:41.00
## Max. :846.0 Max. :67.10 Max. :2.4200 Max. :81.00
## Outcome
## Min. :0.000
## 1st Qu.:0.000
## Median :0.000
## Mean :0.349
## 3rd Qu.:1.000
## Max. :1.000
De este resumen se infiere que todas las bases de datos son cuantitativas como se mencionó en la tabla construida anteriormente. En el caso de la variable Outcome, R asume que es numérica debido a que el contenido de sus celdas está compuesto por números. Sin embargo, debido a que sus opciones de respuesta son 1 para diagnósticos positivos y 0 para negativos; se clasifica como una variable cualitativa dicotómica, tal como se mencionó en la tabla.
Cuando se cumplan las condiciones establecidas ((bmi > 40) o charges == 0 (en el caso de que existan)), las celdas serán tomadas como valores faltantes
datos$BMI[datos$BMI > 40] <- NA
if ("Charges" %in% names(datos)) {
datos$Charges[datos$Charges == 0] <- NA
}
Luego, a través de Amelia(), se gener aun missingness map para visualizar el % de valores NA:
missmap(datos, col = c("red", "blue"), legend = TRUE)
## Warning: Unknown or uninitialised column: `arguments`.
## Unknown or uninitialised column: `arguments`.
## Warning: Unknown or uninitialised column: `imputations`.
Esto significa, que el dataset contiene un 1% de valores faltantes. Por supuesto, esto ocurre bajo las condiciones establecidas en la Actividad Evalutativa #3. Pues siguiendo las condiciones de 14.1 Actividad Práctica, el porcentaje de valores faltantes era del 9%.
En este inciso, se aplicarán 3 métodos de detección de valores atípicos a cada variable numérica presente en la base de datos.
Primero se genera un diagrama de caja y bigotes para visualizar posibles outliers:
boxplot(datos$Pregnancies,
main = "Boxplot de Pregnancies",
ylab = "Pregnancies",
col = "steelblue",
border = "black")
A simple vista, se evidencia presencia de posibles datos atípicos. Por lo tanto, es necesario aplicar la regla del IQR para detectarlos con mayor precisión.
out <- boxplot.stats(datos$Pregnancies)$out
out_ind <- which(datos$Pregnancies %in% c(out))
out_ind
## [1] 89 160 299 456
datos[out_ind, ]
## # A tibble: 4 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 15 136 70 32 110 37.1
## 2 17 163 72 41 114 NA
## 3 14 100 78 25 184 36.6
## 4 14 175 62 30 0 33.6
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
El primer output arroja el índice de cada fila que contiene un posible outlier.
El segundo output genera una tabla en la que aparecen el valor real que es considera atípico.
Luego, los valores obtenidos en la tabla coinciden con los que se aprecian a simple vista en el diagrama de caja y bigotes. Por lo tanto, hasta ahora, se confirma la presencia de 4 posibles valores atípicos en la pvariable Pregnancies.
Se fijan ambos límites y los datos que los sobrepasen se consideran atípicos:
lower_bound <- quantile(datos$Pregnancies, 0.025, na.rm = TRUE)
upper_bound <- quantile(datos$Pregnancies, 0.975, na.rm = TRUE)
outlier_ind <- which(datos$Pregnancies < lower_bound | datos$Pregnancies > upper_bound)
cat("Límite inferior (2.5%):", lower_bound, "\n")
## Límite inferior (2.5%): 0
cat("Límite superior (97.5%):", upper_bound, "\n")
## Límite superior (97.5%): 12
cat("Filas con outliers:", if (length(outlier_ind)) outlier_ind else "ninguna", "\n\n")
## Filas con outliers: 29 73 87 89 160 275 299 324 358 456 519 636 692 745
datos[outlier_ind, ]
## # A tibble: 14 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 13 145 82 19 110 22.2
## 2 13 126 90 0 0 NA
## 3 13 106 72 54 0 36.6
## 4 15 136 70 32 110 37.1
## 5 17 163 72 41 114 NA
## 6 13 106 70 0 0 34.2
## 7 14 100 78 25 184 36.6
## 8 13 152 90 33 29 26.8
## 9 13 129 0 30 0 39.9
## 10 14 175 62 30 0 33.6
## 11 13 76 60 0 0 32.8
## 12 13 104 72 0 0 31.2
## 13 13 158 114 0 0 NA
## 14 13 153 88 37 140 NA
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
El método de percentiles arroja un límite superior que es menor que el límite del bigote positivo de los boxplots. Por lo tanto, el número de datos atípicos es mayor al obtenido mediante el método de la regla del IQR.
lower_bound <- median(datos$Pregnancies, na.rm = TRUE) -
3 * mad(datos$Pregnancies, constant = 1, na.rm = TRUE)
upper_bound <- median(datos$Pregnancies, na.rm = TRUE) +
3 * mad(datos$Pregnancies, constant = 1, na.rm = TRUE)
outlier_ind <- which(datos$Pregnancies < lower_bound | datos$Pregnancies > upper_bound)
cat("Límite inferior:", lower_bound, "\n")
## Límite inferior: -3
cat("Límite superior:", upper_bound, "\n")
## Límite superior: 9
cat("Filas con outliers:", outlier_ind, "\n\n")
## Filas con outliers: 8 12 13 25 26 29 35 37 73 87 89 144 160 194 216 247 255 260 271 275 282 299 307 324 328 334 358 359 376 437 456 459 465 506 511 519 543 559 560 579 583 591 615 635 636 649 659 661 668 673 692 707 713 718 741 745 746 764
datos[outlier_ind, ]
## # A tibble: 58 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 10 115 0 0 0 35.3
## 2 10 168 74 0 0 38
## 3 10 139 80 0 0 27.1
## 4 11 143 94 33 146 36.6
## 5 10 125 70 26 115 31.1
## 6 13 145 82 19 110 22.2
## 7 10 122 78 31 0 27.6
## 8 11 138 76 0 0 33.2
## 9 13 126 90 0 0 NA
## 10 13 106 72 54 0 36.6
## # ℹ 48 more rows
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
En este caso, el límite superior es menor que el obtenido en el método de Percntiles. Por consiguiente, el número de datos atípicos es más elevado todavía.
boxplot(datos$Glucose,
main = "Boxplot de Glucose",
ylab = "Glucose",
col = "steelblue",
border = "black")
out <- boxplot.stats(datos$Glucose)$out
out_ind <- which(datos$Glucose %in% c(out))
out_ind
## [1] 76 183 343 350 503
datos[out_ind, ]
## # A tibble: 5 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 0 48 20 0 24.7
## 2 1 0 74 20 23 27.7
## 3 1 0 68 35 0 32
## 4 5 0 80 32 0 NA
## 5 6 0 68 41 0 39
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
Esta regla, detecta 5 posibles datos atípicos que coinciden con los visualizados en el boxplot, es decir, cuando la glucosa es 0.
lower_bound <- quantile(datos$Glucose, 0.025, na.rm = TRUE)
upper_bound <- quantile(datos$Glucose, 0.975, na.rm = TRUE)
outlier_ind <- which(datos$Glucose < lower_bound | datos$Glucose > upper_bound)
cat("Límite inferior (2.5%):", lower_bound, "\n")
## Límite inferior (2.5%): 71.175
cat("Límite superior (97.5%):", upper_bound, "\n")
## Límite superior (97.5%): 189
cat("Filas con outliers:", if (length(outlier_ind)) outlier_ind else "ninguna", "\n\n")
## Filas con outliers: 9 23 48 63 76 77 98 147 183 186 207 229 259 261 274 320 343 350 353 360 400 409 462 490 499 503 521 538 562 580 597 618 662 673 676 681 738 760
datos[outlier_ind, ]
## # A tibble: 38 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2 197 70 45 543 30.5
## 2 7 196 90 0 0 39.8
## 3 2 71 70 27 0 28
## 4 5 44 62 0 0 25
## 5 1 0 48 20 0 24.7
## 6 7 62 78 0 0 32.6
## 7 1 71 48 18 76 20.4
## 8 9 57 80 37 0 32.8
## 9 1 0 74 20 23 27.7
## 10 7 194 68 28 0 35.9
## # ℹ 28 more rows
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
En este caso, como ambos límites comprenden valores mucho más grandes que 0, el número de valores atípicos aumenta, pues los diagramas de caja y bigotes solo tomaban el 0 como outlier.
lower_bound <- median(datos$Glucose, na.rm = TRUE) -
3 * mad(datos$Glucose, constant = 1, na.rm = TRUE)
upper_bound <- median(datos$Glucose, na.rm = TRUE) +
3 * mad(datos$Glucose, constant = 1, na.rm = TRUE)
outlier_ind <- which(datos$Glucose < lower_bound | datos$Glucose > upper_bound)
cat("Límite inferior:", lower_bound, "\n")
## Límite inferior: 57
cat("Límite superior:", upper_bound, "\n")
## Límite superior: 177
cat("Filas con outliers:", outlier_ind, "\n\n")
## Filas con outliers: 3 9 14 23 41 46 57 63 76 155 176 183 186 187 207 210 213 229 237 238 246 259 261 318 320 328 333 340 343 350 360 361 400 409 426 428 441 446 490 499 503 507 546 547 550 562 580 596 605 607 623 648 662 676 681 716 749 754 760
datos[outlier_ind, ]
## # A tibble: 59 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 8 183 64 0 0 23.3
## 2 2 197 70 45 543 30.5
## 3 1 189 60 23 846 30.1
## 4 7 196 90 0 0 39.8
## 5 3 180 64 25 70 34
## 6 0 180 66 39 0 NA
## 7 7 187 68 39 304 37.7
## 8 5 44 62 0 0 25
## 9 1 0 48 20 0 24.7
## 10 8 188 78 0 0 NA
## # ℹ 49 more rows
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
Ahora, como el límite superior obtenido es menor que el límite superior resultante tras aplicar el método de percentiles. Es claro que el número de valores atípicos será aún mayor.
boxplot(datos$BloodPressure,
main = "Boxplot de BloodPressure",
ylab = "BloodPressure",
col = "steelblue",
border = "black")
out <- boxplot.stats(datos$BloodPressure)$out
out_ind <- which(datos$BloodPressure %in% c(out))
out_ind
## [1] 8 16 19 44 50 61 79 82 85 107 126 173 178 194 223 262 267 270 301
## [20] 333 337 348 358 363 427 431 436 454 469 485 495 523 534 536 550 590 598 602
## [39] 605 620 644 692 698 704 707
datos[out_ind, ]
## # A tibble: 45 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 10 115 0 0 0 35.3
## 2 7 100 0 0 0 30
## 3 1 103 30 38 83 NA
## 4 9 171 110 24 240 NA
## 5 7 105 0 0 0 0
## 6 2 84 0 0 0 0
## 7 0 131 0 0 0 NA
## 8 2 74 0 0 0 0
## 9 5 137 108 0 0 NA
## 10 1 96 122 0 0 22.4
## # ℹ 35 more rows
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
En este caso, se visualizan outliers fuera de ambos bigotes del diagrama.
lower_bound <- quantile(datos$BloodPressure, 0.025, na.rm = TRUE)
upper_bound <- quantile(datos$BloodPressure, 0.975, na.rm = TRUE)
outlier_ind <- which(datos$BloodPressure < lower_bound | datos$BloodPressure > upper_bound)
cat("Límite inferior (2.5%):", lower_bound, "\n")
## Límite inferior (2.5%): 0
cat("Límite superior (97.5%):", upper_bound, "\n")
## Límite superior (97.5%): 96
cat("Filas con outliers:", if (length(outlier_ind)) outlier_ind else "ninguna", "\n\n")
## Filas con outliers: 44 85 107 178 188 208 304 363 370 380 388 441 465 550 659 663 673 674 692
datos[outlier_ind, ]
## # A tibble: 19 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 9 171 110 24 240 NA
## 2 5 137 108 0 0 NA
## 3 1 96 122 0 0 22.4
## 4 0 129 110 46 130 NA
## 5 1 128 98 41 58 32
## 6 5 162 104 0 0 37.7
## 7 5 115 98 0 0 NA
## 8 5 103 108 37 0 39.2
## 9 1 133 102 28 140 32.8
## 10 0 93 100 39 72 NA
## 11 8 105 100 36 0 NA
## 12 0 189 104 25 0 34.3
## 13 10 115 98 0 0 24
## 14 4 189 110 31 0 28.5
## 15 11 127 106 0 0 39
## 16 8 167 106 46 231 37.6
## 17 10 68 106 23 49 35.5
## 18 3 123 100 35 240 NA
## 19 13 158 114 0 0 NA
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
Nuevamente, el método de percentiles muestra una mayor cantidad de valores atípicos a comparación de la regla del IQR. En este caso, ambos límites tienen sentido médico, pues no es nada común encontrar pacientes con una presión sanguína menor o igual a cero, ni mayor que 96.
lower_bound <- median(datos$BloodPressure, na.rm = TRUE) -
3 * mad(datos$BloodPressure, constant = 1, na.rm = TRUE)
upper_bound <- median(datos$BloodPressure, na.rm = TRUE) +
3 * mad(datos$BloodPressure, constant = 1, na.rm = TRUE)
outlier_ind <- which(datos$BloodPressure < lower_bound | datos$BloodPressure > upper_bound)
cat("Límite inferior:", lower_bound, "\n")
## Límite inferior: 48
cat("Límite superior:", upper_bound, "\n")
## Límite superior: 96
cat("Filas con outliers:", outlier_ind, "\n\n")
## Filas con outliers: 5 8 16 19 44 50 61 79 81 82 85 107 126 173 178 188 194 208 223 262 267 270 301 304 333 337 347 348 358 363 370 380 388 427 431 436 441 454 465 469 485 495 523 534 536 550 576 577 590 598 600 602 605 620 644 659 663 673 674 692 698 704 707 708 742
datos[outlier_ind, ]
## # A tibble: 65 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0 137 40 35 168 NA
## 2 10 115 0 0 0 35.3
## 3 7 100 0 0 0 30
## 4 1 103 30 38 83 NA
## 5 9 171 110 24 240 NA
## 6 7 105 0 0 0 0
## 7 2 84 0 0 0 0
## 8 0 131 0 0 0 NA
## 9 3 113 44 13 0 22.4
## 10 2 74 0 0 0 0
## # ℹ 55 more rows
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
Con el simple de hecho de obtener un límite inferior mayor que 0. Es evidente que el número de outliers aumenta drásticamente.
boxplot(datos$SkinThickness,
main = "Boxplot de SkinThickness",
ylab = "SkinThickness",
col = "steelblue",
border = "black")
out <- boxplot.stats(datos$SkinThickness)$out
out_ind <- which(datos$SkinThickness %in% c(out))
out_ind
## [1] 580
datos[out_ind, ]
## # A tibble: 1 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2 197 70 99 0 34.7
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
La regla del IQR sólo detecta un outlier: Cuando el espesor del pliegue cutáneo es de 99. A su vez, es importante mencionar que en esta ocasión, el valor obtenido sí coincide con el visualizados en el diagrama de caja y bigotes.
lower_bound <- quantile(datos$SkinThickness, 0.025, na.rm = TRUE)
upper_bound <- quantile(datos$SkinThickness, 0.975, na.rm = TRUE)
outlier_ind <- which(datos$SkinThickness < lower_bound | datos$SkinThickness > upper_bound)
cat("Límite inferior (2.5%):", lower_bound, "\n")
## Límite inferior (2.5%): 0
cat("Límite superior (97.5%):", upper_bound, "\n")
## Límite superior (97.5%): 47
cat("Filas con outliers:", if (length(outlier_ind)) outlier_ind else "ninguna", "\n\n")
## Filas con outliers: 58 87 100 121 151 212 274 276 371 410 446 459 533 540 580 592 658 694 764
datos[outlier_ind, ]
## # A tibble: 19 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0 100 88 60 110 NA
## 2 13 106 72 54 0 36.6
## 3 1 122 90 51 220 NA
## 4 0 162 76 56 100 NA
## 5 1 136 74 50 204 37.4
## 6 0 147 85 54 0 NA
## 7 1 71 78 50 45 33.2
## 8 2 100 70 52 57 NA
## 9 3 173 82 48 465 38.4
## 10 1 172 68 49 579 NA
## 11 0 180 78 63 14 NA
## 12 10 148 84 48 237 37.6
## 13 1 86 66 52 65 NA
## 14 3 129 92 49 155 36.4
## 15 2 197 70 99 0 34.7
## 16 2 112 78 50 140 39.4
## 17 1 120 80 48 200 38.9
## 18 7 129 68 49 125 38.5
## 19 10 101 76 48 180 32.9
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
Al ser 47 el límite superior resultante, es claro que el número de valores atípicos aumentará drásticamente con respecto al total obtenido con la regla del IQR, que sólo tomaba el 99 como outlier.
lower_bound <- median(datos$SkinThickness, na.rm = TRUE) -
3 * mad(datos$SkinThickness, constant = 1, na.rm = TRUE)
upper_bound <- median(datos$SkinThickness, na.rm = TRUE) +
3 * mad(datos$SkinThickness, constant = 1, na.rm = TRUE)
outlier_ind <- which(datos$SkinThickness < lower_bound | datos$SkinThickness > upper_bound)
cat("Límite inferior:", lower_bound, "\n")
## Límite inferior: -13
cat("Límite superior:", upper_bound, "\n")
## Límite superior: 59
cat("Filas con outliers:", outlier_ind, "\n\n")
## Filas con outliers: 58 446 580
datos[outlier_ind, ]
## # A tibble: 3 × 9
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0 100 88 60 110 NA
## 2 0 180 78 63 14 NA
## 3 2 197 70 99 0 34.7
## # ℹ 3 more variables: DiabetesPedigreeFunction <dbl>, Age <dbl>, Outcome <dbl>
En este caso, el límite de outliers disminuyó, en comparación con el método de percentiles.
Tras aplicar múltiples técnicas de detección de valores atípicos a la mayoría de variables cuantitativas presentes en el dataset. Es evidente que es necesario aplicar técnicas de imputación para darles un tratamiento eficiente a cada una de ellas.
Se utiliza el método pmm para imputar las variables:
datos_out <- datos
vars_imputar <- c("Pregnancies", "BloodPressure", "SkinThickness", "Glucose")
for (v in vars_imputar) {
lb <- median(datos_out[[v]], na.rm = TRUE) - 3 * mad(datos_out[[v]], constant = 1, na.rm = TRUE)
ub <- median(datos_out[[v]], na.rm = TRUE) + 3 * mad(datos_out[[v]], constant = 1, na.rm = TRUE)
idx <- which(datos_out[[v]] < lb | datos_out[[v]] > ub)
datos_out[[v]][idx] <- NA
}
method <- make.method(datos_out)
method[] <- ""
method[vars_imputar] <- "pmm"
imp <- mice(datos_out, method = method, m = 5, seed = 123)
##
## iter imp variable
## 1 1 Pregnancies Glucose BloodPressure SkinThickness
## 1 2 Pregnancies Glucose BloodPressure SkinThickness
## 1 3 Pregnancies Glucose BloodPressure SkinThickness
## 1 4 Pregnancies Glucose BloodPressure SkinThickness
## 1 5 Pregnancies Glucose BloodPressure SkinThickness
## 2 1 Pregnancies Glucose BloodPressure SkinThickness
## 2 2 Pregnancies Glucose BloodPressure SkinThickness
## 2 3 Pregnancies Glucose BloodPressure SkinThickness
## 2 4 Pregnancies Glucose BloodPressure SkinThickness
## 2 5 Pregnancies Glucose BloodPressure SkinThickness
## 3 1 Pregnancies Glucose BloodPressure SkinThickness
## 3 2 Pregnancies Glucose BloodPressure SkinThickness
## 3 3 Pregnancies Glucose BloodPressure SkinThickness
## 3 4 Pregnancies Glucose BloodPressure SkinThickness
## 3 5 Pregnancies Glucose BloodPressure SkinThickness
## 4 1 Pregnancies Glucose BloodPressure SkinThickness
## 4 2 Pregnancies Glucose BloodPressure SkinThickness
## 4 3 Pregnancies Glucose BloodPressure SkinThickness
## 4 4 Pregnancies Glucose BloodPressure SkinThickness
## 4 5 Pregnancies Glucose BloodPressure SkinThickness
## 5 1 Pregnancies Glucose BloodPressure SkinThickness
## 5 2 Pregnancies Glucose BloodPressure SkinThickness
## 5 3 Pregnancies Glucose BloodPressure SkinThickness
## 5 4 Pregnancies Glucose BloodPressure SkinThickness
## 5 5 Pregnancies Glucose BloodPressure SkinThickness
datos_pmm <- complete(imp)
Con el fin de verificar visualmente la presencia de outliers post-imputación en la base de datos, se generan varios diagramas de caja y bigotes:
variables_imputadas <- c("Pregnancies", "BloodPressure", "SkinThickness", "Glucose")
for (var in variables_imputadas) {
boxplot(datos_pmm[[var]],
main = paste("Boxplot de", var, "después de imputar"),
col = "steelblue",
border = "black")
}
De esto, se infiere por simple inspección, que ya no hay presencia de outliers y por ende la imputación fue exitosa.