将引用/替换/延迟变量传递给dplyr函数

时间:2018-01-30 22:14:11

标签: r dplyr

现在我正在尝试将某些dplyr动作封装到自己的函数中。我遇到的问题是,我不确定如何传递符号,以便他们在适当的时候进行评估。

考虑以下设计的例子,我试图找到从这个数据按降序排序的前n项:

data = tibble(n = seq(10), unif = runif(10), norm = rnorm(10))

使用dplyr,我可以编写以下内容来查找前三名:

data %>% top_n(3, unif) %>% arrange(desc(unif))

现在说我想把它封装成一个函数。天真地,人们可能会尝试跟随,因为col的值将被传递,所以会失败:

top_n_sorted = function(tbl, n, col) {
  # How do I pass col as its name here?
  return(
    tbl %>%
      top_n(n, col) %>%
      arrange(desc(col))
  )
}
data %>% top_n(3, unif) %>% arrange(desc(unif))
# => KABOOM: object 'unif' not found.

我认为也许通过引用的值(通过替换或引用)可以做到这一点,但它显然从未被dplyr函数打开:

top_n_sorted = function(tbl, n, col) {
  return(
    tbl %>%
      top_n(n, quote(col)) %>%
      arrange(desc(quote(col)))
  )
}
data %>% top_n(3, unif) %>% arrange(desc(unif))
# => KABOOM: object of type 'symbol' is not subsettable.

我已经挖掘了Hadley的article on metaprogramming,虽然我理解如何在我自己的函数的上下文中使用quote,substitute和eval,但我不确定如何将符号向前传递给其他函数使用像dplyr那样的技巧。

3 个答案:

答案 0 :(得分:1)

使用当前版本的 dplyr ,我们会使用 rlang 中的参数:

$("#choiceDisplay").html(displayString);

您可以详细了解这个新系统here

答案 1 :(得分:0)

其他答案更好,更简单,但一般来说,您可以通过创建字符串并使用eval(parse(text=...))来评估它,从而制作出您想要的任何表达式。如果问题变得有点复杂并且您需要更快而不是更晚的事情,这可能会很方便。

下面我只是将col粘贴到我们想要的位置,它会吐出实际值并对其进行评估。这确实需要我在引号中输入它而不是作为符号。

top_n_sorted = function(tbl, n, col) {
  return(
         eval(
              parse(
                    text = paste0('tbl %>% top_n(n, "', col, '") %>% arrange(desc(', col, '))')
                    )
             )
        )
}

data %>% top_n_sorted(3, "unif")

答案 2 :(得分:-1)

老实说,我并没有真正得到dplyr中的非标准评估,特别是当你想知道如何传递输入时。但是,在大多数情况下,当unquoting似乎破坏了东西时,我发现只是将变量名称作为字符串起作用。通常我发现,只要你知道它是一个字符串,直到你把它赋予一个dplyr函数,它可以接受变量名的名字作为字符串,事情就不会出错。

这是一个适用于您的第一个函数的示例,例如。唯一的区别是将参数col设为"unif"而不是unif。这并不总是有效,但您没有无法使用此解决方法的情况。

top_n_sorted = function(tbl, n, col) {
  tbl %>%
    top_n(n, col)) %>%
    arrange(desc(col))
}

top_n_sorted(data, 3, "unif")