【问题标题】:Non-standard evaluation and quasiquotation in dplyr() not working as (naively) expecteddplyr() 中的非标准评估和 quasiquotation 未按(天真)预期工作
【发布时间】:2018-08-08 03:35:03
【问题描述】:

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

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

基于this discussion 我认为上面的代码可以工作。还有this post带我去试试top_n_(),好像不存在。

我正在学习vignette("programming"),这有点超出我的想象。 This post 引导我尝试 !! 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

以下基于@lionel 和@Tung 的问题和cmets 的其他令人困惑的示例。这里让我感到困惑的是,帮助文件说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"

【问题讨论】:

  • dplyr automatically quotes its inputs。这是top_n 的源代码:它使用enquo!! 来引用和取消引用输入。运行qq_show(!!quo(sym(count_colname))),看看为什么你需要在提供给top_n之前先用!!取消引用sym(count_colname)

标签: r dplyr tidyeval non-standard-evaluation quasiquotes


【解决方案1】:

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

按照@lionel 的建议使用rlang::qq_show,我们可以看到它不起作用,因为letrs_count.df 中没有count_colname

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)

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

top_n(x, n, wt)

参数:

  • x: 一个tbl() 过滤

  • n:要返回的行数。如果x 被分组,则这是每组的行数。如果有关系,将包括超过n 行。如果n 是正数,则选择顶部的n 行。如果为负,则选择底部的 n 行。

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

另请参阅以下答案:1st2nd3rd

【讨论】:

  • 谢谢。您引用的3rd post 让我认为这会起作用x &lt;- enquo(count_coln); laut.top.df &lt;- laut.count.df %&gt;% top_n(max(10, ceiling(percent * nrow(.) / 100)), !! x),但事实并非如此。这绝对是我遇到过的最令人沮丧的概念。
  • @Josh:count_coln 是什么? enquo 通常在函数内部使用。我建议你看Hadley's 5min tidy evaluation video
  • 谢谢,我想知道这是否是 enquo 的问题。仍然试图围绕sym 所做的事情。 count_colname 代表我想要的列名。它由一个唯一标识符组成,该标识符源自我的原始数据库搜索(示例中为 "derived_name")和 "_letr_count" 我在这里创建 count_colname &lt;- paste0(search_name, "_letr_count") 并在此处使用它 colnames(letrs_count.df) &lt;- c("letr", count_colname) 和导致我挣扎的 top_n 函数.
  • sym() 将字符串转换为变量名。我建议您使用rlang::qq_show() 尝试取消引用并查看结果。例如尝试var &lt;- "cyl"; rlang::qq_show(mutate(data, !!var + 1))。然后尝试!!sym(var)
  • @Josh:此链接可能有助于减轻您进入 tidyeval 的痛苦colinfay.me/tidyeval-1
【解决方案2】:

所以,我意识到我在这个问题(以及许多其他问题)中遇到的问题并不是真正的准引用和/或非标准评估,而是converting character strings into object names。这是我的新解决方案:

letrs_top.df <- letrs_count.df %>%
    top_n(5, get(count_colname))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-24
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 2019-03-23
    • 1970-01-01
    • 2017-10-27
    • 2015-03-10
    相关资源
    最近更新 更多