R telling me vectors are not vectors when I map function that includes grf::causal_forest()

Viewed 82

I want to pass a vector of column names to purrr::map() and iteratively pass them to the grf::causal_forest() function. In attempting this, i get an error that the values i'm passing to causal_forest() are not vectors (which is required) even though they definitely are.

For example, say I have this df

n <- 500
p <- 5
X <- matrix(rnorm(n * p), n, p)
W <- rbinom(n, 1, 0.5)
Y1 <- pmax(X[, 1], 0) * W + X[, 2] + pmin(X[, 3], 0) + rnorm(n)
Y2 <- pmax(X[, 1], 0) * W + X[, 2] + pmin(X[, 3], 0) + rnorm(n)
Y3 <- pmax(X[, 1], 0) * W + X[, 2] + pmin(X[, 3], 0) + rnorm(n)
df <- data.frame(Y1, Y2, Y3, W, X)

head(df)

          Y1           Y2          Y3 W           X1         X2          X3          X4          X5
1  0.5457143  1.933581483  2.38474639 1 -0.788463384  0.9146194  0.73684926 -0.51268651 -0.53317046
2  0.9640213 -1.098133573  1.15639726 1  0.008873619  1.1513535 -1.09108874  0.10308198  1.46560149
3  0.8839862  0.005357524  1.26430215 1  1.588380125 -0.9261196  0.35219255  0.81017210 -1.86847771
4  0.1424579 -0.783984941 -0.01038922 0  2.391068797  0.3080699 -0.94651780  1.92707015  0.42646239
5  0.1771250  0.484711614 -1.95481918 1  0.058835623  0.2541232 -0.05696465  0.01781394 -0.07254417
6 -1.8144585 -1.972902090 -1.47101855 1 -0.518724916 -1.1474859  0.94850272  0.80635703  0.72156403

Where Y* are the dependent variables, X* is the covariate matrix, and W is a binary treatment indicator. I can estimate the model with just a single value of Y* like so

library(grf)

c_forest <- causal_forest(
  X = X, 
  Y = df$Y1, 
  W = df$W)

ate_c_forest <- average_treatment_effect(
  c_forest, 
  target.sample = "overlap")

ate_c_forest

  estimate    std.err 
0.12262543 0.09578717 

But I want to iterate over each value of Y1, Y2, and Y3 using map(), then extract the estimate and std.err for the output of each call to average_treatment_effect(), and put these inside a tibble. So I wrote this small function

Y_n <- c("Y1", "Y2", "Y3")
names(Y_n) <- Y_n

grf_fcn <- function(.x){
  Y <- df$.x
  W <- df$W
  
  c_forest <- causal_forest(
    X = X,
    W = W,
    Y = Y)
  
  ate_c_forest <- average_treatment_effect(
    c_forest, 
    target.sample = "overlap")
}

## call function
library(purrr)

grf_results <- purrr::map(
  .x = tidyselect::all_of(Y_n),
  .f = grf_fcn)

However, when I attempt to call the function it returns the error "Error in validate_observations(Y, X) : Observations (W, Y, Z or D) must be vectors." I find this curious as Y* and W are vectors. E.g.

> is.vector(df$Y1)
[1] TRUE
> is.vector(df$W)
[1] TRUE

Can anyone see where i'm going wrong here? Or is this a bug of some kind?

1 Answers

To better understand where's the problem in your function, compare the output of the two following calls to map.

This one is the one you are using, it will return NULL:

purrr::map(tidyselect::all_of(Y_n), function(x) { df$x })

This one uses bracket notation, it will return the expected values:

purrr::map(tidyselect::all_of(Y_n), function(x) { df[[x]] })

This is a quirk of map and honestly I'm not quite sure what's going on under the hood, but at least we know how to modify your function to get your desired results:

grf_fcn <- function(x){
  Y <- df[[x]]
  W <- df$W
  
  c_forest <- causal_forest(
    X = X,
    W = W,
    Y = Y)
  
  ate_c_forest <- average_treatment_effect(
    c_forest, 
    target.sample = "overlap")
}
Related