I am trying to use expand.model.frame()
within lapply()
after estimating models with both lm
and fixest::feols()
.
As it happens, I continuously run into errors for fixest::feols
, likely because I am confused about environments.
Here's a prototypical example:
library(fixest)
library(lfe)
library(estimatr)
fun <- function(object, clustid){
fml <- object$call$formula
if(!inherits(clustid, "formula")){
clustid <- reformulate(clustid)
}
expand.model.frame(
model = object,
extras = clustid,
#envir = environment(terms(object)),
#envir = .GlobalEnv,
na.expand = FALSE
)
}
data(mtcars)
tmp_lm <- lapply(list(mtcars, mtcars), function(x){lm(mpg ~ qsec ,data = x)})
lapply(tmp_lm, function(x) fun(x, clustid = "carb"))
tmp_feols <- lapply(list(mtcars, mtcars), function(x){feols(mpg ~ qsec ,data = x)})
lapply(tmp_feols, function(x) fun(x, clustid = ~carb))
# Error in eval(model$call$data, envir) : object 'x' not found
tmp_felm <- lapply(list(mtcars, mtcars), function(x){felm(mpg ~ qsec ,data = x)})
lapply(tmp_felm, function(x) fun(x, clustid = ~carb))
tmp_estimatr <- lapply(list(mtcars, mtcars), function(x){lm_robust(mpg ~ qsec ,data = x)})
lapply(tmp_estimatr, function(x) fun(x, clustid = ~carb))
Does anyone have a suggestion how I would have to tweak fun()
so that I would no longer run into the error below?
CodePudding user response:
I can see from your commented code that you have been experimenting with the envir
argument. You are on the right track here. The "fixest" class contains an object called call_env
to ensure you can access the correct evaluating environment. That means you need to alter your code to get the correct calling environment according to the type of object passed:
fun <- function(object, clustid){
if(!inherits(clustid, "formula")){
clustid <- reformulate(clustid)
}
e <- if(class(object) == "fixest")
object$call_env else environment(formula(object))
expand.model.frame(
model = object,
extras = clustid,
envir = e,
na.expand = FALSE
)
}
This allows:
data(mtcars)
tmp_feols <- lapply(list(mtcars, mtcars), function(x){feols(mpg ~ qsec ,data = x)})
lapply(tmp_feols, function(x) fun(x, clustid = ~carb))
#> [[1]]
#> mpg qsec carb
#> Mazda RX4 21.0 16.46 4
#> Mazda RX4 Wag 21.0 17.02 4
#> Datsun 710 22.8 18.61 1
#> Hornet 4 Drive 21.4 19.44 1
#> Hornet Sportabout 18.7 17.02 2
#> Valiant 18.1 20.22 1
#> Duster 360 14.3 15.84 4
#> Merc 240D 24.4 20.00 2
#> Merc 230 22.8 22.90 2
#> Merc 280 19.2 18.30 4
#> Merc 280C 17.8 18.90 4
#> Merc 450SE 16.4 17.40 3
#> Merc 450SL 17.3 17.60 3
#> Merc 450SLC 15.2 18.00 3
#> Cadillac Fleetwood 10.4 17.98 4
#> Lincoln Continental 10.4 17.82 4
#> Chrysler Imperial 14.7 17.42 4
#> Fiat 128 32.4 19.47 1
#> Honda Civic 30.4 18.52 2
#> Toyota Corolla 33.9 19.90 1
#> Toyota Corona 21.5 20.01 1
#> Dodge Challenger 15.5 16.87 2
#> AMC Javelin 15.2 17.30 2
#> Camaro Z28 13.3 15.41 4
#> Pontiac Firebird 19.2 17.05 2
#> Fiat X1-9 27.3 18.90 1
#> Porsche 914-2 26.0 16.70 2
#> Lotus Europa 30.4 16.90 2
#> Ford Pantera L 15.8 14.50 4
#> Ferrari Dino 19.7 15.50 6
#> Maserati Bora 15.0 14.60 8
#> Volvo 142E 21.4 18.60 2
#>
#> [[2]]
#> mpg qsec carb
#> Mazda RX4 21.0 16.46 4
#> Mazda RX4 Wag 21.0 17.02 4
#> Datsun 710 22.8 18.61 1
#> Hornet 4 Drive 21.4 19.44 1
#> Hornet Sportabout 18.7 17.02 2
#> Valiant 18.1 20.22 1
#> Duster 360 14.3 15.84 4
#> Merc 240D 24.4 20.00 2
#> Merc 230 22.8 22.90 2
#> Merc 280 19.2 18.30 4
#> Merc 280C 17.8 18.90 4
#> Merc 450SE 16.4 17.40 3
#> Merc 450SL 17.3 17.60 3
#> Merc 450SLC 15.2 18.00 3
#> Cadillac Fleetwood 10.4 17.98 4
#> Lincoln Continental 10.4 17.82 4
#> Chrysler Imperial 14.7 17.42 4
#> Fiat 128 32.4 19.47 1
#> Honda Civic 30.4 18.52 2
#> Toyota Corolla 33.9 19.90 1
#> Toyota Corona 21.5 20.01 1
#> Dodge Challenger 15.5 16.87 2
#> AMC Javelin 15.2 17.30 2
#> Camaro Z28 13.3 15.41 4
#> Pontiac Firebird 19.2 17.05 2
#> Fiat X1-9 27.3 18.90 1
#> Porsche 914-2 26.0 16.70 2
#> Lotus Europa 30.4 16.90 2
#> Ford Pantera L 15.8 14.50 4
#> Ferrari Dino 19.7 15.50 6
#> Maserati Bora 15.0 14.60 8
#> Volvo 142E 21.4 18.60 2
But will still work on the lm
version.
Of course, a more sophisticated way to do this would be to create a new generic function that dispatches according to class, rather than handling classes inside one big function.
Created on 2022-05-28 by the reprex package (v2.0.1)