dplyr()中的非标准评估和准范式不符合(天真)预期的工作

Jos*_*osh 4 r dplyr non-standard-evaluation tidyeval quasiquotes

我正在尝试搜索数据库,然后"derived_name"在下面的可重现示例中使用从原始搜索派生的名称标记输出.我正在使用dplyr管道%>%,我在准静态评估和/或非标准评估方面遇到了麻烦.具体而言,使用在最终函数中count_colname派生自的字符对象无法对数据帧进行子集化."derived_name"top_n()

search_name <- "derived_name"
set.seed(1)
letrs <- letters[rnorm(52, 13.5, 5)]
letrs_count.df <- letrs %>%
    table() %>%
    as.data.frame()
count_colname <- paste0(search_name, "_letr_count")
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_top.df <- letrs_count.df %>%
    top_n(5, count_colname)
identical(letrs_top.df, letrs_count.df)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)

根据这个讨论,我认为上面的代码可行.而这篇文章引起我去尝试top_n_(),这似乎不存在.

我正在学习vignette("programming")哪个有点过头了.这篇文章让我尝试了!! sym()语法,这有效,但我不明白为什么!帮助理解为什么下面的代码工作将非常感激.谢谢.

colnames(letrs_count.df) <- c("letr", count_colname)
letrs_top.df <- letrs_count.df %>%
    top_n(5, (!! sym(count_colname)))
letrs_top.df
#   letr derived_name_letr_count
# 1    l                       5
# 2    m                       6
# 3    o                       7
# 4    p                       5
# 5    q                       6
Run Code Online (Sandbox Code Playgroud)

基于@lionel和@Tung的问题和评论的其他令人困惑的例子如下.令我困惑的是,帮助文件说sym()"把字符串作为输入并将它们变成符号"和!!"取消引用它的论点".但是,在下面的示例中,sym(count_colname)似乎没有引用derived_name_letr_count.我不明白为什么!!需要!! sym(count_colname),因为sym(count_colname)qq_show(!! sym(count_colname))给出相同的价值.

count_colname
# [1] "derived_name_letr_count"
sym(count_colname)
# derived_name_letr_count
qq_show(count_colname)
# count_colname
qq_show(sym(count_colname))
# sym(count_colname)
qq_show(!! sym(count_colname))
# derived_name_letr_count
qq_show(!! count_colname)
# "derived_name_letr_count"
Run Code Online (Sandbox Code Playgroud)

Tun*_*ung 6

根据top_n文档(?top_n),它不支持character/ string输入因此第一个例子不起作用.在第二个示例中,rlang::sym将字符串转换为变量名称,然后!!取消引用它,以便可以在内部进行求值top_n.注意:top_n和其他dplyr动词自动引用他们的输入.

根据rlang::qq_show@lionel的建议,我们可以看到它不起作用,因为没有count_colnameletrs_count.df

library(tidyverse)

set.seed(1)
letrs <- letters[rnorm(52, 13.5, 5)]
letrs_count.df <- letrs %>%
  table() %>%
  as.data.frame()

search_name <- "derived_name"
count_colname <- paste0(search_name, "_letr_count")
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_count.df
#>    letr derived_name_letr_count
#> 1     b                       1
#> 2     c                       1
#> 3     f                       2
...

rlang::qq_show(top_n(letrs_count.df, 5, count_colname))
#> top_n(letrs_count.df, 5, count_colname)
Run Code Online (Sandbox Code Playgroud)

sym!!创建存在的正确列名letrs_count.df

rlang::qq_show(top_n(letrs_count.df, 5, !! sym(count_colname)))
#> top_n(letrs_count.df, 5, derived_name_letr_count)

letrs_count.df %>%
  top_n(5, !! sym(count_colname))
#>   letr derived_name_letr_count
#> 1    l                       5
#> 2    m                       6
#> 3    o                       7
#> 4    p                       5
#> 5    q                       6
Run Code Online (Sandbox Code Playgroud)

top_n(x, n, wt)

参数:

  • x:a tbl()来过滤

  • n:要返回的行数.如果x已分组,则这是每个组的行数.n如果有联系,将包括多行.如果n为正,则选择顶n行.如果为负数,则选择底n行.

  • wt: (可选的).用于订购的变量.如果未指定,则默认为中的最后一个变量tbl.该参数自动引用,稍后在数据框的上下文中进行评估.它支持unquoting.有关vignette("programming")这些概念的介绍,请参阅.

另见这些答案:第1,第2,第3

  • @Josh:什么是`count_coln`?`enquo`通常用在函数内部.我建议你看[哈德利的5分钟整洁评价视频](https://www.youtube.com/watch?v=nERXS3ssntw) (2认同)
  • `sym()`将字符串转换为变量名.我建议你使用`rlang :: qq_show()`来试验unquoting并查看结果.例如,尝试`var < - "cyl"; rlang :: qq_show(mutate(data,!! var + 1))`.然后尝试`!! sym(var)` (2认同)