dplyr::mutate (assign na.rm =TRUE)

9
我有一个包含100个变量的data.frame。我只想使用mutate(而不是summarise)获取三个变量的总和。
如果三个变量中的任何一个包含NA值,我仍希望得到它们的sum。为了使用mutate实现这一点,我使用ifelse将所有的NA值替换为0,然后获取了它们的sum
library(dplyr)
df %>% mutate(mod_var1 = ifelse(is.na(var1), 0, var1),
              mod_var2 = ifelse(is.na(var2), 0, var2),
              mod_var3 = ifelse(is.na(var3), 0, var3),
              sum = (mod_var1+mod_var2+mod_var3))

有没有更好(更短)的方法来完成这个任务?

数据

df <- read.table(text = c("
var1    var2    var3
4   5   NA
2   NA  3
1   2   4
NA  3   5
3   NA  2
1   1   5"), header =T)

3
用0替换数据框df中的缺失值,并使用mutate函数计算var1、var2和var3的总和。 - Rich Scriven
@RichScriven 你的回答很好。然而,正如我在问题中提到的,我有一个包含100个变量的数据框,你的回答会将所有100个变量中的NA替换为零(不仅仅是var1、var2和var3),这不是我想要的。 - shiny
3个回答

10

rowwise()是我常用的函数。它类似于group_by(),但是它将每一行视为一个单独的组。

df %>% rowwise() %>% mutate(Sum = sum(c(var1, var2, var3), na.rm = TRUE))

非常感谢您的时间和帮助。rowwise很棒,但是在我有130万行数据时,得到结果需要很长时间。 - shiny

6
我们可以使用Reduce+一起使用。
df %>% 
     mutate_each(funs(replace(., is.na(.), 0)), var1:var3) %>% 
     mutate(Sum = Reduce(`+`, .))      
#   var1 var2 var3 Sum
#1    4    5    0   9
#2    2    0    3   5
#3    1    2    4   7
#4    0    3    5   8
#5    3    0    2   5
#6    1    1    5   7

或者使用 rowSums

df %>% 
   mutate(Sum = rowSums(.[names(.)[1:3]], na.rm = TRUE))
#   var1 var2 var3 Sum
#1    4    5   NA   9
#2    2   NA    3   5
#3    1    2    4   7
#4   NA    3    5   8
#5    3   NA    2   5
#6    1    1    5   7

基准测试

set.seed(24)
df1 <- as.data.frame(matrix(sample(c(NA, 1:5), 1e6 *3, replace=TRUE),
                dimnames = list(NULL, paste0("var", 1:3)), ncol=3))
system.time({
df1 %>% rowwise() %>% mutate(Sum = sum(c(var1, var2, var3), na.rm = TRUE))
})
# user  system elapsed 
#  21.50    0.03   21.66 

system.time({
df1 %>%
    mutate(rn = row_number()) %>%
    gather(var, varNum, var1:var3) %>%
    group_by(rn) %>%
    mutate(sum = sum(varNum, na.rm = TRUE)) %>% 
    spread(var, varNum)})
 # user  system elapsed 
 #  5.96    0.39    6.37 


system.time({
replace(df1, is.na(df1), 0) %>% mutate(sum = var1 + var2 + var3)
})

# user  system elapsed 
#   0.17    0.01    0.19 

system.time({
df1 %>% 
     mutate_each(funs(replace(., is.na(.), 0)), var1:var3) %>% 
     mutate(Sum = Reduce(`+`, .))      
})
# user  system elapsed 
#   0.10    0.02    0.11 

system.time({
df1 %>% 
   mutate(Sum = rowSums(.[names(.)[1:3]], na.rm = TRUE))
   })
# user  system elapsed 
#   0.04    0.00    0.03 

非常感谢您的时间和帮助。从您的回答中看来,rowSums是最好且最快的方法。然而,正如我在问题中提到的,数据框有100个变量,不仅仅是3个变量,而且这3个变量(var1到var3)具有不同的名称,并且它们相距很远,例如(第3列、第7列和第76列)。是否有任何方法可以在rowSums中使用变量名而不是1:3? - shiny
2
如果您知道这些变量的位置,您可以使用 names(df)[c(3, 7, 76)] 或者您可以使用实际列名即 rowSums(.[c("somename", "another", "var5")] - akrun

2

better=tidyr时:

df %>%
    mutate(rn = row_number()) %>%
    gather(var, varNum, var1:var3) %>%
    group_by(rn) %>%
    mutate(sum = sum(varNum, na.rm = TRUE)) %>% 
    spread(var, varNum)

如果你的数据集有扩大的趋势,那么使用云计算资源可以帮助你更好地应对。

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