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

Posted

技术标签:

【中文标题】在 dplyr 动词中将字符串作为参数传递【英文标题】:Passing strings as arguments in dplyr verbs 【发布时间】:2014-08-28 11:15:11 【问题描述】:

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

condition <- "dist > 50"

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

require(ggplot2)
ds <- cars
ds1 <- ds %>%
   filter (eval(condition))
ds1

但是会报错

Error: filter condition does not evaluate to a logical vector. 

代码应为:

  ds1<- ds %>%
     filter(dist > 50)
  ds1

导致:

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

问题:

如何将字符串作为参数传递给dplyr 动词?

【问题讨论】:

据我了解,这是work in progress 现在它已经完成并且是标准dplyr安装的一部分。 【参考方案1】:

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

常规硬编码过滤语句。为了比较,语句dist &gt; 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()

结果:

   speed dist
1     14   60
2     14   80
3     15   54
4     18   56
...
17    25   85

带有 NSE(非标准评估)的 rlang 方法。 如 Programming with dplyr 小插图中所述,dist &gt; 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)

结果:

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

rlang 方法传递字符串。 语句 "dist &gt; 50" 作为显式字符串传递给函数,并由 rlang::parse_expr() 解析为表达式,然后由 !! 取消引用。 p>

# 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")

结果:

filter statement: `>dist50`.
   speed dist
1     14   60
2     14   80
3     15   54
4     18   56
...
17    25   85

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

# The select statement is passed a string.
cars_subset_2b <- function( select_statement ) 
  cars %>%
    dplyr::select(!!select_statement)

cars_subset_2b("dist")

【讨论】:

【参考方案2】:

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

condition <- quote(dist > 50)

mtcars %>%
   filter_(condition)

【讨论】:

等不及了。 dplyr 的直观性和智能性一直让我感到惊讶。谢谢,哈德利! 如果想要传递多个参数怎么办?传递像list("dist &gt; 50", "speed &gt; 10") 这样的列表会返回Error: Can't convert a list to a quosure 编辑:找到它:paste(list('dist &gt; 50', 'speed &gt; 10'), collapse=" &amp; ")【参考方案3】:

虽然他们正在努力,但这里有一个使用if 的解决方法:

library(dplyr)
library(magrittr)

ds <- data.frame(attend = c(1:5,NA,7:9,NA,NA,12))

filter_na <- FALSE

filtertest <- function(x,filterTF = filter_na)
  if(filterTF) x else !(x)


ds %>%
  filter(attend %>% is.na %>% filtertest)

  attend
1      1
2      2
3      3
4      4
5      5
6      7
7      8
8      9
9     12

filter_na <- TRUE
ds %>%
  filter(attend %>% is.na %>% filtertest)

  attend
1     NA
2     NA
3     NA

【讨论】:

谢谢,@AndrewMacDonald!抱歉,之前没有提供可重现的示例 太好了,谢谢@AndrewMacDonald,这很有效,而且最重要的是给了我一个使用 dplyr 函数的简单例子——我想参考一下。再次感谢! 很高兴它有用!我在上面稍微编辑了一下(不应该在filter 中使用$ 我不知道 $ 也没有注意到故障(或者没有意识到这是由于这个原因?)。感谢您的提醒,我会记住这一点。

以上是关于在 dplyr 动词中将字符串作为参数传递的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CloudFormation 中将字符串列表作为参数传递?

在 Postman 中将类对象作为参数传递

如何在 django 2 中将 url 中的 # 作为参数传递

在 JPQL Native Query 中将查询作为查询参数传递

在 Django 中将文件路径作为 URL 参数传递

如何在存储库方法中将完整查询作为字符串作为参数传递并与@Query Annotation 一起使用?