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

一曲冷凌霜 提交于 2020-06-14 06:45:09

问题


If I have the following 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

How can I replace the missing values with the mean of each column within id? In my actual data I have many variables which for only ones I wish to replace so how could be done in a general way so that for example it is not replaced for var3 but only to var1 and var2?:

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

I tried something like this but I haven't found a solution:

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

回答1:


To evaluate the columns with only the column names, we can use get(). And we are going to need lapply() to perform this operation over multiple columns.

## 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]

which gives the updated 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

Update: With your updated question, to avoid running this over all columns that contain NA, don't use nm. Just use your own vector 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]

and this gives

   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



回答2:


You can use the apply function over each column such that:

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


来源:https://stackoverflow.com/questions/34124291/data-table-replace-na-with-mean-for-multiple-columns-and-by-id

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!