Missing Values (Valores faltantes)
Santiago Banchero
Leo Lucianna
Juan Manuel Fernandez
Minería de Datos - UBA
Vamos a trabajar en la implementación de las siguientes técnicas en R:
Cargamos iris y generamos datos faltantes aleatoriamente:
for(i in 1:4) {
for(j in 1:5) {
inst.aleat<-sample(1:nrow(iris), 1, replace=F)
iris[inst.aleat, i]<-NA
}
}
Podemos ver, por ejemplo, las instancias con que poseen faltante en una variable:
iris[is.na(iris$Sepal.Length),]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
22 NA 3.7 1.5 0.4 setosa
65 NA 2.9 3.6 1.3 versicolor
67 NA 3.0 4.5 1.5 versicolor
90 NA 2.5 4.0 1.3 versicolor
149 NA 3.4 5.4 2.3 virginica
Podríamos contar la cantidad de faltantes para una variable:
sum(is.na(iris$Sepal.Length))
[1] 5
También podemos analizar la proporción de faltantes sobre el total de instancias:
round(sum(is.na(iris$Sepal.Length))/nrow(iris)*100,2)
[1] 3.33
Si quisieramos trabajar únicamente con las instancias del dataset con registros completos:
iris.reg_completos<-na.omit(iris)
nrow(iris.reg_completos)
[1] 131
Simplemente podemos realizar los cálculos removiendo los faltantes:
print(mean(iris$Petal.Length))
[1] NA
print(mean(iris$Petal.Length, na.rm = TRUE))
[1] 3.8
Seleccionamos las instancias con valor faltante y las reemplazamos por la media de ese atributo:
# Sustitución por la media
iris.imp<-iris
iris.imp$media<-iris$Sepal.Length
iris.imp$media[is.na(iris.imp$media)]<-mean(iris.imp$media, na.rm = TRUE)
# Verificamos que no quedan faltantes
sum(is.na(iris.imp$media))
[1] 0
Primero ajustamos el modelo de Regresión:
#Armamos el modelo
rl_model<-lm(iris.imp$Sepal.Length ~ iris.imp$Sepal.Width+iris.imp$Petal.Length, data = iris.imp)
# Imprimimos los coeficientes del modelo
print(rl_model$coefficients)
(Intercept) iris.imp$Sepal.Width iris.imp$Petal.Length
2.2458828 0.6038898 0.4719438
Luego, con la instrucción summary tenemos un resumen con los coeficientes y la eficiencia del modelo ajustado, entre otras cosas
summary(rl_model)
Analizamos el modelo:
Call:
lm(formula = iris.imp$Sepal.Length ~ iris.imp$Sepal.Width + iris.imp$Petal.Length,
data = iris.imp)
Residuals:
Min 1Q Median 3Q Max
-0.97935 -0.22927 -0.00269 0.22184 0.76359
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.24588 0.26100 8.605 1.97e-14 ***
iris.imp$Sepal.Width 0.60389 0.07291 8.283 1.18e-13 ***
iris.imp$Petal.Length 0.47194 0.01812 26.038 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.335 on 132 degrees of freedom
(15 observations deleted due to missingness)
Multiple R-squared: 0.839, Adjusted R-squared: 0.8366
F-statistic: 344 on 2 and 132 DF, p-value: < 2.2e-16
Ahora, solo queda imputar los valores faltantes en función del modelo generado:
# Imputamos en base al modelo
iris.imp$regresion<-iris.imp$Sepal.Length
SW<-iris.imp$Sepal.Width[is.na(iris.imp$Sepal.Length)]
PL<-iris.imp$Petal.Length[is.na(iris.imp$Sepal.Length)]
coef<-rl_model$coefficients
# Hacemos la imputación
iris.imp$regresion[is.na(iris.imp$regresion)]<-coef[1]+SW*coef[2]+PL*coef[3]
# Verificamos que no existen faltantes
sum(is.na(iris.imp$regresion))
[1] 0
Para hot deck, vamos a utilizar la librería VIM. La función hotdeck imputará los datos directamente sobre el atributo del parámetro y generará un nuevo atributo -boolean- que indica las instancias imputadas:
# Cargamos la librería
library(VIM)
# Definimos un dataframe auxiliar para no perder la variable original
df_aux<-hotdeck(iris, variable="Sepal.Length")
iris.imp$hotdeck<-df_aux$Sepal.Length
iris.imp$hotdeckbool<-df_aux$Sepal.Length_imp
# Verificamos que no existen faltantes
sum(is.na(iris.imp$hotdeck))
[1] 0
Vamos a trabajar con MICE, esta librería provee un gráfico que detalla la cantidad de atributos con missing por cada atributo:
# Cargamos la librería
library(mice)
# Gráfico con el resumen de los missing para el dataset iris
md.pattern(iris, rotate.names=TRUE)
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
131 1 1 1 1 1 0
4 1 1 1 1 0 1
4 1 1 1 0 1 1
1 1 1 1 0 0 2
5 1 1 0 1 1 1
5 1 0 1 1 1 1
0 5 5 5 5 20
Ahora avanzamos sobre la imputación:
# Imputamos los datos con pmm (media, para valores numéricos)
imputed_Data <- mice(iris, maxit = 3, method = 'pmm')
iter imp variable
1 1 Sepal.Length Sepal.Width Petal.Length Petal.Width
1 2 Sepal.Length Sepal.Width Petal.Length Petal.Width
1 3 Sepal.Length Sepal.Width Petal.Length Petal.Width
1 4 Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5 Sepal.Length Sepal.Width Petal.Length Petal.Width
2 1 Sepal.Length Sepal.Width Petal.Length Petal.Width
2 2 Sepal.Length Sepal.Width Petal.Length Petal.Width
2 3 Sepal.Length Sepal.Width Petal.Length Petal.Width
2 4 Sepal.Length Sepal.Width Petal.Length Petal.Width
2 5 Sepal.Length Sepal.Width Petal.Length Petal.Width
3 1 Sepal.Length Sepal.Width Petal.Length Petal.Width
3 2 Sepal.Length Sepal.Width Petal.Length Petal.Width
3 3 Sepal.Length Sepal.Width Petal.Length Petal.Width
3 4 Sepal.Length Sepal.Width Petal.Length Petal.Width
3 5 Sepal.Length Sepal.Width Petal.Length Petal.Width
Cuales son los métodos de imputación del paquete MICE?
Ahora, con la función complete recuperamos los datos completos:
#Tomamos los datos completos
completeData <- complete(imputed_Data)
# Los asignamos a una nueva variable
iris.imp$mice <- completeData$Sepal.Length
# Verificamos que no existen faltantes
sum(is.na(iris.imp$mice))
[1] 0
Ahora, analizamos gráficamente la distribución original y su variación luego de realizar las imputaciones:
# Quitamos los atributos que no vamos a usar y renombramos Sepal.Length
iris.imp<-iris.imp[,-c(2:5)]
names(iris.imp)[1]<-"original"
# Analisis grafico de los resultados
plot(density(iris.imp$original, na.rm=TRUE), type = "l", col="red", ylab = "Original", ylim=c(0,0.5))
lines(density(iris.imp$media, na.rm=TRUE), type = "l", col="blue")
lines(density(iris.imp$regresion, na.rm=TRUE), type = "l", col="green")
lines(density(iris.imp$hotdeck, na.rm=TRUE), type = "l", col="yellow")
lines(density(iris.imp$mice, na.rm=TRUE), type = "l", col="black")
legend(7, 0.5, legend=c("Original", "Media", 'Regresión', 'Hotdeck', 'MICE'), col=c("red", "blue", 'green','yellow', "black"), lty=1, cex=0.8)
Obtenemos los siguientes gráficos de densidad: