使用 dplyr 计算行中的值数
Posted
技术标签:
【中文标题】使用 dplyr 计算行中的值数【英文标题】:Count number of values in row using dplyr 【发布时间】:2016-10-10 11:05:42 【问题描述】:这个问题应该有一个简单、优雅的解决方案,但我想不通,所以就这样吧:
假设我有以下数据集,我想使用 dplyr 计算每行中存在的 2 的数量。
set.seed(1)
ID <- LETTERS[1:5]
X1 <- sample(1:5, 5,T)
X2 <- sample(1:5, 5,T)
X3 <- sample(1:5, 5,T)
df <- data.frame(ID,X1,X2,X3)
library(dplyr)
现在,以下工作:
df %>%
rowwise %>%
mutate(numtwos = sum(c(X1,X2,X3) == 2))
但是如何避免输入所有列名?
我知道没有dplyr
可能更容易做到这一点,但更一般地说,我想知道如何在不输入所有列名的情况下将dplyr
的mutate
用于多列。
【问题讨论】:
【参考方案1】:试试rowSums
:
> set.seed(1)
> ID <- LETTERS[1:5]
> X1 <- sample(1:5, 5,T)
> X2 <- sample(1:5, 5,T)
> X3 <- sample(1:5, 5,T)
> df <- data.frame(ID,X1,X2,X3)
> df
ID X1 X2 X3
1 A 2 5 2
2 B 2 5 1
3 C 3 4 4
4 D 5 4 2
5 E 2 1 4
> rowSums(df == 2)
[1] 2 1 0 1 1
或者,dplyr
:
> df %>% mutate(numtwos = rowSums(. == 2))
ID X1 X2 X3 numtwos
1 A 2 5 2 2
2 B 2 5 1 1
3 C 3 4 4 0
4 D 5 4 2 1
5 E 2 1 4 1
【讨论】:
我提到我特别想知道如何用 dplyr 做到这一点,即使它不是最好的解决方案。 @C_Z_ 查看我最近的编辑,我认为这是最短的dplyr
解决方案
.
究竟是如何工作的?是不是像data.table
中的.SD
?
我认为.
只是引用您正在变异的df
的一种方式【参考方案2】:
这是使用purrr
的另一种选择:
library(purrr)
df %>%
by_row(function(x)
sum(x[-1] == 2) ,
.to = "numtwos",
.collate = "cols"
)
这给出了:
#Source: local data frame [5 x 5]
#
# ID X1 X2 X3 numtwos
# <fctr> <int> <int> <int> <int>
#1 A 2 5 2 2
#2 B 2 5 1 1
#3 C 3 4 4 0
#4 D 5 4 2 1
#5 E 2 1 4 1
如NEWS 中所述,基于行的函数在dplyr
中仍在成熟:
我们仍在弄清楚
dplyr
中的内容和内容purrr
。期待大量的实验和许多变化 功能。
基准测试
我们可以看到rowwise()
和do()
与purrr::by_row()
在此类问题上的比较,以及它们在rowSums()
和整洁数据方式上的“表现”:
largedf <- df[rep(seq_len(nrow(df)), 10e3), ]
library(microbenchmark)
microbenchmark(
steven = largedf %>%
by_row(function(x)
sum(x[-1] == 2) ,
.to = "numtwos",
.collate = "cols"),
psidom = largedf %>%
rowwise %>%
do(data_frame(numtwos = sum(.[-1] == 2))) %>%
cbind(largedf, .),
gopala = largedf %>%
gather(key, value, -ID) %>%
group_by(ID) %>%
summarise(numtwos = sum(value == 2)) %>%
inner_join(largedf, .),
evan = largedf %>%
mutate(numtwos = rowSums(. == 2)),
times = 10L,
unit = "relative"
)
结果:
#Unit: relative
# expr min lq mean median uq max neval cld
# steven 1225.190659 1261.466936 1267.737126 1227.762573 1276.07977 1339.841636 10 b
# psidom 3677.603240 3759.402212 3726.891458 3678.717170 3728.78828 3777.425492 10 c
# gopala 2.715005 2.684599 2.638425 2.612631 2.59827 2.572972 10 a
# evan 1.000000 1.000000 1.000000 1.000000 1.00000 1.000000 10 a
【讨论】:
看起来很完美 Purrrfect 确实 ;) 虽然从最近的实验来看,by_row()
对于大型数据集来说非常缓慢。
@StevenBeaupré 很酷的比较!谢谢你把它放在一起!【参考方案3】:
只是想添加到@evan.oman 的答案,以防您只想对特定列的行求和,而不是全部。您可以使用常规的select
和/或select_helpers
函数。在此示例中,我们不想在 rowSums
中包含 X1
:
df %>%
mutate(numtwos = rowSums(select(., -X1) == 2))
ID X1 X2 X3 numtwos
1 A 2 5 2 1
2 B 2 5 1 0
3 C 3 4 4 0
4 D 5 4 2 1
5 E 2 1 4 0
【讨论】:
【参考方案4】:一种方法是使用dplyr
和tidyr
的组合将数据转换为长格式,然后进行计算:
library(dplyr)
library(tidyr)
df %>%
gather(key, value, -ID) %>%
group_by(ID) %>%
summarise(numtwos = sum(value == 2)) %>%
inner_join(df, .)
输出如下:
ID X1 X2 X3 numtwos
1 A 2 5 2 2
2 B 2 5 1 1
3 C 3 4 4 0
4 D 5 4 2 1
5 E 2 1 4 1
【讨论】:
【参考方案5】:您可以使用do
,它不会将列添加到原始数据框中,您需要将列添加到原始数据框中。
df %>%
rowwise %>%
do(numtwos = sum(.[-1] == 2)) %>%
data.frame
numtwos
1 2
2 1
3 0
4 1
5 1
添加cbind
将新列绑定到原始数据框:
df %>%
rowwise %>%
do(numtwos = sum(.[-1] == 2)) %>%
data.frame %>% cbind(df, .)
ID X1 X2 X3 numtwos
1 A 2 5 2 2
2 B 2 5 1 1
3 C 3 4 4 0
4 D 5 4 2 1
5 E 2 1 4 1
【讨论】:
谢谢,我希望dplyr
有一个更简洁的方法来做到这一点。哦,好吧!
在dplyr
和data.table
中,Rowwise 操作总是有点痛苦,因为据我所知,数据是按列存储的。
@Arun,感谢您的澄清。这也是我的猜测。以上是关于使用 dplyr 计算行中的值数的主要内容,如果未能解决你的问题,请参考以下文章