如何撤消 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 = .))
}
}
所以,我问这个是作为 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 = .))
}
}