Tratamiento de datos faltantes y atipicos

0. Creamos una base de datos de referencia (datos del curso) con datos problemáticos (atipicos y faltantes)

Reconocer diferencias entre datos: - Faltantes (NA) → no hay información disponible. - Erróneos o irreales → valores imposibles, inconsistentes o mal digitados (edad=-5, IMC=150). - Atípicos válidos → valores extremos pero posibles (altura = 195 cm, peso = 45 kg).

set.seed(123)
edad <- c(35,34,23,210,19,54,21,22,18,29,17,28,21,20,21,21,18,120)  # 210 y 120
altura <- c(NA,165,NA,174,175,160,160,182,176,170,164,189,166,176,157,180,NA,158)  # NA, 282 
peso <- c(95,NA,64,79,70,60,50,97,59,68,52,98,51,73,52,65,58,180) # NA 180 
genero <- c("M","F","F","M","M","F","F","M","M","M","F","M","F","M","F","M","F",NA)
#
BD <- data.frame(
  genero = as.factor(genero),
  edad, peso, altura,
  IMC = peso / (altura/100)^2
)
#
BD
##    genero edad peso altura      IMC
## 1       M   35   95     NA       NA
## 2       F   34   NA    165       NA
## 3       F   23   64     NA       NA
## 4       M  210   79    174 26.09328
## 5       M   19   70    175 22.85714
## 6       F   54   60    160 23.43750
## 7       F   21   50    160 19.53125
## 8       M   22   97    182 29.28390
## 9       M   18   59    176 19.04700
## 10      M   29   68    170 23.52941
## 11      F   17   52    164 19.33373
## 12      M   28   98    189 27.43484
## 13      F   21   51    166 18.50777
## 14      M   20   73    176 23.56663
## 15      F   21   52    157 21.09619
## 16      M   21   65    180 20.06173
## 17      F   18   58     NA       NA
## 18   <NA>  120  180    158 72.10383

1. Identificar datos faltantes

# Identificar NA
colSums(is.na(BD)) # Numero de filas donde hay elementos NA
## genero   edad   peso altura    IMC 
##      1      0      1      3      4
# Faltantes a partir del resumen general
summary(BD)
##   genero       edad             peso            altura           IMC       
##  F   :8   Min.   : 17.00   Min.   : 50.00   Min.   :157.0   Min.   :18.51  
##  M   :9   1st Qu.: 20.25   1st Qu.: 58.00   1st Qu.:162.0   1st Qu.:19.66  
##  NA's:1   Median : 21.50   Median : 65.00   Median :170.0   Median :23.15  
##           Mean   : 40.61   Mean   : 74.76   Mean   :170.1   Mean   :26.13  
##           3rd Qu.: 32.75   3rd Qu.: 79.00   3rd Qu.:176.0   3rd Qu.:25.46  
##           Max.   :210.00   Max.   :180.00   Max.   :189.0   Max.   :72.10  
##                            NA's   :1        NA's   :3       NA's   :4
# Faltantes (solo numericas) uisando una libreria
# install.packages("skimr")
library(skimr)
skim(BD)
Data summary
Name BD
Number of rows 18
Number of columns 5
_______________________
Column type frequency:
factor 1
numeric 4
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
genero 1 0.94 FALSE 2 M: 9, F: 8

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
edad 0 1.00 40.61 48.63 17.00 20.25 21.50 32.75 210.0 ▇▁▁▁▁
peso 1 0.94 74.76 31.41 50.00 58.00 65.00 79.00 180.0 ▇▂▁▁▁
altura 3 0.83 170.13 9.66 157.00 162.00 170.00 176.00 189.0 ▆▅▇▃▂
IMC 4 0.78 26.13 13.63 18.51 19.66 23.15 25.46 72.1 ▇▁▁▁▁

2. Identificar datos atipicos

# Atipicos por detección visual básica
par(mfrow=c(2,2))
boxplot(BD$edad, main="Edad (años)", horizontal = T)
boxplot(BD$altura, main="Altura (cm)", horizontal = T)
boxplot(BD$peso, main="Peso (Kg)", horizontal = T)
boxplot(BD$IMC, main="IMC", horizontal = T)

# Atipicos a partir de su variacion
# Regla de rango intercuartílico
Q1 <- quantile(BD$peso, 0.25, na.rm=TRUE)
Q1
## 25% 
##  58
Q3 <- quantile(BD$peso, 0.75, na.rm=TRUE)
Q3
## 75% 
##  79
IQR <- Q3 - Q1
IQR
## 75% 
##  21
limite_inf <- Q1 - 1.5 * IQR
limite_inf
##  25% 
## 26.5
limite_sup <- Q3 + 1.5 * IQR
limite_sup
##   75% 
## 110.5
# Visualizamos los datos que aceptamos tomar
boxplot(BD$peso, main="Peso (Kg)", horizontal = T)
abline(v=Q1, col="red")
abline(v=Q3, col="red")
abline(v=limite_inf, col="lightblue")
abline(v=limite_sup, col="lightblue")

# Filtrar la base de datos (usando criterio de IQR)
BD2 <- subset(BD, peso>limite_inf & peso<limite_sup)
BD2
##    genero edad peso altura      IMC
## 1       M   35   95     NA       NA
## 3       F   23   64     NA       NA
## 4       M  210   79    174 26.09328
## 5       M   19   70    175 22.85714
## 6       F   54   60    160 23.43750
## 7       F   21   50    160 19.53125
## 8       M   22   97    182 29.28390
## 9       M   18   59    176 19.04700
## 10      M   29   68    170 23.52941
## 11      F   17   52    164 19.33373
## 12      M   28   98    189 27.43484
## 13      F   21   51    166 18.50777
## 14      M   20   73    176 23.56663
## 15      F   21   52    157 21.09619
## 16      M   21   65    180 20.06173
## 17      F   18   58     NA       NA
BD3 <- subset(BD2, edad<100)
BD3
##    genero edad peso altura      IMC
## 1       M   35   95     NA       NA
## 3       F   23   64     NA       NA
## 5       M   19   70    175 22.85714
## 6       F   54   60    160 23.43750
## 7       F   21   50    160 19.53125
## 8       M   22   97    182 29.28390
## 9       M   18   59    176 19.04700
## 10      M   29   68    170 23.52941
## 11      F   17   52    164 19.33373
## 12      M   28   98    189 27.43484
## 13      F   21   51    166 18.50777
## 14      M   20   73    176 23.56663
## 15      F   21   52    157 21.09619
## 16      M   21   65    180 20.06173
## 17      F   18   58     NA       NA

3.1. imputar o reemplazar valores (Por variable)

# Reemplazar NA de altura con media general (o por mediana?)
mean(BD$altura) # Media de la data original
## [1] NA
mean(BD$altura, na.rm=T) # promedieme sin los faltantes
## [1] 170.1333
#
BD4 <- BD # Copia de la BD original para no afectarla
BD4$altura[is.na(BD4$altura)] <- mean(BD4$altura, na.rm=TRUE)
BD4 # Visualizamos la base de datos imputada BD4
##    genero edad peso   altura      IMC
## 1       M   35   95 170.1333       NA
## 2       F   34   NA 165.0000       NA
## 3       F   23   64 170.1333       NA
## 4       M  210   79 174.0000 26.09328
## 5       M   19   70 175.0000 22.85714
## 6       F   54   60 160.0000 23.43750
## 7       F   21   50 160.0000 19.53125
## 8       M   22   97 182.0000 29.28390
## 9       M   18   59 176.0000 19.04700
## 10      M   29   68 170.0000 23.52941
## 11      F   17   52 164.0000 19.33373
## 12      M   28   98 189.0000 27.43484
## 13      F   21   51 166.0000 18.50777
## 14      M   20   73 176.0000 23.56663
## 15      F   21   52 157.0000 21.09619
## 16      M   21   65 180.0000 20.06173
## 17      F   18   58 170.1333       NA
## 18   <NA>  120  180 158.0000 72.10383
mean(BD4$altura)
## [1] 170.1333
# Conclusion, completamos la data sin afectar la media del grupo
# Reemplazar NA de altura con media por grupos
# Usando funciones de base
BD_M <- subset(BD, genero=="M") # Igual que ==
BD_F <- subset(BD, genero!="M") # Diferente que !=
BD_M$altura[is.na(BD_M$altura)] <- mean(BD_M$altura, na.rm=TRUE)
BD_F$altura[is.na(BD_F$altura)] <- mean(BD_F$altura, na.rm=TRUE)
BD6 <- rbind(BD_M, BD_F)
BD6
##    genero edad peso altura      IMC
## 1       M   35   95 177.75       NA
## 4       M  210   79 174.00 26.09328
## 5       M   19   70 175.00 22.85714
## 8       M   22   97 182.00 29.28390
## 9       M   18   59 176.00 19.04700
## 10      M   29   68 170.00 23.52941
## 12      M   28   98 189.00 27.43484
## 14      M   20   73 176.00 23.56663
## 16      M   21   65 180.00 20.06173
## 2       F   34   NA 165.00       NA
## 3       F   23   64 162.00       NA
## 6       F   54   60 160.00 23.43750
## 7       F   21   50 160.00 19.53125
## 11      F   17   52 164.00 19.33373
## 13      F   21   51 166.00 18.50777
## 15      F   21   52 157.00 21.09619
## 17      F   18   58 162.00       NA
# Usando libreria dplyr
library(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
BD5 <- BD %>%
  group_by(genero) %>%
  mutate(altura2 = ifelse(is.na(altura), mean(altura, na.rm=TRUE), altura)
  )
BD5
## # A tibble: 18 × 6
## # Groups:   genero [3]
##    genero  edad  peso altura   IMC altura2
##    <fct>  <dbl> <dbl>  <dbl> <dbl>   <dbl>
##  1 M         35    95     NA  NA      178.
##  2 F         34    NA    165  NA      165 
##  3 F         23    64     NA  NA      162 
##  4 M        210    79    174  26.1    174 
##  5 M         19    70    175  22.9    175 
##  6 F         54    60    160  23.4    160 
##  7 F         21    50    160  19.5    160 
##  8 M         22    97    182  29.3    182 
##  9 M         18    59    176  19.0    176 
## 10 M         29    68    170  23.5    170 
## 11 F         17    52    164  19.3    164 
## 12 M         28    98    189  27.4    189 
## 13 F         21    51    166  18.5    166 
## 14 M         20    73    176  23.6    176 
## 15 F         21    52    157  21.1    157 
## 16 M         21    65    180  20.1    180 
## 17 F         18    58     NA  NA      162 
## 18 <NA>     120   180    158  72.1    158

3.2. imputar o reemplazar valores (multivariable)

  • van Buuren, S., & Groothuis-Oudshoorn, K. (2011). mice: Multivariate Imputation by Chained Equations in R. Journal of Statistical Software, 45(3), 1–67. https://doi.org/10.18637/jss.v045.i03
# Regla 20% de datos faltantes, es posible imputar
library(mice) # Multivariate Imputation by Chained Equations
## 
## Adjuntando el paquete: 'mice'
## The following object is masked from 'package:stats':
## 
##     filter
## The following objects are masked from 'package:base':
## 
##     cbind, rbind
md.pattern(BD)

##    edad genero peso altura IMC  
## 13    1      1    1      1   1 0
## 3     1      1    1      0   0 2
## 1     1      1    0      1   0 2
## 1     1      0    1      1   1 1
##       0      1    1      3   4 9
# Realizamos la imputacion
imp <- mice(BD, m=3, method='pmm', seed=500)
## 
##  iter imp variable
##   1   1  genero  peso  altura  IMC
##   1   2  genero  peso  altura  IMC
##   1   3  genero  peso  altura  IMC
##   2   1  genero  peso  altura  IMC
##   2   2  genero  peso  altura  IMC
##   2   3  genero  peso  altura  IMC
##   3   1  genero  peso  altura  IMC
##   3   2  genero  peso  altura  IMC
##   3   3  genero  peso  altura  IMC
##   4   1  genero  peso  altura  IMC
##   4   2  genero  peso  altura  IMC
##   4   3  genero  peso  altura  IMC
##   5   1  genero  peso  altura  IMC
##   5   2  genero  peso  altura  IMC
##   5   3  genero  peso  altura  IMC
## m=3: número de imputaciones.
## method='pmm': predictive mean matching (variables numéricas).
BD7 <- complete(imp)
# Verificamos los datos imputados
md.pattern(BD7)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

##    genero edad peso altura IMC  
## 18      1    1    1      1   1 0
##         0    0    0      0   0 0
#
cor(BD[2:4])
##        edad peso altura
## edad      1   NA     NA
## peso     NA    1     NA
## altura   NA   NA      1
cor(BD7[2:4])
##              edad       peso      altura
## edad    1.0000000 0.45079944 -0.07951770
## peso    0.4507994 1.00000000  0.09544009
## altura -0.0795177 0.09544009  1.00000000
# Comparamos los datos imputados vs originales incompletos
summary(BD6) # Imputada. IMC 72? -> no filtrado previo
##  genero      edad             peso           altura           IMC       
##  F:8    Min.   : 17.00   Min.   :50.00   Min.   :157.0   Min.   :18.51  
##  M:9    1st Qu.: 20.00   1st Qu.:56.50   1st Qu.:162.0   1st Qu.:19.53  
##         Median : 21.00   Median :64.50   Median :170.0   Median :22.86  
##         Mean   : 35.94   Mean   :68.19   Mean   :170.3   Mean   :22.60  
##         3rd Qu.: 29.00   3rd Qu.:74.50   3rd Qu.:176.0   3rd Qu.:23.57  
##         Max.   :210.00   Max.   :98.00   Max.   :189.0   Max.   :29.28  
##                          NA's   :1                       NA's   :4
summary(BD)
##   genero       edad             peso            altura           IMC       
##  F   :8   Min.   : 17.00   Min.   : 50.00   Min.   :157.0   Min.   :18.51  
##  M   :9   1st Qu.: 20.25   1st Qu.: 58.00   1st Qu.:162.0   1st Qu.:19.66  
##  NA's:1   Median : 21.50   Median : 65.00   Median :170.0   Median :23.15  
##           Mean   : 40.61   Mean   : 74.76   Mean   :170.1   Mean   :26.13  
##           3rd Qu.: 32.75   3rd Qu.: 79.00   3rd Qu.:176.0   3rd Qu.:25.46  
##           Max.   :210.00   Max.   :180.00   Max.   :189.0   Max.   :72.10  
##                            NA's   :1        NA's   :3       NA's   :4

4. Conclusiones

  • Seguir el proceso de identificar datos “problematicos”
  • Reconocer su los NA o atipicos son viables desde su criterio tecnico
  • Conocer los posibles valores antes de filtrar o eliminar
  • Realizar eliminacion y/o imputacion si se requiere
  • Validar los datos antes y despues del tratamiento