1

原始问题

谁能向我解释为什么 unquote 在下面不起作用?

我想do在 0.7.4 版本的调用中传递(函数)用户指定的列名dplyr。与使用do_. 一个基本的(成功的)示例忽略了在此处使用非常不必要的事实,do例如:

sum_with_do <- function(D, x, ...) {
    x <- rlang::ensym(x)
    gr <- quos(...)

    D %>%
        group_by(!!! gr) %>%
        do(data.frame(y=sum(.[[quo_name(x)]])))
}

D <- data.frame(group=c('A','A','B'), response=c(1,2,3))
sum_with_do(D, response, group)

# A tibble: 2 x 2
# Groups:   group [2]
  group     y
  <fct> <dbl>
1 A        3.
2 B        3.

rlang::从现在导出的 dplyr 0.7.5 开始,这是不必要的ensym。我已经包括了 Lionel 关于使用ensymhere 而不是的建议enquo,因为前者保证 的值x是一个符号(而不是表达式)。

取消引用在这里没有用(例如其他dplyr 示例),替换quo_name(x)!! x上面的会产生以下错误:

Error in ~response : object 'response' not found

解释

根据接受的响应,根本原因是do不会在其他 dplyr 函数(例如mutate)使用的相同环境中评估表达式。

我从文档或源代码中都没有发现这一点非常清楚(例如,比较 data.frames 的源代码,mutate如果do愿意的话,可以跟着 Alice 走下兔子洞),但本质上——这可能不是什么新鲜事最多;

  • do在其父环境是调用环境的环境中计算表达式,并将 data.frame 的当前组(切片)附加到符号.,并且;
  • 其他 dplyr 函数“或多或少”评估 data.frame 环境中的表达式,其中 parent 是调用环境。

另请参阅Advanced R. 22. 评估以获取“数据屏蔽”方面的描述。

4

1 回答 1

1

这是因为常规do()语义中除了以下之外没有数据屏蔽.

do(df, data.frame(y = sum(.$response)))
#>   y
#> 1 6

do(df, data.frame(y = sum(.[[response]])))
#> Error: object 'response' not found

因此,您只需要将裸列名称捕获为字符串,并且无需取消引用,因为没有数据屏蔽:

sum_with_do <- function(df, x, ...) {
  # ensym() guarantees that `x` is a simple column name and not a
  # complex expression:
  x <- as.character(ensym(x))

  df %>%
    group_by(...) %>%
    do(data.frame(y = sum(.[[x]])))
}
于 2018-04-19T05:22:59.540 回答