在R中使用data.table的`:=`对两列的值求和,忽略NA值。

22
我有一个与使用data.table和:=函数相关的非常简单的问题,我不太理解:=的行为,经常遇到类似的问题。这里是一些示例数据。
 mat <- structure(list(
              col1 = c(NA, 0, -0.015038, 0.003817, -0.011407), 
              col2 = c(0.003745, 0.007463, -0.007407, -0.003731, -0.007491)), 
              .Names = c("col1", "col2"), 
              row.names = c(NA, 10L), 
              class = c("data.table", "data.frame"))

提供

> mat
         col1      col2
 1:        NA  0.003745
 2:  0.000000  0.007463
 3: -0.015038 -0.007407
 4:  0.003817 -0.003731
 5: -0.011407 -0.007491

我想创建一个名为col3的列,它给出了col1和col2的总和。如果我使用

mat[,col3 := col1 + col2]

#        col1      col2      col3
#1:        NA  0.003745        NA
#2:  0.000000  0.007463  0.007463
#3: -0.015038 -0.007407 -0.022445
#4:  0.003817 -0.003731  0.000086
#5: -0.011407 -0.007491 -0.018898

我发现在第一行得到了一个NA,但我希望忽略NA。因此我尝试使用以下方法。

mat[,col3 := sum(col1,col2,na.rm=TRUE)]

#        col1      col2      col3
#1:        NA  0.003745 -0.030049
#2:  0.000000  0.007463 -0.030049
#3: -0.015038 -0.007407 -0.030049
#4:  0.003817 -0.003731 -0.030049
#5: -0.011407 -0.007491 -0.030049

这不是我想要的,因为它给出了col1和col2所有元素的总和。我似乎并没有理解:=的含义...如何忽略NA值获取col1和col2的元素总和?

不确定这是否相关,但以下是我的sessionInfo:

> sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] en_AU.UTF-8/en_AU.UTF-8/en_AU.UTF-8/C/en_AU.UTF-8/en_AU.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.8.3

1
可能是因为没有可供求和的键。 - A5C1D2H2I1M1N2O1R2T1
但是我不想按键求和,我想按行求和! - Vivi
8
在使用na.rm=TRUE的情况下计算行总和。 - Joshua Ulrich
2个回答

29

这是标准的R行为,与data.table无关。

将任何内容添加到NA中都会返回NA

NA + 1
## NA

sum将返回一个单独的数字

如果你想让 1 + NA 返回 1

那么你需要运行类似以下的代码

mat[,col3 := col1 + col2]
mat[is.na(col1), col3 := col2]
mat[is.na(col2), col3 := col1]

处理col1或者col2NA的情况


编辑 - 一种更简单的解决方案

你也可以使用rowSums,它有一个na.rm参数

mat[ , col3 :=rowSums(.SD, na.rm = TRUE), .SDcols = c("col1", "col2")]

rowSums是你想要的(根据定义,包含col1col2并去除NA值的矩阵的rowSums)。

(@JoshuaUlrich将其作为评论建议)


Ulrich的评论(您的编辑)似乎正是我要找的。我现在不能测试,但明天应该可以。 - Vivi
rowSums是迄今为止最快的选项,因为它是矢量化的。 - isthisthat

22

这并不是对data.table缺乏理解,而是对于R中矢量化函数的理解不足。您可以定义一个双元运算符,在处理缺失值时与“+”运算符有所不同:

 `%+na%` <- function(x,y) {ifelse( is.na(x), y, ifelse( is.na(y), x, x+y) )}

 mat[ , col3:= col1 %+na% col2]
#-------------------------------
        col1      col2      col3
1:        NA  0.003745  0.003745
2:  0.000000  0.007463  0.007463
3: -0.015038 -0.007407 -0.022445
4:  0.003817 -0.003731  0.000086
5: -0.011407 -0.007491 -0.018898

你可以使用mrdwad的评论并使用sum(... , na.rm=TRUE)来实现:

mat[ , col4 := sum(col1, col2, na.rm=TRUE), by=1:NROW(mat)]

1
我曾以为我可以做出这样的东西,但实际上我真的相信会有预先编程好的函数或方法可以做到这一点,而不需要编写自己的函数…… 我还认为:=应该按行为单位工作,也许有办法使sum()起作用(例如使用with=FALSE之类的东西)。 - Vivi
这是你对 := 的误解。它在 mat 中通过引用进行赋值,因此不需要大量的内部复制。与数据表中行的引用无关。 - mnel
4
@Vivi 这不是个坏点子。对于minmax,有pminpmax,所以为什么没有psum用于sum呢?基本上你正在寻找的是psum。我也会问这个问题! - Matt Dowle
1
@Vivi现在在这里问:https://dev59.com/kWcs5IYBdhLWcg3wHwRH - Matt Dowle
我喜欢使用by=1:NROW方法,但它似乎比%+na%的解决方案慢很多... - Vivi
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接