仅对非 NA 元素求和,但如果全部为 NA,则返回 NA。

11

我认为评论区已经给出了非常好的答案,但是为了以后参考方便,我会重新表述问题。

我正在尝试使用data.table按组求和。问题是有些组仅仅包含NA值。对于这些组,我希望求和结果返回NA。然而,如果有一个组中有一个不同于NA的值,我希望得到非NA值的总和。

A <- data.table(col1= c('A','A','B','B','C','C'),  
                col2= c(NA,NA,2,3,NA,4))

没有添加参数na.rm = T时,C组在应返回4的情况下返回NA。
A[, sum(col2), by = .(col1)]
   col1 V1
1:    A NA
2:    B  5
3:    C NA

然而,添加na.rm = T时,在应该返回NA的A组中返回了0。
A[, sum(col2, na.rm = T), by = .(col1)]
   col1 V1
1:    A  0
2:    B  5
3:    C  4

我最喜欢的方法是Sandipan在评论中提出的方法,类似于我下面编写的函数:

ifelse(all(is.na(col2)), NA, sum(col2, na.rm = T)

我创建了一个函数来解决这个问题,但我不确定是否已经有内置的方法可以解决这个问题:
sum.na <- function(df){

  if (all(is.na(df))){

    suma <- NA
  }  
  else {    
    suma <- sum(df, na.rm = T)
  }

  return(suma)
}

2
你能展示一个包含 data.table 的例子吗?一般来说,我认为 DT[!is.na(x), sumx := sum(x), by=id] 应该可以工作。 - Frank
1
如果x是向量,这段代码应该可以正常工作:ifelse(all(is.na(x)), NA, sum(x, na.rm=TRUE)) - Sandipan Dey
3
感谢您更新问题,即使您已经得到了答案。这使得帖子对未来的用户更有价值。 - Barker
1
是的,我也喜欢@sandipan的方法。我在自己的代码中找到了一个变体:function(x) if (all(is.na(x))) x[NA_integer_] else sum(x, na.rm = TRUE) 这确保了当所有值都为NA时,结果与x具有相同的类,并跳过不必要的ifelse。顺便说一句,如果您想“ping”或提醒某人您的消息(就像我在这里@ sandipan一样),您需要在他们的名字前使用@。 - Frank
@Gregor 谢谢您的建议。 - dleal
显示剩余4条评论
2个回答

6

根据其他用户的建议,我将发布我的问题答案。解决方案由@sandipan在上面的评论中提供:

如问题所述,如果您需要对包含NAs的一列的值求和,则有两种好的方法:

1)使用ifelse:

A[, (ifelse(all(is.na(col2)), col2[NA_integer_], sum(col2, na.rm = T))), 
  by = .(col1)]

2) 按照 @Frank 的建议定义一个函数:

suma = function(x) if (all(is.na(x))) x[NA_integer_] else sum(x, na.rm = TRUE)

A[, suma(col2), by = .(col1)]

请注意,正如@Frank所指出的那样,我添加了NA_integer_,因为我一直收到有关类型的错误。

1
使用来自“hablar”的sum_
library(hablar)
A[, as.numeric(sum_(col2)), .(col1)]
#   col1 V1
#1:    A NA
#2:    B  5
#3:    C  4

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