在dplyr谓词中将字符串作为参数传递

and*_*rey 12 string r data-manipulation parameter-passing dplyr

我希望能够为dplyr动词定义参数

condition <- "dist > 50"
Run Code Online (Sandbox Code Playgroud)

然后在dplyr函数中使用这些字符串:

require(ggplot2)
ds <- cars
ds1 <- ds %>%
   filter (eval(condition))
ds1
Run Code Online (Sandbox Code Playgroud)

但它会引发错误

Error: filter condition does not evaluate to a logical vector. 
Run Code Online (Sandbox Code Playgroud)

代码应评估为:

  ds1<- ds %>%
     filter(dist > 50)
  ds1
Run Code Online (Sandbox Code Playgroud)

导致 :

DS1

   speed dist
1     14   60
2     14   80
3     15   54
4     18   56
5     18   76
6     18   84
7     19   68
8     20   52
9     20   56
10    20   64
11    22   66
12    23   54
13    24   70
14    24   92
15    24   93
16    24  120
17    25   85
Run Code Online (Sandbox Code Playgroud)

题:

如何在dplyr动词中传递字符串作为参数?

had*_*ley 14

在下一个版本的dplyr中,它可能会像这样工作:

condition <- quote(dist > 50)

mtcars %>%
   filter_(condition)
Run Code Online (Sandbox Code Playgroud)


wib*_*ley 5

由于这些 2014 年的答案,使用rlang 的 quasiquotation可以有两种新方法。

传统的硬编码过滤器语句。 为了比较起见,该语句dist > 50直接包含在dplyr::filter().

library(magrittr)

# The filter statement is hard-coded inside the function.
cars_subset_0 <- function( ) {
  cars %>%
    dplyr::filter(dist > 50)
}
cars_subset_0()
Run Code Online (Sandbox Code Playgroud)

结果:

   speed dist
1     14   60
2     14   80
3     15   54
4     18   56
...
17    25   85
Run Code Online (Sandbox Code Playgroud)

rlang 方法与 NSE(非标准评估)。使用 dplyr小插图编程中所述,该语句dist > 50由 处理rlang::enquo(),它“使用一些黑暗魔法查看参数,查看用户键入的内容,并将该值作为 quosure 返回”。然后 rlang 取消!!引用输入“以便在周围的上下文中立即对其进行评估”。

# The filter statement is evaluated with NSE.
cars_subset_1 <- function( filter_statement ) {
  filter_statement_en <- rlang::enquo(filter_statement)
  message("filter statement: `", filter_statement_en, "`.")

  cars %>%
    dplyr::filter(!!filter_statement_en)
}
cars_subset_1(dist > 50)
Run Code Online (Sandbox Code Playgroud)

结果:

filter statement: `~dist > 50`.
<quosure>
expr: ^dist > 50
env:  global
   speed dist
1     14   60
2     14   80
3     15   54
4     18   56
17    25   85
Run Code Online (Sandbox Code Playgroud)

rlang 方法传递一个字符串。 该语句"dist > 50"作为显式字符串传递给函数,并解析为表达式 by rlang::parse_expr(),然后不引用 by !!

# The filter statement is passed a string.
cars_subset_2 <- function( filter_statement ) {
  filter_statement_expr <- rlang::parse_expr(filter_statement)
  message("filter statement: `", filter_statement_expr, "`.")

  cars %>%
    dplyr::filter(!!filter_statement_expr)
}
cars_subset_2("dist > 50")
Run Code Online (Sandbox Code Playgroud)

结果:

filter statement: `>dist50`.
   speed dist
1     14   60
2     14   80
3     15   54
4     18   56
...
17    25   85
Run Code Online (Sandbox Code Playgroud)

事情更简单 dplyr::select()。显式字符串只需要!!.

# The select statement is passed a string.
cars_subset_2b <- function( select_statement ) {
  cars %>%
    dplyr::select(!!select_statement)
}
cars_subset_2b("dist")
Run Code Online (Sandbox Code Playgroud)