将数据框与缺失值对齐

Aligning Data frame with missing values

我正在使用具有许多 NA 值的数据框。虽然我能够创建线性模型,但由于缺少值和指示列,我随后无法将模型的拟合值与原始数据对齐。

这是一个可重现的例子:

library(MASS)
dat <- Aids2
# Add NA's 
dat[floor(runif(100, min = 1, max = nrow(dat))),3] <- NA
# Create a model
model <- lm(death ~ diag + age, data = dat)
# Different Values
length(fitted.values(model))
# 2745
nrow(dat)
# 2843

这里其实有3种解法:

  1. 填充 NA 到我们自己的拟合值;
  2. 使用predict()计算拟合值;
  3. 我们自己删除不完整的案例,只将完整的案例传递给 lm()

选项 1

## row indicator with `NA`
id <- attr(na.omit(dat), "na.action")
fitted <- rep(NA, nrow(dat))
fitted[-id] <- model$fitted
nrow(dat)
# 2843
length(fitted)
# 2843
sum(!is.na(fitted))
# 2745

选项 2

## the default NA action for "predict.lm" is "na.pass"
pred <- predict(model, newdata = dat)  ## has to use "newdata = dat" here!
nrow(dat)
# 2843
length(pred)
# 2843
sum(!is.na(pred))
# 2745

选项 3

或者,您可以简单地将没有任何 NA 的数据帧传递给 lm():

complete.dat <- na.omit(dat)
fit <- lm(death ~ diag + age, data = complete.dat)
nrow(complete.dat)
# 2745
length(fit$fitted)
# 2745
sum(!is.na(fit$fitted))
# 2745

综上所述,

  • 选项 1 通过填充 NA 以直接的方式完成 "alignment",但我认为人们很少采用这种方法;
  • 选项2很简单,但是计算量更大;
  • 选项 3 是我的最爱,因为它使所有事情变得简单。

我使用了一个简单的 for 循环。拟合值具有它们所属的原始行的属性(名称)。因此:

for(i in 1:nrow(data)){
  data$fitted.values[i]<-
    fit$fitted.values[paste(i)]
}

"data" 是您的原始数据框。 Fit 是模型中的对象(即 fit <- lm(y~x, data = data))

我的回答是对@ithomps 解决方案的扩展:

for(i in 1:nrow(data)){
  data$fitted.values.men[i]<- ifelse(data$sex == 1, 
    fit.males$fitted.values[paste(i)], "NA")
  data$fitted.values.women[i]<- ifelse(data$sex == 0, 
    fit.females$fitted.values[paste(i)], "NA")
  data$fitted.values.combined[i]<- fit.combo$fitted.values[paste(i)]
}

因为在我的案例中,我 运行 三个模型:1 个男性模型,1 个女性模型,1 个混合模型。为了让事情 "more" 方便:男性和女性 运行 分布在我的 data 中。此外,我将丢失数据作为 lm() 的输入,因此我 fit <- lm(y~x, data = data, na.action = na.exclude) 以在我的模型对象 (fit) 中获取 NA。

希望这对其他人有帮助。

(我发现很难制定我的 issue/question,很高兴我找到了这个 post!)

如果您不想更改原始数据。试试这个方法,真的很简单

names(fitted.values(model)) 是可用观察数据的行名,我们可以使用此功能添加新列:

dat[names(fitted.values(model)), "fitted.values"] <- fitted.values(model)
sum(!is.na(dat[, "fitted.values"]))
# [1] 2745