如何撤消 ensym 并在函数内为函数指定环境?

How to undo ensym and specify the environment for a function within a function?

所以,我问这个是作为 another question 的后续行动,我认为可以解决我所有问题的解决方案。好像不是这样的。采用以下设置

library(tidyverse)

set.seed(1) 

mytib <- tibble(a = as.character(c(1:5, NA)), 
                b = as.character(c(6:8, NA, 9:10)), 
                c = as.character(sample(x = c(0,1), size = 6, replace = TRUE)))

vars <- c("a", "b")

采用 Ritchie Sacramento 在另一个 post

中创建的函数
convert_tib <- function(tib, var) {
  tib %>% 
    transmute(across(c(var, c), as.integer)) %>%
    filter(!is.na(.data[[var]]))
}

我想在该函数中添加另一个函数调用。这个想法是,我首先转换和过滤我的变量(上面的代码),然后我将它输入这个函数 experiment::ATEnocov(Y = a, Z = c, data = tib) 以获得转换和过滤数据的平均处理效果。然后我想 运行 整个函数 purrr:map 跨越一堆变量。

不幸的是,在 convert_tib 函数末尾添加此函数调用会产生错误消息 Error in eval(call$Y, envir = data) : object 'a' not found。很明显,这与调用 ATEnocov 的环境有关,但我无法弄清楚如何将变量提供给同一函数内的函数。

你真的不需要玩弄 NSE 来让它工作,你可以简单地做:

library(dplyr)
library(purrr)
library(experiment)

convert_tib <- function(tib, var) {
  d <- tib %>%
    transmute(across(c(all_of(var), c), as.integer)) %>%
    filter(!is.na(.data[[var]]))
  ATEnocov(d[[1]], d[[2]])
}

map(set_names(vars), convert_tib, tib = mytib)

请注意,上面的映射是在命名向量上进行的 - 这是为了给出一个命名列表作为输出,因为 ATEnocov() 函数 return 的调用在以这种方式执行时是相当无用的。这给出:

$a
$call
ATEnocov(Y = d[[1]], Z = d[[2]])

$Y
[1] 1 2 3 4 5

$Z
[1] 0 1 0 0 1

$match
NULL

$ATE.est
[1] 0.8333333

$ATE.var
[1] 3.027778

attr(,"class")
[1] "ATEnocov"

$b
$call
ATEnocov(Y = d[[1]], Z = d[[2]])

$Y
[1]  6  7  8  9 10

$Z
[1] 0 1 0 1 0

$match
NULL

$ATE.est
[1] 0

$ATE.var
[1] 2.333333

attr(,"class")
[1] "ATEnocov"

如果您希望它以更好的方式 return 调用,您可以改用:

convert_tib <- function(tib, var) {
  tib %>% 
    transmute(across(c(all_of(var), c), as.integer)) %>%
    filter(!is.na(.data[[var]])) %>%
    {
      do.call("ATEnocov", list(as.name(var), as.name("c"), data = quote(.)))
    }
}

return调用为:

$a
$call
ATEnocov(Y = a, Z = c, data = .)

...

或类似地使用rlang:

convert_tib <- function(tib, var) {
  tib %>% 
    transmute(across(c(all_of(var), c), as.integer)) %>%
    filter(!is.na(.data[[var]])) %>%
    {
      rlang::inject(ATEnocov(!!sym(var), c, data = .))
    }
}