数据框中两列含有NA值,如何求它们的和?

37

我有一个数据框,其中一些值为NA。我需要对两列求和。如果某个值是NA,我需要将它视为零。

a  b c d
1  2 3 4
5 NA 7 8

列 e 应该是 b 和 c 的总和:

e
5
7

我尝试了很多方法,做了两打搜索都没有找到答案。这似乎是个简单的问题,希望有人能帮忙!


2
如果将 NA 视为 0 进行处理,为什么不将它们转换为 0,然后执行操作呢? - erasmortg
6个回答

50
dat$e <- rowSums(dat[,c("b", "c")], na.rm=TRUE)
dat
#   a  b c d e
# 1 1  2 3 4 5
# 2 5 NA 7 8 7

谢谢!我知道一定有一个简单的解决方案。我一直尝试按行应用求和函数,但没有成功。 - StatDance
你也可以使用 apply 轻松实现,但是 rowSums 是矢量化的。顺便说一句,最佳性能将通过显式转换为矩阵来实现,例如 rowSums(as.matrix... - David Arenburg
嗨,我正在尝试将这个答案扩展到数据框列表。我迄今为止尝试了lapply(dat, function(x) x$e <- rowSums(x[,c("b", "c", "d")], na.rm=T))和dat$e <- lapply(dat, function(x) rowSums(x[,c("b", "c", "d")], na.rm=T))但都没有成功。你有什么想法吗?谢谢 - N.Varela

32

dplyr 的解决方案,取自这里

dplyr的解决方案,取自这里:
library(dplyr)
dat %>% 
    rowwise() %>% 
    mutate(e = sum(b, c, na.rm = TRUE))

3

如果您想在两列都有NA值时保留它,则可以使用以下代码:

数据样例:

dt <- data.table(x = sample(c(NA, 1, 2, 3), 100, replace = T), y = sample(c(NA, 1, 2, 3), 100, replace = T))

解决方法:

dt[, z := ifelse(is.na(x) & is.na(y), NA_real_, rowSums(.SD, na.rm = T)), .SDcols = c("x", "y")]

(data.table方法)

3

这里有另一种解决方案,使用拼接的ifelse()函数:

 dat$e <- ifelse(is.na(dat$b) & is.na(dat$c), dat$e <-0, ifelse(is.na(dat$b), dat$e <- 0 + dat$c, dat$b + dat$c))
 #  a  b c d e
 #1 1  2 3 4 5
 #2 5 NA 7 8 7

编辑,这里有另一种解决方案,使用了 @kasterma 在评论中建议的 with,这种方法更易读且直接:

 dat$e <- with(dat, ifelse(is.na(b) & is.na(c ), 0, ifelse(is.na(b), 0 + c, b + c)))

1
完美的地方,with将改善事物:dat$e <- with(dat, ifelse(is.na(b) & is.na(c ), 0, ifelse(is.na(b), 0 + c, b + c))) - kasterma
我同意,更易读了!我也编辑了答案,加入了你的解决方案,如果可以的话。 - erasmortg
totally fine @erasmortg - kasterma
4
这既不高效也不健壮。如果你有十列,你就必须嵌套10个ifelse语句,而且还有很多其他语句,谁知道需要多少。 - David Arenburg

3

希望对你有所帮助。

在某些情况下,您可能有一些非数字列。这种方法将为您服务。 请注意:对于dplyr版本1.0.0及更高版本,使用c_across()

df <- data.frame(
  TEXT = c("text1", "text2"), a = c(1,5), b = c(2, NA), c = c(3,7), d = c(4,8))

df2 <- df %>% 
  rowwise() %>% 
  mutate(e = sum(c_across(a:d), na.rm = TRUE))
# A tibble: 2 x 6
# Rowwise: 
# TEXT        a     b     c     d     e
# <chr>     <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 text1     1     2     3     4    10
# 2 text2     5    NA     7     8    20

0

dplyr

rowwise对于中等大小的数据框来说,效率非常低下。如果有一种逐行计算的变体,将会快得多。对于求和操作,可以使用rowSums。您可以使用rowSums内部包裹的pick来选择要进行求和的列:

df |>
  mutate(e = rowSums(pick(c:d), na.rm = T))
#   a  b c d  e
# 1 1  2 3 4  7
# 2 5 NA 7 8 15

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