我的问题涉及在数据框的多个列中汇总值,并使用创建与此求和相对应的新列dplyr.列中的数据条目是二进制(0,1).我正在考虑一个行summarise_each或类的mutate_each函数dplyr.以下是数据框的最小示例:
library(dplyr)
df=data.frame(
x1=c(1,0,0,NA,0,1,1,NA,0,1),
x2=c(1,1,NA,1,1,0,NA,NA,0,1),
x3=c(0,1,0,1,1,0,NA,NA,0,1),
x4=c(1,0,NA,1,0,0,NA,0,0,1),
x5=c(1,1,NA,1,1,1,NA,1,0,1))
> df
x1 x2 x3 x4 x5
1 1 1 0 1 1
2 0 1 1 0 1
3 0 NA 0 NA NA
4 NA 1 1 1 1
5 0 1 1 0 1
6 1 0 0 0 1
7 1 NA NA NA NA
8 NA NA NA 0 1
9 0 0 0 0 0
10 1 1 1 1 1
Run Code Online (Sandbox Code Playgroud)
我可以使用类似的东西:
df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)
Run Code Online (Sandbox Code Playgroud)
但这将涉及写出每个列的名称.我有50个专栏.此外,列名称在我想要实现此操作的循环的不同迭代中发生更改,因此我想尝试避免必须提供任何列名.
我怎样才能最有效地做到这一点?任何帮助将不胜感激.
Boe*_*ern 81
怎么样
总结每一栏
df %>%
replace(is.na(.), 0) %>%
summarise_all(funs(sum))
Run Code Online (Sandbox Code Playgroud)
总结每一行
df %>%
replace(is.na(.), 0) %>%
mutate(sum = rowSums(.[1:5]))
Run Code Online (Sandbox Code Playgroud)
Eri*_*con 26
我会使用正则表达式匹配来对具有某些模式名称的变量求和.例如:
df <- df %>% mutate(sum1 = rowSums(.[grep("x[3-5]", names(.))], na.rm = TRUE),
sum_all = rowSums(.[grep("x", names(.))], na.rm = TRUE))
Run Code Online (Sandbox Code Playgroud)
这样,您可以创建多个变量作为数据框的某些变量组的总和.
LMc*_*LMc 23
在较新版本中,dplyr您可以使用rowwise()withc_across为没有特定行变体的函数执行行聚合,但如果存在行变体,它应该更快。
由于rowwise()它只是一种特殊的分组形式并改变了动词的工作方式,因此您可能希望ungroup()在执行逐行操作后将其通过管道传输。
要按名称选择范围:
df %>%
dplyr::rowwise() %>%
dplyr::mutate(sumrange = sum(dplyr::c_across(x1:x5), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()
Run Code Online (Sandbox Code Playgroud)
按类型选择:
df %>%
dplyr::rowwise() %>%
dplyr::mutate(sumnumeric = sum(c_across(where(is.numeric)), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()
Run Code Online (Sandbox Code Playgroud)
按列名选择:
您可以使用任意数量的整齐选择助手喜欢starts_with,ends_with,contains,等。
df %>%
dplyr::rowwise() %>%
dplyr::mutate(sum_startswithx = sum(c_across(starts_with("x")), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()
Run Code Online (Sandbox Code Playgroud)
按列索引选择:
df %>%
dplyr::rowwise() %>%
dplyr::mutate(sumindex = sum(c_across(c(1:4, 5)), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()
Run Code Online (Sandbox Code Playgroud)
rowise()将适用于任何汇总功能。但是,在您的特定情况下,存在按行的变体 ( rowSums),因此您可以执行以下操作(请注意使用across替代),这样会更快:
df %>%
dplyr::mutate(sumrow = rowSums(dplyr::across(x1:x5), na.rm = T))
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅rowwise页面。
基准测试
在这个例子中, row-wise 变体rowSums大约需要一半的时间:
library(microbenchmark)
microbenchmark(
df %>%
dplyr::rowwise() %>%
dplyr::mutate(sumrange = sum(dplyr::c_across(x1:x5), na.rm = T)),
df %>%
dplyr::mutate(sumrow = rowSums(dplyr::across(x1:x5), na.rm = T)),
times = 1000L
)
min lq mean median uq max neval cld
5.5256 6.256 7.024232 6.58885 7.02325 22.1911 1000 b
2.7011 3.112 3.661106 3.41070 3.71975 32.6282 1000 a
Run Code Online (Sandbox Code Playgroud)
Ric*_*lvo 22
如果你只想对某些列求和,我会使用这样的东西:
library(dplyr)
df=data.frame(
x1=c(1,0,0,NA,0,1,1,NA,0,1),
x2=c(1,1,NA,1,1,0,NA,NA,0,1),
x3=c(0,1,0,1,1,0,NA,NA,0,1),
x4=c(1,0,NA,1,0,0,NA,0,0,1),
x5=c(1,1,NA,1,1,1,NA,1,0,1))
df %>% select(x3:x5) %>% rowSums(na.rm=TRUE) -> df$x3x5.total
head(df)
Run Code Online (Sandbox Code Playgroud)
这样你就可以使用dplyr::select语法了.
Der*_*ger 13
我经常遇到这个问题,最简单的方法是使用命令中的apply()函数mutate.
library(tidyverse)
df=data.frame(
x1=c(1,0,0,NA,0,1,1,NA,0,1),
x2=c(1,1,NA,1,1,0,NA,NA,0,1),
x3=c(0,1,0,1,1,0,NA,NA,0,1),
x4=c(1,0,NA,1,0,0,NA,0,0,1),
x5=c(1,1,NA,1,1,1,NA,1,0,1))
df %>%
mutate(sum = select(., x1:x5) %>% apply(1, sum, na.rm=TRUE))
Run Code Online (Sandbox Code Playgroud)
在这里,您可以使用任何想要使用标准dplyr技巧(例如starts_with()或contains())的列来选择列.通过在单个mutate命令中完成所有工作,此操作可以在dplyr处理步骤流中的任何位置发生.最后,通过使用该apply()函数,您可以灵活地使用所需的任何摘要,包括您自己的专用摘要函数.
或者,如果使用非tidyverse函数的想法没有吸引力,那么您可以收集列,汇总它们并最终将结果连接回原始数据框.
df <- df %>% mutate( id = 1:n() ) # Need some ID column for this to work
df <- df %>%
group_by(id) %>%
gather('Key', 'value', starts_with('x')) %>%
summarise( Key.Sum = sum(value) ) %>%
left_join( df, . )
Run Code Online (Sandbox Code Playgroud)
在这里,我使用该starts_with()函数来选择列并计算总和,您可以使用NA值执行任何操作.这种方法的缺点是虽然它非常灵活,但它并不适合dplyr数据清理步骤.
skd*_*skd 11
使用reduce()from purrr的速度比rowSums最终要快apply,并且肯定比快,因为您避免了遍历所有行,而只是利用了矢量化操作:
library(purrr)
library(dplyr)
iris %>% mutate(Petal = reduce(select(., starts_with("Petal")), `+`))
Run Code Online (Sandbox Code Playgroud)
看到这个计时
由于很难在 @skd、@LMc 和其他人给出的所有有趣答案中做出决定,因此我对所有相当长的替代方案进行了基准测试。
与其他示例的区别在于,我使用了更大的数据集(10.000 行)和来自现实世界数据集(菱形)的数据集,因此结果可能更多地反映了现实世界数据的方差。
可重现的基准测试代码是:
set.seed(17)
dataset <- diamonds %>% sample_n(1e4)
cols <- c("depth", "table", "x", "y", "z")
sum.explicit <- function() {
dataset %>%
mutate(sum.cols = depth + table + x + y + z)
}
sum.rowSums <- function() {
dataset %>%
mutate(sum.cols = rowSums(across(cols)))
}
sum.reduce <- function() {
dataset %>%
mutate(sum.cols = purrr::reduce(select(., cols), `+`))
}
sum.nest <- function() {
dataset %>%
group_by(id = row_number()) %>%
nest(data = cols) %>%
mutate(sum.cols = map_dbl(data, sum))
}
# NOTE: across with rowwise doesn't work with all functions!
sum.across <- function() {
dataset %>%
rowwise() %>%
mutate(sum.cols = sum(across(cols)))
}
sum.c_across <- function() {
dataset %>%
rowwise() %>%
mutate(sum.cols = sum(c_across(cols)))
}
sum.apply <- function() {
dataset %>%
mutate(sum.cols = select(., cols) %>%
apply(1, sum, na.rm = TRUE))
}
bench <- microbenchmark::microbenchmark(
sum.nest(),
sum.across(),
sum.c_across(),
sum.apply(),
sum.explicit(),
sum.reduce(),
sum.rowSums(),
times = 10
)
bench %>% print(order = 'mean', signif = 3)
Unit: microseconds
expr min lq mean median uq max neval
sum.explicit() 796 839 1160 950 1040 3160 10
sum.rowSums() 1430 1450 1770 1650 1800 2980 10
sum.reduce() 1650 1700 2090 2000 2140 3300 10
sum.apply() 9290 9400 9720 9620 9840 11000 10
sum.c_across() 341000 348000 353000 356000 359000 360000 10
sum.nest() 793000 827000 854000 843000 871000 945000 10
sum.across() 4810000 4830000 4880000 4900000 4920000 4940000 10
Run Code Online (Sandbox Code Playgroud)
可视化这一点(没有异常值sum.across)有助于比较:
nest和rowwise/用于较大的数据集(> 100.000 行或重复操作)c_acrossrowSums计算开销很小purrr::reduce相对较新(但在 python 中众所周知),并且在基础 R 中非常高效,因此在 Top3 中赢得了一席之地。因为显式形式写起来很麻烦,而且除了/ 、/之外没有太多向量化方法,所以我建议所有其他函数(例如)都应用。ReducerowSumsrowMeanscolSumscolMeanssdpurrr::reduce