如何在``dplyr``或``tidyr``中的多列上进行rowSums?

时间:2015-08-05 22:05:29

标签: r dplyr tidyr

例如,是否可以在dplyr中执行此操作:

new_name <- "Sepal.Sum"
col_grep <- "Sepal"

iris <- cbind(iris, tmp_name = rowSums(iris[,grep(col_grep, names(iris))]))
names(iris)[names(iris) == "tmp_name"] <- new_name

这会在名称中添加包含“Sepal”的所有列,并创建一个名为“Sepal.Sum”的新变量。

重要的是,在为grep函数选择列时,解决方案需要依赖dplyr:::matches(或dplyr:::one_ofrowSums等),并拥有新列的名称是动态的。

我的应用程序在循环中创建了许多新列,因此更好的解决方案是使用mutate_each_生成许多新列。

2 个答案:

答案 0 :(得分:9)

Here a dplyr solution that uses the contains special functions to be used inside select.

 iris %>% mutate(Sepal.Sum = iris %>% rowwise() %>% select(contains("Sepal")) %>% rowSums()) -> iris2
 head(iris2)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Sum
1          5.1         3.5          1.4         0.2  setosa       8.6
2          4.9         3.0          1.4         0.2  setosa       7.9
3          4.7         3.2          1.3         0.2  setosa       7.9
4          4.6         3.1          1.5         0.2  setosa       7.7
5          5.0         3.6          1.4         0.2  setosa       8.6
6          5.4         3.9          1.7         0.4  setosa       9.3

and here the benchmarks:

Unit: milliseconds
                                                                                                      expr
 iris2 <- iris %>% mutate(Sepal.Sum = iris %>% rowwise() %>% select(contains("Sepal")) %>%      rowSums())
      min      lq     mean   median       uq      max neval
 1.816496 1.86304 2.132217 1.928748 2.509996 5.252626   100

答案 1 :(得分:2)

由于时间过长,不想发表评论。

在解决方案的时间安排方面(期望看起来较低的data.table解决方案)已经提出并且没有任何突出显示更优雅。

library(dplyr)
library(data.table)
new_name <- "Sepal.Sum"
col_grep <- "Sepal"
# Make iris bigger
data(iris)
for(i in 1:18){
  iris <- bind_rows(iris, iris)
}
iris1 <- iris
system.time({ 
  # Base solution
  iris1 <- cbind(iris1, tmp_name = rowSums(iris1[,grep(col_grep, names(iris1))])) 
  names(iris1)[names(iris1) == "tmp_name"] <- new_name 
}) 
# 1.26

system.time({ 
  # less elegant dplyr solution
  iris %>% select(matches(col_grep)) %>% rowSums() %>% 
    data.frame(.) %>% bind_cols(iris, .) %>% setNames(., c(names(iris), new_name)) 
})
# 1.14

system.time({ 
  # bit more elegant dplyr solution
  iris %>% mutate(tmp_name = rowSums(.[] %>% select(matches(col_grep)))) %>% 
    rename_(.dots = setNames("tmp_name", new_name))
})
# 1.12

data(iris)
# Make iris bigger
for(i in 1:18){
  iris <- rbindlist(list(iris, iris))
}
system.time({
  setDT(iris)[, tmp_name := rowSums(.SD[,grep(col_grep, names(iris)), with = FALSE])]
  setnames(iris, "tmp_name", new_name)
})
# 2.39