10 votos

Predicción con randomForest (R) cuando algunos valores de entrada tienen valores faltantes (NA)

Tengo un buen modelo de clasificación randomForest que me gustaría usar en una aplicación que predice la clase de un nuevo caso. El nuevo caso inevitablemente tiene valores faltantes. Predict no funcionará así para NAs. ¿Cómo debo hacerlo entonces?

data(iris)
# crea primero el nuevo caso con valores faltantes
na.row<-45
na.col<-c(3,5)
case.na<-iris[na.row,]
case.na[,na.col]<-NA

iris.rf <- randomForest(Species ~ ., data=iris[-na.row,])
# print(iris.rf)

myrf.pred <- predict(iris.rf, case.na[-5], type="response")
myrf.pred
[1] 

Intenté con missForest. Combiné los datos originales y el nuevo caso, los sacudí con missForest, y obtuve valores imputados para los NAs en mi nuevo caso. Sin embargo, es demasiado pesado computacionalmente.

data.imp <- missForest(data.with.na)

Pero debe haber una forma de usar el modelo rf para predecir un nuevo caso con valores faltantes, ¿verdad?

EDITAR: en mi aplicación la predicción se hace en un nuevo caso. La imputación simple con valores de media|mediana del conjunto de entrenamiento es una solución directa, pero introduce sesgo en la predicción del nuevo caso.

4 votos

Hay muchas formas de manejar los valores faltantes en árboles de decisión, pero el paquete randomForest en R solo tiene el método de imputación que describiste. Si deseas permanecer en un ambiente similar, gbm tiene un método algo más suave para manejar los valores faltantes en nuevos datos (no es perfecto, pero es útil).

0 votos

Creo que el paquete party maneja mejor los valores faltantes

0 votos

Estimado @Simone, ¿cómo funciona el paquete party con NAs en el conjunto de pruebas? No pude encontrar rastro de imputación en los manuales o ejemplos de party.

2voto

Grevling Puntos 123

No tienes más opción que imputar los valores o cambiar de modelos. Una buena elección podría ser aregImpute en el paquete Hmisc. Creo que es menos pesado que rfimpute, que es lo que te está deteniendo, primer ejemplo del paquete (hay otros):

# Comprueba que aregImpute puede estimar casi exactamente los valores faltantes cuando
# hay una relación no lineal perfecta entre dos variables
# Ajustar splines cúbicos restringidos con 4 knots para x1 y x2, lineal para x3
set.seed(3)
x1 <- rnorm(200)
x2 <- x1^2
x3 <- runif(200)
m <- 30
x2[1:m] <- NA
a <- aregImpute(~x1+x2+I(x3), n.impute=5, nk=4, match='closest')
a
matplot(x1[1:m]^2, a$imputed$x2)
abline(a=0, b=1, lty=2)

x1[1:m]^2
a$imputed$x2

# Imputación múltiple y estimación de varianzas y covarianzas de
# estimaciones de coeficientes de regresión teniendo en cuenta la imputación
# Ejemplo 1: tamaño de muestra grande, muchos datos faltantes, sin superposición en
# NA entre variables
x1 <- factor(sample(c('a','b','c'),1000,TRUE))
x2 <- (x1=='b') + 3*(x1=='c') + rnorm(1000,0,2)
x3 <- rnorm(1000)
y  <- x2 + 1*(x1=='c') + .2*x3 + rnorm(1000,0,2)
orig.x1 <- x1[1:250]
orig.x2 <- x2[251:350]
x1[1:250] <- NA
x2[251:350] <- NA
d <- data.frame(x1,x2,x3,y)
# Encontrar el valor de nk que produce los mejores modelos de imputación de validación
# tlinear=FALSE significa no forzar que la variable objetivo sea lineal
f <- aregImpute(~y + x1 + x2 + x3, nk=c(0,3:5), tlinear=FALSE,
                data=d, B=10) # normalmente B=75
f
# Intentar forzar a que la variable objetivo (x1, luego x2) sea lineal mientras se permiten
# predictores no lineales (también podría decir tlinear=TRUE)
f <- aregImpute(~y + x1 + x2 + x3, nk=c(0,3:5), data=d, B=10)
f

# Usar 100 imputaciones para verificar mejor contra valores verdaderos individuales
f <- aregImpute(~y + x1 + x2 + x3, n.impute=100, data=d)
f
par(mfrow=c(2,1))
plot(f)
modecat <- function(u) {
 tab <- table(u)
 as.numeric(names(tab)[tab==max(tab)][1])
}
table(orig.x1,apply(f$imputed$x1, 1, modecat))
par(mfrow=c(1,1))
plot(orig.x2, apply(f$imputed$x2, 1, mean))
fmi <- fit.mult.impute(y ~ x1 + x2 + x3, lm, f, 
                       data=d)
sqrt(diag(vcov(fmi)))
fcc <- lm(y ~ x1 + x2 + x3)
summary(fcc)   # Los SEs son más grandes que con imputación múltiple

Mencionas que tienes muchas nuevas observaciones que tienen valores faltantes en las variables independientes. Aunque tengas muchos casos así, si para cada nueva observación solo faltan uno o dos de sus variables y la cantidad de variables no es pequeña, tal vez simplemente rellenar los huecos con la mediana o el promedio (¿son continuas?) podría funcionar.

Otra cosa que podría ser interesante es realizar un análisis de importancia de variables. La implementación de random forest en R calcula dos medidas de importancia y respectivas gráficas:

varImpPlot(tuModeloRandomForest) # tuModeloRandomForest debe tener el argumento importance=TRUE 

Y puedes jugar con incluir solo variables "importantes" en el entrenamiento del modelo, hasta que la precisión de la predicción no se vea muy afectada en comparación con el "modelo completo". Quizás te convenga mantener variables con un bajo número de faltantes. Podría ayudarte a reducir el tamaño de tu problema.

1voto

Ben Puntos 4744

Puedes usar na.roughfix cuando estás prediciendo más de 1 muestra (es decir, prediciendo para >1 fila de datos).

Por ejemplo:

data(iris)

# Hacer que algunos datos estén faltantes
na.row<-c(146,150)
na.col<-c(3,5)
iris[na.row,na.col]<-NA

# Ver los NAs
tail(iris)
#     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
# 145          6.7         3.3          5.7         2.5 virginica
# 146          6.7         3.0           NA         2.3      
# 147          6.3         2.5          5.0         1.9 virginica
# 148          6.5         3.0          5.2         2.0 virginica
# 149          6.2         3.4          5.4         2.3 virginica
# 150          5.9         3.0           NA         1.8      

# Ejecutar Random Forest en un subconjunto de iris
set.seed(100)
iris.rf <- randomForest(Species ~ ., data=iris[1:120,]) #use el argumento na.action="na.roughfix" si hay NAs en tu conjunto de entrenamiento
iris.rf
# Llamada:
# randomForest(formula = Species ~ ., data = iris[1:120, ]) 
# Tipo de random forest: clasificación
# Número de árboles: 500
# Nº de variables intentadas en cada split: 2
# 
# Estimación OOB de la tasa de error: 4.17%
# Matriz de confusión:
#            setosa versicolor virginica class.error
# setosa         50          0         0        0.00
# versicolor      0         47         3        0.06
# virginica       0          2        18        0.10

# Ejecutar predicción en el conjunto de prueba, usando na.roughfix()
myrf.pred <- predict(iris.rf, na.roughfix(iris[121:150,]), type="response")
myrf.pred
#       121        122        123        124        125        126        127        128        129        130        131        132        133        134        135        136 
# virginica versicolor  virginica versicolor  virginica  virginica versicolor versicolor  virginica versicolor  virginica  virginica  virginica versicolor versicolor  virginica 
#       137        138        139        140        141        142        143        144        145        146        147        148        149        150 
# virginica  virginica versicolor  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica  virginica 
# Niveles: setosa versicolor virginica

Puedes ver que trató bien con los NAs.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X