So, I'm asking this as a follow-up to another question, to the solution to which I thought would fix all of my problems. It seems like that's not the case. Take the following setup
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")
Taking the function Ritchie Sacramento created in the other post
convert_tib <- function(tib, var) {
tib %>%
transmute(across(c(var, c), as.integer)) %>%
filter(!is.na(.data[[var]]))
}
I would like to add another function call within that function. The idea is that I first transform and filter my variables (code above) and then I feed it into this function experiment::ATEnocov(Y = a, Z = c, data = tib)
to obtain the average treatment effect for the transformed and filtered data. I'd then like to run the whole function with purrr:map
across a bunch of variables.
Unfortunately, adding this function call at the end of the convert_tib
function produces the error message Error in eval(call$Y, envir = data) : object 'a' not found
. Quite clearly this has to do with the environments in which ATEnocov
is called but I just can't figure out how to feed the variable into the function inside the same function.
CodePudding user response:
You don't really need to play around with NSE to get this to work, you can simply do:
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)
Notice that the above maps over a named vector - this is to give a named list as output because the ATEnocov()
function returns its call which when executed this way is rather uninformative. This gives:
$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"
If you want it to return the call in a nicer way you can instead use:
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(.)))
}
}
Which returns the call as:
$a
$call
ATEnocov(Y = a, Z = c, data = .)
...
Or similarly using 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 = .))
}
}