context("fixest") skip_on_cran() skip_if_not_installed("modeltests") library(modeltests) skip_if_not_installed("fixest") fixest::setFixest_nthreads(1) # avoid warnings about requesting more threads set.seed(27) n <- 100 df <- data.frame( id = sample(5, n, TRUE), v1 = sample(5, n, TRUE), v2 = sample(1e6, n, TRUE), v3 = sample(round(runif(100, max = 100), 4), n, TRUE), v4 = sample(round(runif(100, max = 100), 4), n, TRUE) ) fit <- fixest::feols(v2 ~ v3, df) fit2 <- fixest::feols(v2 ~ v3 | id + v1, df) form <- v2 ~ v4 fit_form <- fixest::feols(form, df) # part of a regression test test_that("fixest tidier arguments", { check_arguments(tidy.fixest) check_arguments(glance.fixest) check_arguments(augment.fixest) }) test_that("bug #1018: fixed effects but no regressors", { mod <- fixest::feols(Sepal.Length ~ 1 | Species, data = iris) check_tidy_output(tidy(mod)) check_glance_outputs(glance(mod)) }) test_that("tidy.fixest", { td <- tidy(fit) td2 <- tidy(fit2, conf.int = TRUE) td3 <- tidy(fit2, conf.int = TRUE, se = "hetero") td4 <- tidy(fit_form) check_tidy_output(td) check_tidy_output(td2) check_tidy_output(td3) check_tidy_output(td4) check_dims(td, 2, 5) }) test_that("glance.fixest", { gl <- glance(fit) gl2 <- glance(fit2) check_glance_outputs(gl, gl2) check_dims(gl, expected_cols = 9) }) test_that("augment.fixest", { check_augment_function( aug = augment.fixest, model = fit, data = df, newdata = df, strict = FALSE ) check_augment_function( aug = augment.fixest, model = fit2, data = df, newdata = df, strict = FALSE ) check_augment_function( aug = augment.fixest, model = fit_form, data = df, newdata = df, strict = FALSE ) }) test_that("all other fixest estimators run", { skip_on_cran() skip_on_ci() form <- v2 ~ v4 | id res_feglm <- fixest::feglm(form, data = df, family = "poisson") res_fenegbin <- fixest::fenegbin(form, data = df) res_feNmlm <- fixest::feNmlm(form, data = df) res_femlm <- fixest::femlm(form, data = df) res_fepois <- fixest::fepois(form, data = df) # Tidy check_tidy_output(tidy(res_feglm)) check_tidy_output(tidy(res_fenegbin)) check_tidy_output(tidy(res_feNmlm)) check_tidy_output(tidy(res_femlm)) check_tidy_output(tidy(res_fepois)) # Glance check_glance_outputs( glance(res_feglm), glance(res_fenegbin), glance(res_feNmlm), glance(res_femlm), glance(res_fepois) ) # augment # Note this this causes warnings with strict=TRUE because # modeltests:::acceptable_augment_colnames calls model.frame, which doesn't # work for fixest models. check_augment_function( aug = augment.fixest, model = res_feglm, data = df, newdata = df, strict = FALSE ) check_augment_function( aug = augment.fixest, model = res_femlm, data = df, newdata = df, strict = FALSE ) augment_error <- "augment is only supported for fixest models estimated with feols, feglm, or femlm" expect_error(augment(res_fenegbin, df), augment_error) expect_error(augment(res_feNmlm, df), augment_error) expect_error(augment(res_fepois, df), augment_error) }) test_that("tidiers work with model results or summary of model results", { skip_on_cran() skip_on_ci() # Default standard errors are clustered by `id`. Test against non-default # independent, heteroskedastic ("hetero") standard errors. fit2_summ <- summary(fit2, se = "hetero") expect_equal(tidy(fit2, se = "hetero"), tidy(fit2_summ)) expect_equal( tidy(fit2, se = "hetero", conf.int = TRUE), tidy(fit2_summ, conf.int = TRUE) ) expect_equal(glance(fit2, se = "hetero"), glance(fit2_summ)) expect_equal(augment(fit2, df, se = "hetero"), augment(fit2_summ, df)) # Repeat for feglm res_glm <- fixest::feglm(v2 ~ v4 | id, data = df, family = "poisson") res_glm_summ <- summary(fixest::feglm(v2 ~ v4 | id, data = df, family = "poisson"), se = "hetero") expect_equal(tidy(res_glm, se = "hetero"), tidy(res_glm_summ)) expect_equal( as.data.frame(tidy(res_glm, se = "hetero", conf.int = TRUE)), as.data.frame(tidy(res_glm_summ, conf.int = TRUE)) ) expect_equal(glance(res_glm, se = "hetero"), glance(res_glm_summ)) expect_equal(augment(res_glm, df, se = "hetero"), augment(res_glm_summ, df)) # We rely on behavior from fixest where summary.fixest() doesn't change the # `se` or `dof` arguments if they've already been set. # Test that claim here. (Calling summary again does change other things, like # the `summary_from_fit` flag, so we can't just expect_equal the whole object) expect_false(is.null(fit2_summ$coeftable)) expect_equal(fit2_summ$coeftable, summary(fit2_summ)$coeftable) expect_equal(summary(fit)$coeftable, summary(summary(fit))$coeftable) })