我的问题涉及到对 Dataframe 中多列的值求和,并使用dplyr
创建一个与此求和对应的新列。列中的数据项是二进制(0,1)。我考虑的是dplyr
的summarise_each
或mutate_each
函数的行模拟。下面是 Dataframe 的一个最小示例:
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
我可以用这样的话:
df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)
但是这会涉及到写出每一列的名字。2我有50列。3另外,在我想要实现这个操作的循环的不同迭代中,列的名字会改变,所以我想尽量避免给予任何列的名字。
我怎样才能最有效地做到这一点?任何帮助将不胜感激。
8条答案
按热度按时间wnavrhmk1#
dplyr〉= 1.0.0,使用横向
使用
rowSums
对每行求和(rowwise
适用于任何聚合,但速度较慢)对每列求和
深度〈1.0.0
对每一行求和
使用superseeded
summarise_all
对每列求和:gtlvzcf82#
深度〉= 1.0.0
在新版本的
dplyr
中,您可以将rowwise()
与c_across
沿着使用,以便为没有特定行变量的函数执行行聚合,但是如果存在行变量,则应该比使用rowwise
(例如rowSums
、rowMeans
)更快。由于
rowwise()
只是一种特殊形式的分组,并且改变了动词的工作方式,因此您可能希望在执行完行操作后将其通过管道传输到ungroup()
。要按名称选择范围:
要按类型选择:
要按列名选择:
您可以使用任意数量的tidy selection helpers,如
starts_with
、ends_with
、contains
等。要按列索引选择:
rowise()
将适用于 * 任何汇总函数 *。但是,在您的特定情况下,存在一个按行变量(rowSums
),因此您可以执行以下操作(注意,使用across
),这样会更快:有关详细信息,请参阅rowwise页面。
更新了dplyr 1.1.0
请注意,从dplyr 1.1.0开始,添加了
pick
动词,目的是替换此处across
的使用方式。across
用于将函数应用于整理选择 Dataframe 的每列。pick
用于为在整个 Dataframe 上操作的函数创建整理选择 Dataframe :基准测试
rowwise
使管道链可读性很强,对于较小的 Dataframe 也能很好地工作,但是效率很低。rowwise
与按行变量函数对于本例,行方式变量
rowSums
要快得多:**没有按行变量函数的大型 Dataframe **
如果你的函数没有一个行变量,并且你有一个很大的 Dataframe ,考虑一个长格式,它比
rowwise
更有效。虽然可能有更快的非tidyverse选项,这里有一个tidyverse选项(使用tidyr::pivot_longer
):c_横向与横向拾取
如上所述,
pick
是在dplyr 1.1.0中引入的,以替换这里使用across
的方式,如果使用此版本或更新版本,请将across
替换为pick
。在
sum
函数的特定情况下,across
和c_across
对上面的大部分代码给予相同的输出:c_across
的按行输出是一个向量(因此c_
),而across
的按行输出是一个单行tibble
对象:要应用的函数必须使用哪个动词。如上面的
sum
所示,它们几乎可以互换使用。但是,mean
和许多其他常见函数都要求将(数值)向量作为第一个参数:忽略平均值(
rowMean
)存在的行向变量,则在这种情况下应使用c_across
:rowSums
、rowMeans
等可以将数字 Dataframe 作为第一个参数,这就是它们使用across
的原因。uttx8gqw3#
如果只想对某些列求和,我会使用如下代码:
这样就可以使用
dplyr::select
的语法。9rbhqvlz4#
我会使用正则表达式匹配来对具有特定模式名称的变量求和。
通过这种方式,您可以创建多个变量作为数据框中某组变量的总和。
vsnjm48y5#
使用
purrr
中的reduce()
比rowSums
稍快,但肯定比apply
快,因为您避免了对所有行进行迭代,而只是利用了矢量化操作:有关计时,请参阅此内容
wooyq4lh6#
我经常遇到这个问题,最简单的方法是在
mutate
命令中使用apply()
函数。在这里,您可以使用标准的
dplyr
技巧来选择列(例如starts_with()
或contains()
)。通过在单个mutate
命令中执行所有工作,此操作可以在dplyr
处理步骤流中的任何位置发生。最后,通过使用apply()
函数,您可以灵活地使用所需的任何摘要。包括您自己专门构建的总结功能。或者,如果使用非tidyverse函数的想法不吸引人,那么您可以收集列,汇总它们,最后将结果连接回原始数据框。
这里我使用了
starts_with()
函数来选择列并计算总和,你可以对NA
值做任何你想做的事情。这种方法的缺点是,尽管它非常灵活,但它并不真正适合dplyr
的数据清理步骤流。rjjhvcjd7#
对(几乎)所有选项进行基准测试以跨列求和
由于很难在@skd、@LMc和其他人给出的所有有趣的答案中做出决定,我对所有合理长度的替代方案进行了基准测试。
与其他示例的不同之处在于,我使用了一个更大的数据集(10.000行),并且来自真实的世界的数据集(菱形),因此结果可能更多地反映了真实世界数据的差异。
可重现的基准测试代码为:
将其可视化(无离群值
sum.across
)有助于比较:结论(主观!)
1.尽管
nest
和rowwise
/c_across
可读性很好,但不推荐用于较大的数据集(〉100.000行或重复操作)1.显式求和胜出,因为它在内部最好地利用了求和函数的矢量化,
rowSums
也利用了该矢量化,但计算开销很小purrr::reduce
在tidyverse中相对较新(但在python中众所周知),并且作为base R中的Reduce
非常高效,从而在Top3中赢得一席之地。由于显式形式编写起来很麻烦,而且除了rowSums
/rowMeans
、colSums
/colMeans
之外,矢量化方法并不多,我建议所有其他函数(例如sd
)应用purrr::reduce
。yptwkmov8#
如果您想使用向量跨列或跨行求和,但在本例中修改df而不是向df添加新列。
您可以使用扫描功能:
按行顺序求和(向量+ Dataframe ):
按列顺序求和(向量+ Dataframe ):
这与
vector+df
的说法相同和“是”。您可以将扫描与以下内容一起使用:
另一种方法是将Reduce与column-wise一起使用: