提前为笨重的代码道歉。 我有一个类似于以下的数据框:
df <- data.frame(c(rep_len(1,5), 2, 2), c("A", "A", "B", "B", "C", "C", "C"))
names(df) <- c("id", "consequence")
id consequence
1 1 A
2 1 A
3 1 B
4 1 B
5 1 C
6 2 C
7 2 C
我想执行以下过滤操作:
如果id by group包含结果A或B,则保留这些行,并删除带有结果C的行。如果一个组只包含C或单行,则保留那些/那些行/行。
我试图在dplyr中使用自定义函数执行此操作,但是存在所有行都被过滤的问题,从而消除了所有后果C:
# filtering function:
consequence_select <- function(x) {
if(n_distinct(x$consequence) > 1) {
if(any(unique(x$consequence) %in% c("A", "B"))) {
x %>%
filter(consequence %in% c("A", "B"))} else {return(x)}
} else {return(x)}
}
df %>%
group_by(id) %>%
consequence_select
id consequence
1 1 A
2 1 A
3 1 B
4 1 B
我能用plyr正确地做到这一点:
ddply(df, .(id), consequence_select)
id consequence
1 1 A
2 1 A
3 1 B
4 1 B
5 2 C
6 2 C
答案 0 :(得分:4)
使用dplyr
,您需要将函数包装在do
:
df %>%
group_by(id) %>%
do(consequence_select(.))
.
是指代数据框df
的“代词”。
答案 1 :(得分:4)
您可以通过仅在filter
参数内部而不是do
内部应用来优化代码,因为filter
是此类任务的专用dplyr函数。我创建了两个函数,并使用现有答案对它们进行基准测试。您要使用哪个功能取决于您的要求 - 对于样本数据,它们都会产生相同的结果。我还为基准测试创建了稍大的样本数据,如下所示。
# sample data
df <- data.frame(id = sample(100, 1000, replace = T),
consequence = sample(LETTERS[1:3], 1000, replace = TRUE, prob = c(0.2, 0.2, 0.6)))
# the existing custom function
consequence_select <- function(x) {
if(n_distinct(x$consequence) > 1) {
if(any(unique(x$consequence) %in% c("A", "B"))) {
x %>%
filter(consequence %in% c("A", "B"))} else {return(x)}
} else {return(x)}
}
# eipi's answer
f1 <- function() {
df %>%
group_by(id) %>%
do(consequence_select(.)) }
# jazzuro's answer
f2 <- function() {
df %>%
group_by(id) %>%
do(if(all(.$consequence == "C")) {.} else{.[-which(.$consequence == "C"), ]}) }
# my answer 1
f3a <- function() {
df %>%
group_by(id) %>%
filter((consequence != "C" & n_distinct(consequence) > 1L) | all(consequence == "C") )
}
# my answer 2
f3b <- function() {
df %>%
group_by(id) %>%
filter((consequence %in% c("A", "B") & n_distinct(consequence) > 1L) | all(consequence == "C"))
}
library(microbenchmark)
microbenchmark(f1(), f2(), f3a(), f3b(), unit = "relative")
Unit: relative
expr min lq median uq max neval
f1() 11.243524 11.092915 10.956129 10.717519 8.859949 100
f2() 6.603549 6.663674 6.653424 6.566012 10.956784 100
f3a() 1.279952 1.294679 1.291719 1.294606 1.165322 100
f3b() 1.000000 1.000000 1.000000 1.000000 1.000000 100
all.equal(f1(), f3a())
#[1] TRUE
all.equal(f1(), f3b())
#[1] TRUE
正如您所看到的,数据量的略微增加已经显示出功能之间的速度差异> 10倍。
答案 2 :(得分:3)
您可以使用do
执行此类功能。 foo
是您的数据。
foo %>%
group_by(id) %>%
do(if(all(.$consequence == "C")) {.} else{.[-which(.$consequence == "C"), ]})
# id consequence
#1 1 A
#2 1 A
#3 1 B
#4 1 B
#5 2 C
#6 2 C