diff --git a/DESCRIPTION b/DESCRIPTION index 0270c266..5ddb3adf 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: broom.helpers Title: Helpers for Model Coefficients Tibbles -Version: 1.7.0.9003 +Version: 1.7.0.9004 Authors@R: c( person("Joseph", "Larmarange", , "joseph@larmarange.net", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-7097-700X")), @@ -37,6 +37,7 @@ Suggests: covr, datasets, emmeans, + fixest, forcats, gam, gee, diff --git a/NAMESPACE b/NAMESPACE index aef802e3..31d7f62c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,6 +11,7 @@ S3method(model_get_coefficients_type,clogit) S3method(model_get_coefficients_type,coxph) S3method(model_get_coefficients_type,crr) S3method(model_get_coefficients_type,default) +S3method(model_get_coefficients_type,fixest) S3method(model_get_coefficients_type,geeglm) S3method(model_get_coefficients_type,glm) S3method(model_get_coefficients_type,glmerMod) @@ -27,12 +28,14 @@ S3method(model_get_model,mira) S3method(model_get_model_frame,biglm) S3method(model_get_model_frame,coxph) S3method(model_get_model_frame,default) +S3method(model_get_model_frame,fixest) S3method(model_get_model_frame,model_fit) S3method(model_get_model_frame,survreg) S3method(model_get_model_matrix,biglm) S3method(model_get_model_matrix,brmsfit) S3method(model_get_model_matrix,clm) S3method(model_get_model_matrix,default) +S3method(model_get_model_matrix,fixest) S3method(model_get_model_matrix,glmmTMB) S3method(model_get_model_matrix,model_fit) S3method(model_get_model_matrix,multinom) @@ -58,7 +61,6 @@ S3method(model_get_terms,model_fit) S3method(model_get_weights,default) S3method(model_get_weights,model_fit) S3method(model_get_weights,svyglm) -S3method(model_get_xlevels,biglm) S3method(model_get_xlevels,brmsfit) S3method(model_get_xlevels,default) S3method(model_get_xlevels,felm) diff --git a/NEWS.md b/NEWS.md index 75130775..979b4f23 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,8 @@ - Support for `parsnip::model_fit` objects (#161) - Support for `biglm::bigglm()` and `biglmm::bigglm()` models (#155) +- Support for `fixest::feglm()`, `fixest::femlm()`, `fixest::feols()` + and `fixest::feNmlm()` (#167) **New features** diff --git a/R/model_get_coefficients_type.R b/R/model_get_coefficients_type.R index dced0770..a7d53c73 100644 --- a/R/model_get_coefficients_type.R +++ b/R/model_get_coefficients_type.R @@ -28,18 +28,20 @@ model_get_coefficients_type.default <- function(model) { #' @export #' @rdname model_get_coefficients_type model_get_coefficients_type.glm <- function(model) { - if (model$family$family == "binomial" && model$family$link == "logit") - return("logistic") - if (model$family$family == "binomial" && model$family$link == "log") - return("relative_risk") - if (model$family$family == "binomial" && model$family$link == "cloglog") - return("prop_hazard") - if (model$family$family == "poisson" && model$family$link == "log") - return("poisson") - if (model$family$family == "quasibinomial" && model$family$link == "logit") - return("logistic") - if (model$family$family == "quasipoisson" && model$family$link == "log") - return("poisson") + if (!is.null(model$family)) { + if (model$family$family == "binomial" && model$family$link == "logit") + return("logistic") + if (model$family$family == "binomial" && model$family$link == "log") + return("relative_risk") + if (model$family$family == "binomial" && model$family$link == "cloglog") + return("prop_hazard") + if (model$family$family == "poisson" && model$family$link == "log") + return("poisson") + if (model$family$family == "quasibinomial" && model$family$link == "logit") + return("logistic") + if (model$family$family == "quasipoisson" && model$family$link == "log") + return("poisson") + } "generic" } @@ -53,6 +55,9 @@ model_get_coefficients_type.negbin <- function(model) { #' @rdname model_get_coefficients_type model_get_coefficients_type.geeglm <- model_get_coefficients_type.glm +#' @export +#' @rdname model_get_coefficients_type +model_get_coefficients_type.fixest <- model_get_coefficients_type.glm #' @export #' @rdname model_get_coefficients_type diff --git a/R/model_get_model_frame.R b/R/model_get_model_frame.R index ab44045c..f16e9f3c 100644 --- a/R/model_get_model_frame.R +++ b/R/model_get_model_frame.R @@ -66,3 +66,9 @@ model_get_model_frame.biglm <- function(model) { model_get_model_frame.model_fit <- function(model) { model_get_model_frame(model$fit) } + +#' @export +#' @rdname model_get_model_frame +model_get_model_frame.fixest <- function(model) { + stats::model.frame.default(model$fml, data = get(model$call$data, model$call_env)) +} diff --git a/R/model_get_model_matrix.R b/R/model_get_model_matrix.R index 1d9b5d5f..88758e31 100644 --- a/R/model_get_model_matrix.R +++ b/R/model_get_model_matrix.R @@ -102,3 +102,8 @@ model_get_model_matrix.model_fit <- function(model, ...) { model_get_model_matrix(model$fit, ...) } +#' @export +#' @rdname model_get_model_matrix +model_get_model_matrix.fixest <- function(model) { + stats::model.matrix.default(model$fml, data = get(model$call$data, model$call_env)) +} diff --git a/R/model_get_xlevels.R b/R/model_get_xlevels.R index 7911ce47..2972600b 100644 --- a/R/model_get_xlevels.R +++ b/R/model_get_xlevels.R @@ -19,6 +19,17 @@ model_get_xlevels.default <- function(model) { NULL # nocov } ) + if (is.null(xlevels)) { + xlevels <- tryCatch( + stats::.getXlevels( + stats::terms(model), + model %>% model_get_model_frame() + ), + error = function(e) { + NULL # nocov + } + ) + } xlevels %>% .add_xlevels_for_logical_variables(model) } @@ -64,17 +75,9 @@ model_get_xlevels.glmmTMB <- model_get_xlevels.lmerMod #' @rdname model_get_xlevels model_get_xlevels.plm <- model_get_xlevels.lmerMod -#' @export -#' @rdname model_get_xlevels -model_get_xlevels.biglm <- function(model) { - stats::.getXlevels( - stats::terms(model), - model %>% model_get_model_frame() - ) -} - #' @export #' @rdname model_get_xlevels model_get_xlevels.model_fit <- function(model) { model_get_xlevels(model$fit) } + diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R index d40189fa..c4f10201 100644 --- a/data-raw/DATASET.R +++ b/data-raw/DATASET.R @@ -35,6 +35,10 @@ supported_models <- '`biglm::bigglm()`','', '`biglmm::bigglm()`','', '`parsnip::model_fit`', 'Supported as long as the type of model and the engine is supported.', + '`fixest::feglm()`','', + '`fixest::femlm()`','', + '`fixest::feols()`','', + '`fixest::feNmlm()`','', ) %>% dplyr::arrange(.data$model) diff --git a/data/supported_models.rda b/data/supported_models.rda index 40a0a325..73f4647e 100644 Binary files a/data/supported_models.rda and b/data/supported_models.rda differ diff --git a/man/model_get_coefficients_type.Rd b/man/model_get_coefficients_type.Rd index 957385f2..04759f41 100644 --- a/man/model_get_coefficients_type.Rd +++ b/man/model_get_coefficients_type.Rd @@ -6,6 +6,7 @@ \alias{model_get_coefficients_type.glm} \alias{model_get_coefficients_type.negbin} \alias{model_get_coefficients_type.geeglm} +\alias{model_get_coefficients_type.fixest} \alias{model_get_coefficients_type.biglm} \alias{model_get_coefficients_type.glmerMod} \alias{model_get_coefficients_type.clogit} @@ -30,6 +31,8 @@ model_get_coefficients_type(model) \method{model_get_coefficients_type}{geeglm}(model) +\method{model_get_coefficients_type}{fixest}(model) + \method{model_get_coefficients_type}{biglm}(model) \method{model_get_coefficients_type}{glmerMod}(model) diff --git a/man/model_get_model_frame.Rd b/man/model_get_model_frame.Rd index cf05e830..d2bd16d5 100644 --- a/man/model_get_model_frame.Rd +++ b/man/model_get_model_frame.Rd @@ -7,6 +7,7 @@ \alias{model_get_model_frame.survreg} \alias{model_get_model_frame.biglm} \alias{model_get_model_frame.model_fit} +\alias{model_get_model_frame.fixest} \title{Get the model frame of a model} \usage{ model_get_model_frame(model) @@ -20,6 +21,8 @@ model_get_model_frame(model) \method{model_get_model_frame}{biglm}(model) \method{model_get_model_frame}{model_fit}(model) + +\method{model_get_model_frame}{fixest}(model) } \arguments{ \item{model}{a model object} diff --git a/man/model_get_model_matrix.Rd b/man/model_get_model_matrix.Rd index b3dec2b5..64ca30cf 100644 --- a/man/model_get_model_matrix.Rd +++ b/man/model_get_model_matrix.Rd @@ -10,6 +10,7 @@ \alias{model_get_model_matrix.plm} \alias{model_get_model_matrix.biglm} \alias{model_get_model_matrix.model_fit} +\alias{model_get_model_matrix.fixest} \title{Get the model matrix of a model} \usage{ model_get_model_matrix(model, ...) @@ -29,6 +30,8 @@ model_get_model_matrix(model, ...) \method{model_get_model_matrix}{biglm}(model, ...) \method{model_get_model_matrix}{model_fit}(model, ...) + +\method{model_get_model_matrix}{fixest}(model) } \arguments{ \item{model}{a model object} diff --git a/man/model_get_xlevels.Rd b/man/model_get_xlevels.Rd index c56c7f55..253ec236 100644 --- a/man/model_get_xlevels.Rd +++ b/man/model_get_xlevels.Rd @@ -9,7 +9,6 @@ \alias{model_get_xlevels.brmsfit} \alias{model_get_xlevels.glmmTMB} \alias{model_get_xlevels.plm} -\alias{model_get_xlevels.biglm} \alias{model_get_xlevels.model_fit} \title{Get xlevels used in the model} \usage{ @@ -29,8 +28,6 @@ model_get_xlevels(model) \method{model_get_xlevels}{plm}(model) -\method{model_get_xlevels}{biglm}(model) - \method{model_get_xlevels}{model_fit}(model) } \arguments{ diff --git a/man/supported_models.Rd b/man/supported_models.Rd index 202cab6d..71a3865f 100644 --- a/man/supported_models.Rd +++ b/man/supported_models.Rd @@ -20,37 +20,44 @@ Listing of Supported Models \section{Supported models}{ \tabular{ll}{ model \tab notes \cr - \code{stats::lm()} \tab \cr - \code{stats::glm()} \tab \cr - \code{stats::aov()} \tab Reference rows are not relevant for such models. \cr - \code{ordinal::clm()} \tab Limited support for models with nominal predictors. \cr - \code{ordinal::clmm()} \tab Limited support for models with nominal predictors. \cr - \code{survival::coxph()} \tab \cr - \code{survival::survreg()} \tab \cr - \code{survival::clogit()} \tab \cr - \code{lme4::lmer()} \tab \code{broom.mixed} package required \cr - \code{lme4::glmer()} \tab \code{broom.mixed} package required \cr - \code{lme4::glmer.nb()} \tab \code{broom.mixed} package required \cr + \code{biglm::bigglm()} \tab \cr + \code{biglmm::bigglm()} \tab \cr \code{brms::brm()} \tab \code{broom.mixed} package required \cr - \code{geepack::geeglm()} \tab \cr + \code{cmprsk::crr()} \tab Limited support. It is recommended to use \code{tidycmprsk::crr()} instead. \cr + \code{fixest::feglm()} \tab \cr + \code{fixest::femlm()} \tab \cr + \code{fixest::feNmlm()} \tab \cr + \code{fixest::feols()} \tab \cr \code{gam::gam()} \tab \cr + \code{geepack::geeglm()} \tab \cr \code{glmmTMB::glmmTMB()} \tab \code{broom.mixed} package required \cr + \code{lavaan::lavaan()} \tab Limited support for categorical variables \cr + \code{lfe::felm()} \tab \cr + \code{lme4::glmer()} \tab \code{broom.mixed} package required \cr + \code{lme4::glmer.nb()} \tab \code{broom.mixed} package required \cr + \code{lme4::lmer()} \tab \code{broom.mixed} package required \cr + \code{MASS::glm.nb()} \tab \cr + \code{MASS::polr()} \tab \cr \code{mgcv::gam()} \tab Use default tidier \code{broom::tidy()} for smooth terms only, or \code{gtsummary::tidy_gam()} to include parametric terms \cr + \code{mice::mira} \tab Limited support. If \code{mod} is a \code{mira} object, use \code{tidy_plus_plus(mod, tidy_fun = function(x, ...) mice::pool(x) \%>\% mice::tidy(...))} \cr \code{nnet::multinom()} \tab \cr - \code{survey::svyglm()} \tab \cr + \code{ordinal::clm()} \tab Limited support for models with nominal predictors. \cr + \code{ordinal::clmm()} \tab Limited support for models with nominal predictors. \cr + \code{parsnip::model_fit} \tab Supported as long as the type of model and the engine is supported. \cr + \code{plm::plm()} \tab \cr + \code{rstanarm::stan_glm()} \tab \code{broom.mixed} package required \cr + \code{stats::aov()} \tab Reference rows are not relevant for such models. \cr + \code{stats::glm()} \tab \cr + \code{stats::lm()} \tab \cr + \code{stats::nls()} \tab Limited support \cr \code{survey::svycoxph()} \tab \cr + \code{survey::svyglm()} \tab \cr \code{survey::svyolr()} \tab \cr - \code{MASS::polr()} \tab \cr - \code{MASS::glm.nb()} \tab \cr - \code{mice::mira} \tab Limited support. If \code{mod} is a \code{mira} object, use \code{tidy_plus_plus(mod, tidy_fun = function(x, ...) mice::pool(x) \%>\% mice::tidy(...))} \cr - \code{lavaan::lavaan()} \tab Limited support for categorical variables \cr - \code{stats::nls()} \tab Limited support \cr - \code{lfe::felm()} \tab \cr - \code{rstanarm::stan_glm()} \tab \code{broom.mixed} package required \cr - \code{VGAM::vglm()} \tab Limited support. It is recommended to use \code{tidy_parameters()} as \code{tidy_fun}. \cr - \code{cmprsk::crr()} \tab Limited support. It is recommended to use \code{tidycmprsk::crr()} instead. \cr + \code{survival::clogit()} \tab \cr + \code{survival::coxph()} \tab \cr + \code{survival::survreg()} \tab \cr \code{tidycmprsk::crr()} \tab \cr - \code{plm::plm()} \tab \cr + \code{VGAM::vglm()} \tab Limited support. It is recommended to use \code{tidy_parameters()} as \code{tidy_fun}. \cr } } diff --git a/tests/testthat/test-tidy_plus_plus.R b/tests/testthat/test-tidy_plus_plus.R index b5602dff..b196732d 100644 --- a/tests/testthat/test-tidy_plus_plus.R +++ b/tests/testthat/test-tidy_plus_plus.R @@ -636,3 +636,20 @@ test_that("tidy_plus_plus() works with parsnip::model_fit object", { ) expect_equivalent(res1, res2) }) + +test_that("tidy_plus_plus() works with fixest models", { + skip_on_cran() + skip_if_not_installed("fixest") + + mod <- fixest::feols(fml = mpg ~ am + factor(carb), data = mtcars) + expect_error( + res <- mod %>% tidy_plus_plus(), + NA + ) + + mod <- fixest::feglm(Sepal.Length ~ Sepal.Width + Petal.Length | Species, iris, "poisson") + expect_error( + res <- mod %>% tidy_plus_plus(), + NA + ) +})