data.table 将 NA 替换为多列的均值和 id

data.table replace NA with mean for multiple columns and by id

如果我有以下 data.table:

dat <- data.table("id"=c(1,1,1,1,2,2,2,2), "var1"=c(NA,1,2,2,1,1,2,2),
              "var2"=c(4,4,4,4,5,5,NA,4), "var3"=c(4,4,4,NA,5,5,5,4))
   id var1 var2 var3
1:  1   NA    4    4
2:  1    1    4    4
3:  1    2    4    4
4:  1    2    4   NA
5:  2    1    5    5
6:  2    1    5    5
7:  2    2   NA    5
8:  2    2    4    4

如何用 id 中每列的平均值替换缺失值?在我的实际数据中,我有很多变量,只有我想替换的变量,所以如何以一般方式完成,例如它不会被替换为 var3,而只被替换为 var1 和 var2?:

tomean=c("var1", "var2")

我尝试过类似的方法,但还没有找到解决方案:

dat[, (tomean) := mean(tomean, na.rm=TRUE), by=id, .SDcols = tomean]

您可以对每一列使用 apply 函数,这样:

dat[,as.data.table(apply(.SD, 2, function(x) {x[is.na(x)] <- mean(x, na.rm=T); x})),by=id]
   id     var1     var2 var3
1:  1 1.666667 4.000000    4
2:  1 1.000000 4.000000    4
3:  1 2.000000 4.000000    4
4:  1 2.000000 4.000000    3
5:  2 1.000000 5.000000    5
6:  2 1.000000 5.000000    5
7:  2 2.000000 4.666667    5
8:  2 2.000000 4.000000    4

要评估只有列名的列,我们可以使用get()。我们将需要 lapply() 对多列执行此操作。

## determine the column names that contain NA values
nm <- names(dat)[colSums(is.na(dat)) != 0]
## replace with the mean - by 'id'
dat[, (nm) := lapply(nm, function(x) {
    x <- get(x)
    x[is.na(x)] <- mean(x, na.rm = TRUE)
    x
}), by = id]

它给出更新后的 dat

   id     var1     var2 var3
1:  1 1.666667 4.000000    4
2:  1 1.000000 4.000000    4
3:  1 2.000000 4.000000    4
4:  1 2.000000 4.000000    3
5:  2 1.000000 5.000000    5
6:  2 1.000000 5.000000    5
7:  2 2.000000 4.666667    5
8:  2 2.000000 4.000000    4

更新: 对于更新后的问题,为了避免 运行 在所有包含 NA 的列中出现这种情况,请不要使用 nm。只需使用您自己的矢量 tomean.

tomean <- c("var1", "var2")
dat[, (tomean) := lapply(tomean, function(x) {
    x <- get(x)
    x[is.na(x)] <- mean(x, na.rm = TRUE)
    x
}), by = id]

这给出了

   id     var1     var2 var3
1:  1 1.666667 4.000000    4
2:  1 1.000000 4.000000    4
3:  1 2.000000 4.000000    4
4:  1 2.000000 4.000000   NA
5:  2 1.000000 5.000000    5
6:  2 1.000000 5.000000    5
7:  2 2.000000 4.666667    5
8:  2 2.000000 4.000000    4