计算 data.table 中某行的一部分中的 NA

Counting the NA's in a part of a row in data.table

我有一个数据集 df,其结构类似于以下示例:

nr countrycode questionA questionB questionC WeightquestionA WeightquestionB WeightquestionC
1  NLD               2         1         4         0.6             0.2             0.2
2  NLD               NA        4         NA        0.4             0.4             0.2
3  NLD               4         4         1         0.2             0.2             0.6
4  BLG               1         NA        1         0.1             0.5             0.4
5  BLG               5         3         5         0.2             0.2             0.6

问题 A、B 和 C 涉及相似的主题,因此我想为所有问题创建一个平均分数,同时考虑到每个问题的重要性 (WeightquestionA WeightquestionB WeightquestionC)。

目前我已经手动计算了平均分。

(questionA*WeightquestionA) + (questionB*WeightquestionB) + (questionC*WeightquestionC)

如果不是 NA 的话,这不会是一个无法克服的问题(因为:不,他们不能被删除)。因此,我想自动化该过程。

我目前正在考虑使用 sum(!is.na()) 计算每一行(1 到 5)的每个问题(A、B、C)中的非 NA,并将该值放入新列中。

使用 data.table 然而,我总是无法正确使用语法。我相信它应该是这样的:

df[, NonNA:=sum(!is.na(questionA + questionB + questionC))]

但这对列中的所有 NA 求和,而不是对每一行求和。我应该如何编写语法来计算每行?

我想按名称分别引用列,因为它们在实际 df 中并不相邻。

期望的输出:

nr countrycode qA qB qC WeightquestionA WeightquestionB WeightquestionC NonNA
1  NLD         2  1  4         0.6             0.2             0.2      3
2  NLD         NA 4  NA        0.4             0.4             0.2      1
3  NLD         4  4  1         0.2             0.2             0.6      3
4  BLG         1  NA 1         0.1             0.5             0.4      2
5  BLG         5  3  5         0.2             0.2             0.6      3

我们可以使用 apply 计算非 NA(对于列 questionAquestionBquestionC,即列号 3 到 5),如下所示:

df$nonNA=apply(df[,3:5], 1, function(x) length(which(!is.na(x))))

或(来自snoarm的建议)

df$nonNA=apply(df[,3:5], 1, function(x) sum(!is.na(x)))

示例输出:

   questionA questionB questionC nonNA
1         2         1         4     3
2        NA         4        NA     1
3         4         4         1     3
4         1        NA         1     2
5         5         3         5     3

使用 data.table,你可以这样做:

df[, NonNA := sum(!is.na(questionA), !is.na(questionB), !is.na(questionC)), by = .(nr)]

基本解决方案:

df$nonNA <- rowSums(!is.na(df[,c("questionA", "questionB", "questionC")]))

snoram 推荐的另一种选择:

df[, NonNA := rowSums(!is.na(.SD)), 
    .SDcols=paste0("question", LETTERS[1:3])]

还有:

df[, NonNA := Reduce(function(x, y) x + !is.na(y), .SD, init=rep(0L, .N)), 
    .SDcols=paste0("question", LETTERS[1:3])]