Preprocesamiento


Tratamiento de datos faltantes (Técnicas de Imputación)


Juan Manuel Fernandez

Contenidos

En esta clase vamos a trabajar tips para implementar las siguientes técnicas en R:

  • Filtrado de registros completos
  • Técnicas de imputación de valores faltantes:
    • Sustitución por la media
    • Hot deck
    • Regresiones (en este caso lineal)
    • Multiple Imputation by Chained Equations (MICE)
  • Análisis gráfico de los métodos de imputación

Sobre los datos para los ejemplos

En esta clase vamos a trabajar con el dataset iris. Puntualmente, trabajaremos con el atributo Petal.Length, al cual le agregamos aleatoriamente valores faltantes:

faltantes = sum(is.na(iris$Petal.Length))
cat("El atributo Petal.Length posee", faltantes, "NA.")
El atributo Petal.Length posee 27 NA.
cat('Proporción NA (%):', mean(is.na(iris$Petal.Length))*100)
Proporción NA (%): 18

Además, de ahora en adelante trabajamos con “original”:

original = iris$Petal.Length

Valores Faltantes: Registros Completos

Los valores faltantes limitan algunas tareas de análisis de datos, por ejemplo el cálculo de funciones:

print(mean(original))
[1] NA

No obstante, en R generalmente existen parámetros en las funciones para ejecutarlas sin necesidad de imputar los faltantes:

print(mean(original, na.rm = TRUE))
[1] 3.649593

No obstante, estos parámetros muchas veces varían de acuerdo a la librería.

Valores Faltantes: Registros Completos (++)

La alternativa más simple, es trabajar únicamente con los registros completos de un dataset. Podemos filtrarlos con la función na.omit():

iris.reg_completos<-na.omit(iris)
nrow(iris.reg_completos)
[1] 113

También podemos filtrar los faltantes para una columna:

reg.completos<-iris[!is.na(original),]
nrow(reg.completos)
[1] 123

No obsstante, esta no siempre es una opción viable.

Imputación de datos faltantes: Sustitución por la Media

Para realizar una sustitución por la media, seleccionamos las instancias con valor faltante y las reemplazamos por la media de ese atributo:

# inicializamos el atributo media_imp con "original"
media_imp = original

# Y a continuación sustituimos los faltantes por la media
media_imp[is.na(original)]<-mean(original, na.rm = TRUE)

A continuación verificamos que no quedan faltantes:

sum(is.na(media_imp))
[1] 0

Valores Faltantes: Imputación Hot Deck

Para hot deck, vamos a utilizar la librería VIM. La función hotdeck imputa los datos directamente sobre el atributo del parámetro y genera un nuevo atributo -boolean- que indica las instancias imputadas:

library(VIM) # Cargamos la librería

# Definimos un dataframe auxiliar
hot.deck_imp<-hotdeck(iris, variable="Petal.Length")$Petal.Length
# Se genera un nuevo atributo booleando con las imputaciones
original_imp<-hotdeck(iris, variable="Petal.Length")$Petal.Length_imp

A continuación verificamos que no quedan faltantes:

sum(is.na(hot.deck_imp))
[1] 0

Valores Faltantes: Imputación por Regresión

Aquí vamos a ajustar un modelo de Regresión en función de una o varias características (Aquí nos limitamos a una):

#Armamos un modelo rl simple
rl_model<-lm(original ~ iris$Sepal.Length, data = iris)
# Si quisieramos ajutar un múltiple: 
# rl_model<-lm(original ~ iris$Sepal.Width+iris$Petal.Length, data = iris)
# Imprimimos los coeficientes del modelo
print(rl_model$coefficients)
      (Intercept) iris$Sepal.Length 
        -7.625281          1.929364 

Luego, con la instrucción summary tenemos un resumen con los coeficientes y la eficiencia del modelo ajustado, entre otras cosas

summary(rl_model)

Valores Faltantes: Imputación por Regresión (++)

Analizamos el modelo:


Call:
lm(formula = original ~ iris$Sepal.Length, data = iris)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.36503 -0.58733 -0.03677  0.54910  1.62791 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -7.62528    0.53787  -14.18   <2e-16 ***
iris$Sepal.Length  1.92936    0.09128   21.14   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.8489 on 119 degrees of freedom
  (29 observations deleted due to missingness)
Multiple R-squared:  0.7897,    Adjusted R-squared:  0.7879 
F-statistic: 446.7 on 1 and 119 DF,  p-value: < 2.2e-16

Valores Faltantes: Imputación por Regresión (+++)

Ahora, solo queda imputar los valores faltantes en función del modelo generado:

# inicializamos el atributo regresion_imp con "original"
regresion_imp = original

# Filtro los valores de Sepal.Length donde original es NA
SL<-iris$Sepal.Length[is.na(original)]
coef<-rl_model$coefficients

# Hacemos la imputación
regresion_imp[is.na(regresion_imp)]<-coef[1]+SL*coef[2]

A continuación verificamos que no quedan faltantes:

sum(is.na(regresion_imp))
[1] 0

Multiple Imputation by Chained Equations (MICE)

MICE es una técnica de imputación múltiple:

library(mice) # Cargamos la librería

# Imputamos los datos con pmm (media, para valores numéricos)
imputed_Data <- mice(iris, m=5, maxit = 3, method = 'pmm', printFlag=F)

Ahora, con la función complete recuperamos los datos completos:

#Tomamos los datos completos
completeData <- complete(imputed_Data)
# Los asignamos a una nueva variable
mice_imp <- completeData$Petal.Length

# Se verifica que todos los NA hayan sido imputados:
sum(is.na(mice_imp))
[1] 0

Análisis Gráfico de los métodos de imputación

Ahora, analizamos gráficamente la distribución original y su variación luego de realizar las imputaciones:

# Analisis grafico de los resultados
plot(density(original, na.rm=TRUE), type = "l", col="red", ylab = "Original", ylim=c(0,0.3), main="Análisis de métodos de imputación")
lines(density(media_imp, na.rm=TRUE), type = "l", col="blue")
lines(density(regresion_imp, na.rm=TRUE), type = "l", col="green")
lines(density(hot.deck_imp, na.rm=TRUE), type = "l", col="yellow")
lines(density(mice_imp, na.rm=TRUE), type = "l", col="black")
legend(6.5, 0.3, legend=c("Original", "Media", 'Regresión', 'Hotdeck', 'MICE'), col=c("red", "blue", 'green','yellow', "black"), lty=1, cex=0.8)

Análisis Gráfico de los métodos de imputación (++)

Obtenemos los siguientes gráficos de densidad:

plot of chunk unnamed-chunk-20
¿Conclusiones?