假设我有一个带有分组变量和逻辑变量的小标题,该变量指示行是否是该组的主要响应。
我要执行以下操作:
group
中的任何行被标记为is_primary
,则保留该行,但不保留该行中的其他行group
中没有用is_primary
标记的行,请全部保留以下是一些示例数据:
library(tidyverse)
data <- tibble(group=c("A","A","A","B","B","C","C","C","C"),
is_primary=c(FALSE, FALSE, FALSE,FALSE,TRUE,FALSE,FALSE,TRUE,TRUE),
value=c(1,2,3,4,5,6,7,8,9))
在上面的示例中,我想保留所有A
行,因为没有is_primary==TRUE
行,仅保留第二行B
,并保留最后一行两行C
。
我认为显而易见的解决方案是:
data %>%
group_by(group) %>%
mutate(keep_row=ifelse(any(is_primary),is_primary,TRUE))
但这会导致以下结果,但不满足上述条件。
# A tibble: 9 x 4
# Groups: group [3]
group is_primary value keep_row
<chr> <lgl> <dbl> <lgl>
1 A FALSE 1 TRUE
2 A FALSE 2 TRUE
3 A FALSE 3 TRUE
4 B FALSE 4 FALSE
5 B TRUE 5 FALSE
6 C FALSE 6 FALSE
7 C FALSE 7 FALSE
8 C TRUE 8 FALSE
9 C TRUE 9 FALSE
但是,如果我创建一个中间变量来指示该组是否具有主键,那么它会起作用。
data %>%
group_by(group) %>%
mutate(has_primary=ifelse(any(is_primary),TRUE,FALSE)) %>%
mutate(keep_row=ifelse(has_primary,is_primary,TRUE))
这导致keep_row
是正确的:
# A tibble: 9 x 5
# Groups: group [3]
group is_primary value has_primary keep_row
<chr> <lgl> <dbl> <lgl> <lgl>
1 A FALSE 1 FALSE TRUE
2 A FALSE 2 FALSE TRUE
3 A FALSE 3 FALSE TRUE
4 B FALSE 4 TRUE FALSE
5 B TRUE 5 TRUE TRUE
6 C FALSE 6 TRUE FALSE
7 C FALSE 7 TRUE FALSE
8 C TRUE 8 TRUE TRUE
9 C TRUE 9 TRUE TRUE
ifelse
中发生什么情况,第一个解决方案不起作用?
答案 0 :(得分:3)
当'is_primary'中没有TRUE元素时,我们可以使用if/else
条件返回行,或者else
仅返回'is_primary'为TRUE的行
library(dplyr)
data %>%
group_by(group) %>%
filter(if(!any(is_primary)) TRUE else is_primary)
# A tibble: 6 x 3
# Groups: group [3]
# group is_primary value
# <chr> <lgl> <dbl>
#1 A FALSE 1
#2 A FALSE 2
#3 A FALSE 3
#4 B TRUE 5
#5 C TRUE 8
#6 C TRUE 9
也可以在|
条件下完成
data %>%
group_by(group) %>%
filter(!any(is_primary) | is_primary)
# A tibble: 6 x 3
# Groups: group [3]
# group is_primary value
# <chr> <lgl> <dbl>
#1 A FALSE 1
#2 A FALSE 2
#3 A FALSE 3
#4 B TRUE 5
#5 C TRUE 8
#6 C TRUE 9
或者另一个选择是
data %>%
group_by(group) %>%
filter(sum(is_primary) == 0 | is_primary)
# A tibble: 6 x 3
# Groups: group [3]
# group is_primary value
# <chr> <lgl> <dbl>
#1 A FALSE 1
#2 A FALSE 2
#3 A FALSE 3
#4 B TRUE 5
#5 C TRUE 8
#6 C TRUE 9
或使用slice
data %>%
group_by(group) %>%
slice(if(!any(is_primary)) row_number() else which(is_primary))
上面的data.table
选项是
library(data.table)
setDT(data)[data[, .I[!any(is_primary)|is_primary], by = group]$V1]
或使用base R
data[with(data, !ave(is_primary, group, FUN = any) | is_primary),]
ifelse
的问题在于,根据?ifelse
ifelse(测试,是,否)
如果是或否太短,则将其元素回收。当且仅当测试的任何一个要素为真,并且类似地为否,才会评估是。
使用OP的代码
ifelse(any(is_primary),TRUE,FALSE)
any
返回一个逻辑向量length
1。根据?any
该值是长度为1的逻辑向量。
根据上面的ifelse
文档,这些值被回收
答案 1 :(得分:3)
您的问题是ifelse()
返回的向量就是输入的长度。当您传递ifelse(any(),...)
时,该any()
仅返回对该组重复的单个向量。您可以通过
x <- c(F,T,F,T, F)
ifelse(any(x), x, TRUE)
# [1] FALSE
注意仅返回一个值。 ifelse()
不仅仅是适当的if \ else
语句的快捷方式。它是向量化函数,因此在尝试以非向量化方式有条件地执行代码时,请小心不要使用它。
表达过滤器的另一种方法是
data %>%
group_by(group) %>%
filter(any(is_primary) & is_primary | !any(is_primary))