我想根据可能存在或不存在的变量来过滤我的数据框.作为预期的输出,我想要一个被过滤的df(如果它有过滤器变量),或者原始的,未过滤的df(如果缺少变量).
这是一个最小的例子:
library(tidyverse)
df1 <-
tribble(~a,~b,
1L,"a",
0L, "a",
0L,"b",
1L, "b")
df2 <- select(df1, b)
Run Code Online (Sandbox Code Playgroud)
过滤df1返回所需的结果,过滤后的tibble.
filter(df1, a == 1)
# A tibble: 2 x 2
a b
<int> <chr>
1 1 a
2 1 b
Run Code Online (Sandbox Code Playgroud)
但是第二个抛出错误(预期),因为变量不在df中.
filter(df2, a == 1)
Error in filter_impl(.data, quo) :
Evaluation error: object 'a' not found.
Run Code Online (Sandbox Code Playgroud)
我试过filter_at,这将是一个明显的选择,但如果没有与困境相匹配的变量,它会抛出错误.
filter_at(df2, vars(matches("a")), any_vars(. == 1L))
Error: `.predicate` has no matching columns
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是:有没有办法创建一个产生预期结果的条件过滤,最好是在tidyverse内?
正如@ docendo-discimus在评论中指出的那样,以下解决方案可行.我也加了rlang::has_name而不是"a" %in% names(.).
此问答包含最初的想法:根据外部价值有条理地应用管道步骤.
df1 %>%
filter(if(has_name("a")) a == 1 else TRUE)
# A tibble: 2 x 2
a b
<int> <chr>
1 1 a
2 1 b
df2 %>%
filter(if(has_name("a")) a == 1 else TRUE)
# A tibble: 4 x 1
b
<chr>
1 a
2 a
3 b
4 b
Run Code Online (Sandbox Code Playgroud)
或者,通过使用{}:
df1 %>%
{if(has_name("a")) filter(., a == 1L) else .}
# A tibble: 2 x 2
a b
<int> <chr>
1 1 a
2 1 b
> df2 %>%
+ {if(has_name("a")) filter(., a == 1L) else .}
# A tibble: 4 x 1
b
<chr>
1 a
2 a
3 b
4 b
Run Code Online (Sandbox Code Playgroud)