【问题标题】:dplyr::mutate (assign na.rm =TRUE)dplyr::mutate(分配 na.rm =TRUE)
【发布时间】:2017-05-22 15:37:24
【问题描述】:

我有一个包含 100 个变量的 data.frame。我只想使用mutate(而不是summarise)来获得三个变量的总和。

如果 3 个变量中的任何一个有 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)

【问题讨论】:

  • replace(df, is.na(df), 0) %&gt;% mutate(sum = var1 + var2 + var3)
  • @RichScriven 你的回答很棒。但是,正如我在问题中提到的那样,我有一个包含 100 个变量的 data.frame,您的答案会将所有 100 个变量中的 NA 替换为我不想要的零(不仅是 var1、var2 和 var3)

标签: r sum dplyr na


【解决方案1】:

我们可以使用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 是最好和最快的方法。但是,正如我在问题中提到的,data.frame 有 100 个变量,不仅有 3 个变量,而且这 3 个变量(var1 到 var3)具有不同的名称,并且彼此相距很远(第 3、7 和 76 列)。无论如何,rowSums 中有变量名而不是 1:3 吗?
  • @aelwan 如果你知道这些变量的位置,你可以使用names(df)[c(3, 7, 76)]或者你可以使用实际的列名,即rowSums(.[c("somename", "another", "var5")]
【解决方案2】:

rowwise() 是我的首选功能。类似于group_by(),但它将每一行视为一个单独的组。

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

【讨论】:

  • 非常感谢您的时间和帮助。 rowwise 很棒,但需要很长时间才能得到结果,尤其是我有 130 万行。
【解决方案3】:

哪里更好 = tidyr:

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

如果您的数据集准备增长...

【讨论】:

    猜你喜欢
    • 2018-05-24
    • 2014-11-03
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多