dplyr:filter_,字符条件不起作用

时间:2018-05-19 10:17:49

标签: r dplyr tidyverse rlang

这是我的数据:

df <- tibble::tribble(
  ~A,  ~B,  ~C,  ~D,
  2L, "a", "e", 2L,
  4L, "a", "f", NA_integer_,
  4L, "b", "g", NA_integer_,
  4L, "b", "h", NA_integer_
  )

df$B <- as.factor(df$B) 
df$A <- as.factor(as.character(df$A)) 

以下是我的过滤条件:

remove2 <- "as.integer(A)!=2L"

我只想用A == 2删除观察结果,但是下面的代码保留了它,为什么?

df %>% dplyr::filter_(remove2)

我想使用filter_,因为它接受条件作为字符。如果您可以建议过滤(不使用下划线版本)并将字符作为条件,那也可以。

3 个答案:

答案 0 :(得分:3)

尝试以下方法:

remove2 <- "as.numeric(as.character(A))!=2L"

df %>% dplyr::filter_(remove2)

# A tibble: 3 x 4
  A     B     C         D
  <fct> <fct> <chr> <int>
1 4     a     f        NA
2 4     b     g        NA
3 4     b     h        NA

请注意,因素的编码方式不同。参见

 as.integer(df$A)
 [1] 1 2 2 2

要获取“如图所示”的因子值,请使用as.numeric(as.character(.))

其他答案指出,下划线功能已被弃用(尽管它们仍然有效)。为了以绝对未来的方式实现这一目标,使用简单的base R:

可能是一个好主意。
df[which(df[["A"]] != 2L),]
# A tibble: 3 x 4
  A     B     C         D
  <fct> <fct> <chr> <int>
1 4     a     f        NA
2 4     b     g        NA
3 4     b     h        NA

答案 1 :(得分:3)

作为字符串的代码是反模式。它提出了一个问题:字符串来自哪里?

如果是你,开发人员,输入它,那么编写起来就更困难了(你没有受益于你的IDE功能,比如自动完成),而且更容易出错(你可以写出语法上无效的代码,在它实际被解析和评估之前不会被捕获,可能更晚,更难以理解错误)。

如果是来自不是你的用户的输入,那么这是一个主要的安全漏洞。

你可以改为:

remove2 <- quote(as.numeric(as.character(A)) != 2L)

filter(df, !! remove2)

!!是tidyeval框架中的“unquote”运算符。)

虽然它不完全令人满意(在我看来仍然是代码味道),因为很少必须取消引用整个代码段,通常它只是一个变量名。

答案 2 :(得分:2)

其他人已经解释了这个问题的原因,factor内部被编码为整数,这可能与它看起来很明显不同。我要指出的另一件事是filter_dplyr 0.7以来已被弃用。因此,我们可以考虑使用filter函数将字符串评估为以下两个选项。

remove2 <- "as.integer(as.character(A)) != 2L"

library(dplyr)
library(rlang)

df %>% filter(eval(parse(text = remove2)))
# # A tibble: 3 x 4
#   A     B     C         D
#   <fct> <fct> <chr> <int>
# 1 4     a     f        NA
# 2 4     b     g        NA
# 3 4     b     h        NA

df %>% filter(eval(parse_expr(remove2)))
# # A tibble: 3 x 4
#   A     B     C         D
#   <fct> <fct> <chr> <int>
# 1 4     a     f        NA
# 2 4     b     g        NA
# 3 4     b     h        NA