Я укусил пулю и спустился по этой конкретной кроличьей норе, опубликовав сообщение, чтобы поделиться своими выводами.
Обработка NA в R выполняется с помощью na.action
функций, которые предоставляются model.frame
внутренне при использованиифункция моделирования, такая как lm.
Мы можем определить нашу собственную, которая заменяет столбец, содержащий NA, матрицей, содержащей исходный вектор, со средним значением, заменяющим NA, и фиктивной переменной, указывающей, что произошло.У нас может быть data.frame
универсальный вызов рекурсивно более простой реализации:
na.dummy <- function(object, ...) {
UseMethod("na.dummy", object)
}
na.dummy.numeric <- function(object, ..., m=mean(object, na.rm=TRUE)) {
i <- is.na(object)
structure(cbind(replace(object, i, m), `NA`=i*1),
class='na.dummy', m=m)
}
na.dummy.data.frame <- function(object, ...) {
w <- vapply(object, anyNA, TRUE)
cm <- rep(NA, length(object))
for(j in which(w)) {
object[[j]] <- na.dummy(object[[j]])
cm[j] <- attr(object[[j]], 'm')
}
structure(object,
na.action=structure(cm, class='dummy'))
}
Удивительно, но это в основном работает.Однако, когда вы пытаетесь predict()
на новых данных, система ломается.Ниже приведена функция, которая редактирует метаданные модели для правильной настройки фрейма модели для прогнозирования:
fix_predvars <- function(object){
pv <- attr(terms(object), "predvars")
cm <- na.action(object)
for(j in seq_along(cm)) {
if(is.na(cm[j])) next
newpv <- quote(na.dummy())
newpv[[2]] <- pv[[j+1]]
newpv[["m"]] <- cm[j]
pv[[j+1]] <- newpv
}
attr(object$terms, 'predvars') <- pv
object
}
makepredictcall.na.dummy <- function(var, call){
if (as.character(call)[1L] != "na.dummy")
return(call)
call["m"] <- attr(var, "m")
call
}
predict.na.dummy <- function(object, newx, ...)
{
if(missing(newx))
return(object)
na.dummy(newx, m=attr(object, "m"))
}
Это пример фактического подбора модели, а затем ее использования для создания прогноза в случае отсутствияданные:
> (m <- lm(Y~X1+X2, df, na.action = na.dummy))
Call:
lm(formula = Y ~ X1 + X2, data = df, na.action = na.dummy)
Coefficients:
(Intercept) X1 X2 X2NA
0.2313 0.9715 1.9356 5.9521
> m2 <- fix_predvars(m)
> predict(m2, newdata = data.frame(X1=2,X2=NA_real_))
1
17.80423