diff --git a/DESCRIPTION b/DESCRIPTION index 43a45c612..c0955a9e0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: parameters Title: Processing of Model Parameters -Version: 0.22.1.4 +Version: 0.22.1.6 Authors@R: c(person(given = "Daniel", family = "Lüdecke", diff --git a/NAMESPACE b/NAMESPACE index 1bfa0c66b..0b725c334 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -118,62 +118,6 @@ S3method(convert_efa_to_cfa,fa) S3method(convert_efa_to_cfa,fa.ci) S3method(convert_efa_to_cfa,parameters_efa) S3method(convert_efa_to_cfa,parameters_pca) -S3method(degrees_of_freedom,BBmm) -S3method(degrees_of_freedom,BBreg) -S3method(degrees_of_freedom,betamfx) -S3method(degrees_of_freedom,betaor) -S3method(degrees_of_freedom,bfsl) -S3method(degrees_of_freedom,bigglm) -S3method(degrees_of_freedom,biglm) -S3method(degrees_of_freedom,cgam) -S3method(degrees_of_freedom,cgamm) -S3method(degrees_of_freedom,coeftest) -S3method(degrees_of_freedom,complmrob) -S3method(degrees_of_freedom,default) -S3method(degrees_of_freedom,emmGrid) -S3method(degrees_of_freedom,emm_list) -S3method(degrees_of_freedom,fixest) -S3method(degrees_of_freedom,fixest_multi) -S3method(degrees_of_freedom,garch) -S3method(degrees_of_freedom,glht) -S3method(degrees_of_freedom,gls) -S3method(degrees_of_freedom,hglm) -S3method(degrees_of_freedom,ivFixed) -S3method(degrees_of_freedom,ivprobit) -S3method(degrees_of_freedom,logitmfx) -S3method(degrees_of_freedom,logitor) -S3method(degrees_of_freedom,lqm) -S3method(degrees_of_freedom,lqmm) -S3method(degrees_of_freedom,mediate) -S3method(degrees_of_freedom,merModList) -S3method(degrees_of_freedom,mhurdle) -S3method(degrees_of_freedom,mipo) -S3method(degrees_of_freedom,mira) -S3method(degrees_of_freedom,mmrm) -S3method(degrees_of_freedom,mmrm_fit) -S3method(degrees_of_freedom,mmrm_tmb) -S3method(degrees_of_freedom,model_fit) -S3method(degrees_of_freedom,multinom) -S3method(degrees_of_freedom,negbinirr) -S3method(degrees_of_freedom,negbinmfx) -S3method(degrees_of_freedom,nestedLogit) -S3method(degrees_of_freedom,nlrq) -S3method(degrees_of_freedom,nnet) -S3method(degrees_of_freedom,plm) -S3method(degrees_of_freedom,poissonirr) -S3method(degrees_of_freedom,poissonmfx) -S3method(degrees_of_freedom,probitmfx) -S3method(degrees_of_freedom,rlm) -S3method(degrees_of_freedom,rq) -S3method(degrees_of_freedom,rqs) -S3method(degrees_of_freedom,rqss) -S3method(degrees_of_freedom,selection) -S3method(degrees_of_freedom,serp) -S3method(degrees_of_freedom,summary.lm) -S3method(degrees_of_freedom,svy2lme) -S3method(degrees_of_freedom,systemfit) -S3method(degrees_of_freedom,truncreg) -S3method(degrees_of_freedom,vgam) S3method(display,compare_parameters) S3method(display,equivalence_test_lm) S3method(display,parameters_brms_meta) diff --git a/NEWS.md b/NEWS.md index edbe49a36..fa9695350 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,10 @@ +# parameters 0.22.2 + +## Changes + +* Methods for `degrees_of_freedom()` have been removed. `degrees_of_freedom()` + now calls `insight::get_df()`. + # parameters 0.22.1 ## Breaking changes diff --git a/R/compare_parameters.R b/R/compare_parameters.R index 05305e244..2f03e4576 100644 --- a/R/compare_parameters.R +++ b/R/compare_parameters.R @@ -310,3 +310,19 @@ compare_models <- compare_parameters x } + + +.is_bayesian_model <- function(x, exclude = NULL) { + bayes_classes <- c( + "brmsfit", "stanfit", "MCMCglmm", "stanreg", + "stanmvreg", "bmerMod", "BFBayesFactor", "bamlss", + "bayesx", "mcmc", "bcplm", "bayesQR", "BGGM", + "meta_random", "meta_fixed", "meta_bma", "blavaan", + "blrm", "blmerMod" + ) + # if exclude is not NULL, remove elements in exclude from bayes_class + if (!is.null(exclude)) { + bayes_classes <- bayes_classes[!bayes_classes %in% exclude] + } + inherits(x, bayes_classes) +} diff --git a/R/dof.R b/R/dof.R index f0848eb2c..fb777adde 100644 --- a/R/dof.R +++ b/R/dof.R @@ -3,39 +3,32 @@ #' Estimate or extract degrees of freedom of models parameters. #' #' @param model A statistical model. -#' @param method Can be `"analytical"` (default, DoFs are estimated based -#' on the model type), `"residual"` in which case they are directly taken -#' from the model if available (for Bayesian models, the goal (looking for -#' help to make it happen) would be to refit the model as a frequentist one -#' before extracting the DoFs), `"ml1"` (see [dof_ml1()]), `"betwithin"` -#' (see [dof_betwithin()]), `"satterthwaite"` (see [`dof_satterthwaite()`]), -#' `"kenward"` (see [`dof_kenward()`]) or `"any"`, which tries to extract DoF -#' by any of those methods, whichever succeeds. See 'Details'. -#' @param ... Currently not used. -#' -#' @details -#' Methods for calculating degrees of freedom: +#' @param method Type of approximation for the degrees of freedom. Can be one of +#' the following: #' -#' - `"analytical"` for models of class `lmerMod`, Kenward-Roger approximated -#' degrees of freedoms are calculated, for other models, `n-k` (number of -#' observations minus number of parameters). -#' - `"residual"` tries to extract residual degrees of freedom, and returns -#' `Inf` if residual degrees of freedom could not be extracted. -#' - `"any"` first tries to extract residual degrees of freedom, and if these -#' are not available, extracts analytical degrees of freedom. -#' - `"nokr"` same as `"analytical"`, but does not Kenward-Roger approximation -#' for models of class `lmerMod`. Instead, always uses `n-k` to calculate df -#' for any model. -#' - `"normal"` returns `Inf`. -#' - `"wald"` returns residual df for models with t-statistic, and `Inf` for all other models. -#' - `"kenward"` calls [`dof_kenward()`]. -#' - `"satterthwaite"` calls [`dof_satterthwaite()`]. -#' - `"ml1"` calls [`dof_ml1()`]. -#' - `"betwithin"` calls [`dof_betwithin()`]. +#' + `"residual"` (aka `"analytical"`) returns the residual degrees of +#' freedom, which usually is what [`stats::df.residual()`] returns. If a +#' model object has no method to extract residual degrees of freedom, these +#' are calculated as `n-p`, i.e. the number of observations minus the number +#' of estimated parameters. If residual degrees of freedom cannot be extracted +#' by either approach, returns `Inf`. +#' + `"wald"` returns residual (aka analytical) degrees of freedom for models +#' with t-statistic, `1` for models with Chi-squared statistic, and `Inf` for +#' all other models. Also returns `Inf` if residual degrees of freedom cannot +#' be extracted. +#' + `"normal"` always returns `Inf`. +#' + `"model"` returns model-based degrees of freedom, i.e. the number of +#' (estimated) parameters. +#' + For mixed models, can also be `"ml1"` (or `"m-l-1"`, approximation of +#' degrees of freedom based on a "m-l-1" heuristic as suggested by _Elff et +#' al. 2019_) or `"between-within"` (or `"betwithin"`). +#' + For mixed models of class `merMod`, `type` can also be `"satterthwaite"` +#' or `"kenward-roger"` (or `"kenward"`). See 'Details'. #' -#' For models with z-statistic, the returned degrees of freedom for model parameters -#' is `Inf` (unless `method = "ml1"` or `method = "betwithin"`), because there is -#' only one distribution for the related test statistic. +#' Usually, when degrees of freedom are required to calculate p-values or +#' confidence intervals, `type = "wald"` is likely to be the best choice in +#' most cases. +#' @param ... Currently not used. #' #' @note #' In many cases, `degrees_of_freedom()` returns the same as `df.residuals()`, @@ -47,17 +40,15 @@ #' `"satterthwaite"`, each model parameter can have a different degree of #' freedom. #' -#' @examples +#' @examplesIf require("lme4", quietly = TRUE) #' model <- lm(Sepal.Length ~ Petal.Length * Species, data = iris) #' dof(model) #' #' model <- glm(vs ~ mpg * cyl, data = mtcars, family = "binomial") #' dof(model) #' \donttest{ -#' if (require("lme4", quietly = TRUE)) { -#' model <- lmer(Sepal.Length ~ Petal.Length + (1 | Species), data = iris) -#' dof(model) -#' } +#' model <- lmer(Sepal.Length ~ Petal.Length + (1 | Species), data = iris) +#' dof(model) #' #' if (require("rstanarm", quietly = TRUE)) { #' model <- stan_glm( @@ -70,84 +61,8 @@ #' } #' } #' @export -degrees_of_freedom <- function(model, ...) { - UseMethod("degrees_of_freedom") -} - - - - -#' @rdname degrees_of_freedom -#' @export -degrees_of_freedom.default <- function(model, method = "analytical", ...) { - # check for valid input - .is_model_valid(model) - - if (is.null(method)) { - method <- "wald" - } - method <- tolower(method) - - method <- match.arg(method, choices = c( - "analytical", "any", "fit", "ml1", "betwithin", "satterthwaite", "kenward", - "nokr", "wald", "kr", "profile", "boot", "uniroot", "residual", "normal", - "likelihood" - )) - - if (!.dof_method_ok(model, method, ...) || method %in% c("profile", "likelihood", "boot", "uniroot")) { - method <- "any" - } - - stat <- insight::find_statistic(model) - - # for z-statistic, always return Inf - if (!is.null(stat) && stat == "z-statistic" && !(method %in% c("ml1", "betwithin"))) { - if (method == "residual") { - return(.degrees_of_freedom_residual(model, verbose = FALSE)) - } else { - return(Inf) - } - } - - # Chi2-distributions usually have 1 df - if (!is.null(stat) && stat == "chi-squared statistic") { - if (method == "residual") { - return(.degrees_of_freedom_residual(model, verbose = FALSE)) - } else { - return(1) - } - } - - if (method == "any") { # nolint - dof <- .degrees_of_freedom_residual(model, verbose = FALSE) - if (is.null(dof) || all(is.infinite(dof)) || anyNA(dof)) { - dof <- .degrees_of_freedom_analytical(model, kenward = FALSE) - } - } else if (method == "ml1") { - dof <- dof_ml1(model) - } else if (method == "wald") { - dof <- .degrees_of_freedom_residual(model, verbose = FALSE) - } else if (method == "normal") { - dof <- Inf - } else if (method == "satterthwaite") { - dof <- dof_satterthwaite(model) - } else if (method == "betwithin") { - dof <- dof_betwithin(model) - } else if (method %in% c("kenward", "kr")) { - dof <- dof_kenward(model) - } else if (method == "analytical") { - dof <- .degrees_of_freedom_analytical(model, kenward = TRUE) - } else if (method == "nokr") { - dof <- .degrees_of_freedom_analytical(model, kenward = FALSE) - } else { - dof <- .degrees_of_freedom_residual(model) - } - - if (!is.null(dof) && length(dof) > 0 && all(dof == 0)) { - insight::format_warning("Model has zero degrees of freedom!") - } - - dof +degrees_of_freedom <- function(model, method = "analytical", ...) { + insight::get_df(x = model, type = method, ...) } #' @rdname degrees_of_freedom @@ -155,110 +70,6 @@ degrees_of_freedom.default <- function(model, method = "analytical", ...) { dof <- degrees_of_freedom - - - -# Analytical approach ------------------------------ - - -#' @keywords internal -.degrees_of_freedom_analytical <- function(model, kenward = TRUE) { - nparam <- n_parameters(model) - n <- insight::n_obs(model) - - if (is.null(n)) { - n <- Inf - } - - if (isTRUE(kenward) && inherits(model, "lmerMod")) { - dof <- as.numeric(dof_kenward(model)) - } else { - dof <- rep(n - nparam, nparam) - } - - dof -} - - - - - -# Model approach (Residual df) ------------------------------ - - -#' @keywords internal -.degrees_of_freedom_residual <- function(model, verbose = TRUE) { - if (.is_bayesian_model(model, exclude = c("bmerMod", "bayesx", "blmerMod", "bglmerMod"))) { - model <- bayestestR::bayesian_as_frequentist(model) - } - - # 1st try - dof <- try(stats::df.residual(model), silent = TRUE) - - # 2nd try - if (inherits(dof, "try-error") || is.null(dof) || all(is.na(dof))) { - junk <- utils::capture.output(dof = try(summary(model)$df[2], silent = TRUE)) - } - - # 3rd try, nlme - if (inherits(dof, "try-error") || is.null(dof) || all(is.na(dof))) { - dof <- try(unname(model$fixDF$X), silent = TRUE) - } - - # last try - if (inherits(dof, "try-error") || is.null(dof) || all(is.na(dof))) { - dof <- Inf - if (verbose) { - insight::format_alert("Could not extract degrees of freedom.") - } - } - - - # special cases - # if (inherits(model, "gam")) { - # dof <- .dof_fit_gam(model, dof) - # } - - dof -} - - - - -# residual df - for models with residual df, but no "df.residual()" method -------------- - - -#' @keywords internal -.degrees_of_freedom_no_dfresid_method <- function(model, method = NULL) { - if (identical(method, "normal")) { - return(Inf) - } else if (!is.null(method) && method %in% c("ml1", "satterthwaite", "betwithin")) { - degrees_of_freedom.default(model, method = method) - } else { - .degrees_of_freedom_analytical(model, kenward = FALSE) - } -} - - - - - - -# helper -------------- - -.dof_fit_gam <- function(model, dof) { - params <- insight::find_parameters(model) - if (!is.null(params$conditional)) { - dof <- rep(dof, length(params$conditional)) - } - if (!is.null(params$smooth_terms)) { - s <- summary(model) - dof <- c(dof, s$s.table[, "Ref.df"]) - } - dof -} - - # Helper, check args ------------------------------ .dof_method_ok <- function(model, method, type = "df_method", verbose = TRUE, ...) { @@ -329,23 +140,3 @@ dof <- degrees_of_freedom return(TRUE) } - - - - -# helper - -.is_bayesian_model <- function(x, exclude = NULL) { - bayes_classes <- c( - "brmsfit", "stanfit", "MCMCglmm", "stanreg", - "stanmvreg", "bmerMod", "BFBayesFactor", "bamlss", - "bayesx", "mcmc", "bcplm", "bayesQR", "BGGM", - "meta_random", "meta_fixed", "meta_bma", "blavaan", - "blrm", "blmerMod" - ) - # if exclude is not NULL, remove elements in exclude from bayes_class - if (!is.null(exclude)) { - bayes_classes <- bayes_classes[!bayes_classes %in% exclude] - } - inherits(x, bayes_classes) -} diff --git a/R/extract_parameters.R b/R/extract_parameters.R index 473036b2d..3696ec4de 100644 --- a/R/extract_parameters.R +++ b/R/extract_parameters.R @@ -318,7 +318,7 @@ sig <- .safe(suppressWarnings(insight::get_sigma(model, ci = NULL, verbose = FALSE))) attr(params, "sigma") <- as.numeric(sig) - resdf <- .safe(suppressWarnings(insight::get_df(model, type = "residual"))) + resdf <- .safe(suppressWarnings(insight::get_df(x = model, type = "residual"))) attr(params, "residual_df") <- as.numeric(resdf) } params diff --git a/R/methods_BBMM.R b/R/methods_BBMM.R index 912b16b0c..15ae03155 100644 --- a/R/methods_BBMM.R +++ b/R/methods_BBMM.R @@ -64,18 +64,3 @@ p_value.BBreg <- function(model, ...) { p = as.data.frame(summary(model)$coefficients)$p.value ) } - - - -#' @export -degrees_of_freedom.BBmm <- function(model, method = "residual", ...) { - if (method %in% c("residual", "wald")) { - return(model$df) - } else { - return(degrees_of_freedom.default(model = model, method = method, ...)) - } -} - - -#' @export -degrees_of_freedom.BBreg <- degrees_of_freedom.BBmm diff --git a/R/methods_bfsl.R b/R/methods_bfsl.R index 5297e0632..078946cd3 100644 --- a/R/methods_bfsl.R +++ b/R/methods_bfsl.R @@ -37,20 +37,3 @@ standard_error.bfsl <- function(model, ...) { ) insight::text_remove_backticks(params, verbose = FALSE) } - - - -#' @export -degrees_of_freedom.bfsl <- function(model, method = "residual", ...) { - if (is.null(method)) { - method <- "wald" - } - - method <- match.arg(tolower(method), choices = c("analytical", "any", "fit", "wald", "residual", "normal")) - - if (method %in% c("wald", "residual", "fit")) { - model$df.residual - } else { - degrees_of_freedom.default(model, method = method, ...) - } -} diff --git a/R/methods_biglm.R b/R/methods_biglm.R index 56454116a..ddb9e47a1 100644 --- a/R/methods_biglm.R +++ b/R/methods_biglm.R @@ -8,12 +8,3 @@ standard_error.biglm <- function(model, ...) { SE = as.vector(cs[, 4]) ) } - - -#' @export -degrees_of_freedom.biglm <- function(model, method = NULL, ...) { - .degrees_of_freedom_no_dfresid_method(model, method) -} - -#' @export -degrees_of_freedom.bigglm <- degrees_of_freedom.biglm diff --git a/R/methods_brglm2.R b/R/methods_brglm2.R index 2b9eb4ca9..e4f0bc983 100644 --- a/R/methods_brglm2.R +++ b/R/methods_brglm2.R @@ -181,19 +181,6 @@ ci.multinom <- function(x, ci = 0.95, method = "normal", verbose = TRUE, ...) { } -#' @export -degrees_of_freedom.multinom <- function(model, method = NULL, ...) { - if (is.null(method) || identical(method, "normal")) { - Inf - } else { - insight::n_obs(model) - model$edf - } -} - -#' @export -degrees_of_freedom.nnet <- degrees_of_freedom.multinom - - #' @export standard_error.multinom <- function(model, ...) { se <- tryCatch( diff --git a/R/methods_cgam.R b/R/methods_cgam.R index a70416cd2..0204efa0f 100644 --- a/R/methods_cgam.R +++ b/R/methods_cgam.R @@ -166,38 +166,3 @@ standard_error.cgam <- function(model, ...) { Component = params$Component ) } - - -#' @export -degrees_of_freedom.cgam <- function(model, method = "wald", ...) { - if (is.null(method)) { - method <- "wald" - } - method <- match.arg(tolower(method), choices = c("analytical", "any", "fit", "wald", "residual", "normal")) - - if (method %in% c("wald", "residual", "fit")) { - stats::df.residual(model) - } else { - degrees_of_freedom.default(model, method = method, ...) - } -} - - -#' @export -degrees_of_freedom.cgamm <- function(model, method = "wald", ...) { - if (is.null(method)) { - method <- "wald" - } - method <- match.arg(tolower(method), choices = c("analytical", "any", "fit", "wald", "residual", "normal")) - - if (method %in% c("wald", "residual", "fit")) { - dof <- model$resid_df_obs - if (is.null(dof)) { - dof <- degrees_of_freedom.default(model, method = method, ...) - } - } else { - dof <- degrees_of_freedom.default(model, method = method, ...) - } - - dof -} diff --git a/R/methods_effect_size.R b/R/methods_effect_size.R index 579477b25..06896670c 100644 --- a/R/methods_effect_size.R +++ b/R/methods_effect_size.R @@ -17,21 +17,21 @@ ci.parameters_standardized <- function(x, ci = 0.95, verbose = TRUE, ...) { # check if we have model. if so, use df from model model <- .get_object(x) if (!is.null(model)) { - df <- degrees_of_freedom(model, method = "any") - if (!is.null(df)) { - if (length(df) > 1 && length(df) != nrow(x)) { - df <- Inf + dof <- insight::get_df(model, type = "wald") + if (!is.null(dof)) { + if (length(dof) > 1 && length(dof) != nrow(x)) { + dof <- Inf } } else { - df <- Inf + dof <- Inf } } else { - df <- Inf + dof <- Inf } out <- lapply(ci, function(i) { alpha <- (1 + i) / 2 - fac <- stats::qt(alpha, df = df) + fac <- stats::qt(alpha, df = dof) data.frame( Parameter = x$Parameter, CI = i, diff --git a/R/methods_emmeans.R b/R/methods_emmeans.R index 0c5e1bb84..aac0f08dd 100644 --- a/R/methods_emmeans.R +++ b/R/methods_emmeans.R @@ -27,23 +27,7 @@ model_parameters.emmGrid <- function(model, s <- summary(model, level = ci, adjust = "none") params <- as.data.frame(s) - # we assume frequentist here... - if (!.is_bayesian_emmeans(model)) { - # get statistic, se and p - statistic <- insight::get_statistic(model, ci = ci, adjust = "none") - SE <- standard_error(model) - p <- p_value(model, ci = ci, adjust = "none") - - params$Statistic <- statistic$Statistic - params$SE <- SE$SE - params$p <- p$p - - # ==== adjust p-values? - - if (!is.null(p_adjust)) { - params <- .p_adjust(params, p_adjust, model, verbose) - } - } else { + if (.is_bayesian_emmeans(model)) { # Bayesian models go here... params <- bayestestR::describe_posterior( model, @@ -60,8 +44,22 @@ model_parameters.emmGrid <- function(model, verbose = verbose, ... ) - statistic <- NULL + } else { + # we assume frequentist here... + statistic <- insight::get_statistic(model, ci = ci, adjust = "none") + SE <- standard_error(model) + p <- p_value(model, ci = ci, adjust = "none") + + params$Statistic <- statistic$Statistic + params$SE <- SE$SE + params$p <- p$p + + # ==== adjust p-values? + + if (!is.null(p_adjust)) { + params <- .p_adjust(params, p_adjust, model, verbose) + } } @@ -88,11 +86,11 @@ model_parameters.emmGrid <- function(model, if (!any(startsWith(colnames(params), "CI_"))) { df_column <- grep("(df|df_error)", colnames(params)) if (length(df_column) > 0) { - df <- params[[df_column[1]]] + dof <- params[[df_column[1]]] } else { - df <- Inf + dof <- Inf } - fac <- stats::qt((1 + ci) / 2, df = df) + fac <- stats::qt((1 + ci) / 2, df = dof) params$CI_low <- params$Estimate - fac * params$SE params$CI_high <- params$Estimate + fac * params$SE } @@ -105,12 +103,12 @@ model_parameters.emmGrid <- function(model, # Reorder estimate_pos <- which(colnames(s) == estName) parameter_names <- colnames(params)[seq_len(estimate_pos - 1)] - order <- c( + col_order <- c( parameter_names, "Estimate", "Median", "Mean", "SE", "SD", "MAD", "CI_low", "CI_high", "F", "t", "z", "df", "df_error", "p", "pd", "ROPE_CI", "ROPE_low", "ROPE_high", "ROPE_Percentage" ) - params <- params[order[order %in% names(params)]] + params <- params[col_order[col_order %in% names(params)]] # rename names(params) <- gsub("Estimate", "Coefficient", names(params), fixed = TRUE) @@ -210,12 +208,12 @@ model_parameters.summary_emm <- function(model, # Reorder estimate_pos <- which(colnames(model) == estName) parameter_names <- colnames(params)[seq_len(estimate_pos - 1)] - order <- c( + col_order <- c( parameter_names, "Estimate", "Median", "Mean", "SE", "SD", "MAD", "CI_low", "CI_high", "F", "t", "z", "df", "df_error", "p", "pd", "ROPE_CI", "ROPE_low", "ROPE_high", "ROPE_Percentage" ) - params <- params[order[order %in% names(params)]] + params <- params[col_order[col_order %in% names(params)]] # rename names(params) <- gsub("Estimate", "Coefficient", names(params), fixed = TRUE) @@ -315,42 +313,6 @@ boot_em_standard_error <- function(model) { - -# degrees of freedom -------------------- - - -#' @export -degrees_of_freedom.emmGrid <- function(model, ...) { - if (!is.null(model@misc$is_boot) && model@misc$is_boot) { - return(boot_em_df(model)) - } - - summary(model)$df -} - - -#' @export -degrees_of_freedom.emm_list <- function(model, ...) { - if (!is.null(model[[1]]@misc$is_boot) && model[[1]]@misc$is_boot) { - return(boot_em_df(model)) - } - - s <- summary(model) - unlist(lapply(s, function(i) { - if (is.null(i$df)) { - rep(Inf, nrow(i)) - } else { - i$df - } - }), use.names = FALSE) -} - -boot_em_df <- function(model) { - est <- insight::get_parameters(model, summary = FALSE) - rep(NA, ncol(est)) -} - - # p values ---------------------- @@ -361,21 +323,20 @@ p_value.emmGrid <- function(model, ci = 0.95, adjust = "none", ...) { return(boot_em_pval(model, adjust)) } - s <- summary(model, level = ci, adjust = adjust) estimate_pos <- which(colnames(s) == attr(s, "estName")) - if (length(estimate_pos)) { - stat <- insight::get_statistic(model, ci = ci, adjust = adjust) - p <- 2 * stats::pt(abs(stat$Statistic), df = s$df, lower.tail = FALSE) - - .data_frame( - Parameter = .pretty_emmeans_Parameter_names(model), - p = as.vector(p) - ) - } else { + if (!length(estimate_pos)) { return(NULL) } + + stat <- insight::get_statistic(model, ci = ci, adjust = adjust) + p <- 2 * stats::pt(abs(stat$Statistic), df = s$df, lower.tail = FALSE) + + .data_frame( + Parameter = .pretty_emmeans_Parameter_names(model), + p = as.vector(p) + ) } @@ -418,8 +379,8 @@ p_value.emm_list <- function(model, adjust = "none", ...) { # test statistic and p-values stat <- params$Estimate / se - df <- degrees_of_freedom(model) - p_val <- 2 * stats::pt(abs(stat), df = df, lower.tail = FALSE) + dof <- insight::get_df(model) + p_val <- 2 * stats::pt(abs(stat), df = dof, lower.tail = FALSE) out$p[is.na(out$p)] <- p_val[is.na(out$p)] } diff --git a/R/methods_fixest.R b/R/methods_fixest.R index bb2a04d17..9481f0090 100644 --- a/R/methods_fixest.R +++ b/R/methods_fixest.R @@ -82,34 +82,6 @@ standard_error.fixest <- function(model, vcov = NULL, vcov_args = NULL, ...) { } -#' @export -degrees_of_freedom.fixest <- function(model, method = "wald", ...) { - # fixest degrees of freedom can be tricky. best to use the function by the - # package. - insight::check_if_installed("fixest") - if (is.null(method)) { - method <- "wald" - } - method <- match.arg( - tolower(method), - choices = c("wald", "residual", "normal") - ) - - # we may have Inf DF, too - if (method == "normal") { - return(Inf) - } - - method <- switch(method, - wald = "t", - residual = "resid" - ) - fixest::degrees_freedom(model, type = method) -} - - - - # .feglm ----------------------- #' @export @@ -226,22 +198,6 @@ standard_error.fixest_multi <- function(model, ...) { } -#' @export -degrees_of_freedom.fixest_multi <- function(model, ...) { - out <- do.call(rbind, lapply(model, degrees_of_freedom, ...)) - - # add response and group columns - id_columns <- .get_fixest_multi_columns(model) - - # add response column - out$Response <- id_columns$Response - out$Group <- id_columns$Group - - row.names(out) <- NULL - out -} - - #' @export p_value.fixest_multi <- function(model, ...) { out <- do.call(rbind, lapply(model, p_value, ...)) diff --git a/R/methods_gee.R b/R/methods_gee.R index 3b173b8f9..9dcaa3b65 100644 --- a/R/methods_gee.R +++ b/R/methods_gee.R @@ -56,7 +56,7 @@ p_value.geeglm <- function(model, method = "wald", ...) { if (!is.null(stat)) { if (identical(method, "residual")) { - dof <- degrees_of_freedom(model, method = "residual") + dof <- insight::get_df(model, type = "residual") p <- as.vector(2 * stats::pt( sqrt(abs(stat$Statistic)), df = dof, diff --git a/R/methods_hglm.R b/R/methods_hglm.R index 4f237e112..c324d3d4f 100644 --- a/R/methods_hglm.R +++ b/R/methods_hglm.R @@ -154,15 +154,6 @@ standard_error.hglm <- function(model, } -#' @export -degrees_of_freedom.hglm <- function(model, method = "residual", ...) { - if (method == "any") { - method <- "residual" - } - insight::get_df(model, type = method, ...) -} - - #' @export ci.hglm <- function(x, ci = 0.95, diff --git a/R/methods_ivfixed.R b/R/methods_ivfixed.R index 6c175646c..25cb92734 100644 --- a/R/methods_ivfixed.R +++ b/R/methods_ivfixed.R @@ -6,28 +6,17 @@ ci.ivFixed <- ci.default standard_error.ivFixed <- standard_error.coxr -#' @export -degrees_of_freedom.ivFixed <- function(model, method = "wald", ...) { - if (is.null(method)) { - method <- "wald" - } - method <- match.arg(tolower(method), choices = c("analytical", "any", "fit", "wald", "residual", "normal")) - - if (method %in% c("wald", "residual", "fit")) { - as.vector(model$df) - } else { - degrees_of_freedom.default(model, method = method, ...) - } -} - - #' @export p_value.ivFixed <- function(model, method = "wald", ...) { stat <- insight::get_statistic(model) if (!is.null(stat)) { .data_frame( Parameter = stat$Parameter, - p = as.vector(2 * stats::pt(abs(stat$Statistic), df = degrees_of_freedom(model, method = method), lower.tail = FALSE)) + p = as.vector(2 * stats::pt( + abs(stat$Statistic), + df = insight::get_df(model, type = method), + lower.tail = FALSE + )) ) } } diff --git a/R/methods_ivprobit.R b/R/methods_ivprobit.R index 826719b71..d2fe1cec4 100644 --- a/R/methods_ivprobit.R +++ b/R/methods_ivprobit.R @@ -2,11 +2,6 @@ ci.ivprobit <- ci.default - -#' @export -degrees_of_freedom.ivprobit <- degrees_of_freedom.ivFixed - - #' @export standard_error.ivprobit <- function(model, ...) { .data_frame( diff --git a/R/methods_lm.R b/R/methods_lm.R index a52ad3d87..42c13e0d5 100644 --- a/R/methods_lm.R +++ b/R/methods_lm.R @@ -47,9 +47,3 @@ p_value.summary.lm <- function(model, ...) { ci.summary.lm <- function(x, ci = 0.95, method = "residual", ...) { .ci_generic(model = x, ci = ci, method = method, dof = insight::get_df(x), ...) } - - -#' @export -degrees_of_freedom.summary.lm <- function(model, ...) { - model$fstatistic[3] -} diff --git a/R/methods_lmtest.R b/R/methods_lmtest.R index c73d0a528..3809572e2 100644 --- a/R/methods_lmtest.R +++ b/R/methods_lmtest.R @@ -1,8 +1,3 @@ -#' @export -degrees_of_freedom.coeftest <- function(model, ...) { - attributes(model)$df -} - #' @export ci.coeftest <- ci.default diff --git a/R/methods_lqmm.R b/R/methods_lqmm.R index 5b3c8ecae..108af5274 100644 --- a/R/methods_lqmm.R +++ b/R/methods_lqmm.R @@ -67,17 +67,6 @@ standard_error.lqmm <- function(model, ...) { standard_error.lqm <- standard_error.lqmm -#' @export -degrees_of_freedom.lqmm <- function(model, ...) { - out <- model_parameters(model, ...) - out$df_error -} - - -#' @export -degrees_of_freedom.lqm <- degrees_of_freedom.lqmm - - #' @export p_value.lqmm <- function(model, ...) { out <- model_parameters(model, ...) diff --git a/R/methods_lrm.R b/R/methods_lrm.R index f919e0cb9..b5915fc4d 100644 --- a/R/methods_lrm.R +++ b/R/methods_lrm.R @@ -47,13 +47,13 @@ p_value.lrm <- function(model, ...) { # Issue: 697: typically the degrees of freedom are the same for every # observation, but the value is repeated. This poses problems in multiple # imputation models with Hmisc when we get more df values than parameters. - df <- degrees_of_freedom(model, method = "any") - dfu <- unique(df) + dof <- insight::get_df(model, type = "wald") + dfu <- unique(dof) if (length(dfu) == 1) { - df <- dfu + dof <- dfu } - p <- 2 * stats::pt(abs(stat$Statistic), df = df, lower.tail = FALSE) + p <- 2 * stats::pt(abs(stat$Statistic), df = dof, lower.tail = FALSE) .data_frame( Parameter = .remove_backticks_from_string(stat$Parameter), diff --git a/R/methods_mass.R b/R/methods_mass.R index 57804441d..7d1f54728 100644 --- a/R/methods_mass.R +++ b/R/methods_mass.R @@ -1,15 +1,3 @@ -# degrees of freedom ----------------- - -#' @export -degrees_of_freedom.rlm <- function(model, method = "residual", ...) { - .degrees_of_freedom_no_dfresid_method(model, method) -} - - - - - - # ci ----------------- #' @export @@ -49,9 +37,6 @@ ci.polr <- function(x, ci = 0.95, dof = NULL, method = "profile", ...) { - - - # SE ----------------- #' @export @@ -73,9 +58,6 @@ standard_error.polr <- function(model, method = NULL, ...) { - - - # p ----------------- #' @export @@ -85,7 +67,7 @@ p_value.negbin <- p_value.default #' @export p_value.rlm <- function(model, ...) { cs <- stats::coef(summary(model)) - p <- 2 * stats::pt(abs(cs[, 3]), df = degrees_of_freedom(model, method = "any"), lower.tail = FALSE) + p <- 2 * stats::pt(abs(cs[, 3]), df = insight::get_df(model, type = "wald"), lower.tail = FALSE) .data_frame( Parameter = .remove_backticks_from_string(names(p)), p = as.vector(p) @@ -102,7 +84,7 @@ p_value.polr <- function(model, method = NULL, ...) { smry <- suppressMessages(as.data.frame(stats::coef(summary(model)))) tstat <- smry[[3]] - p <- 2 * stats::pt(abs(tstat), df = degrees_of_freedom(model, method = "any"), lower.tail = FALSE) + p <- 2 * stats::pt(abs(tstat), df = insight::get_df(x = model, type = "wald"), lower.tail = FALSE) names(p) <- rownames(smry) .data_frame( @@ -113,8 +95,6 @@ p_value.polr <- function(model, method = NULL, ...) { - - # parameters ----------------- #' @rdname model_parameters.default diff --git a/R/methods_mediate.R b/R/methods_mediate.R index ef907a9ca..a728ecd6d 100644 --- a/R/methods_mediate.R +++ b/R/methods_mediate.R @@ -95,12 +95,6 @@ standard_error.mediate <- function(model, ...) { } -#' @export -degrees_of_freedom.mediate <- function(model, ...) { - NULL -} - - #' @export p_value.mediate <- function(model, ...) { info <- insight::model_info(model$model.y, verbose = FALSE) diff --git a/R/methods_merTools.R b/R/methods_merTools.R index c5f5ff060..4276c5a91 100644 --- a/R/methods_merTools.R +++ b/R/methods_merTools.R @@ -43,13 +43,6 @@ standard_error.merModList <- function(model, ...) { } -#' @export -degrees_of_freedom.merModList <- function(model, ...) { - s <- suppressWarnings(summary(model)) - s$fe$df -} - - #' @export format_parameters.merModList <- function(model, brackets = c("[", "]"), ...) { .format_parameter_default(model[[1]], brackets = brackets) diff --git a/R/methods_mfx.R b/R/methods_mfx.R index 7709fb31d..847eb79a7 100644 --- a/R/methods_mfx.R +++ b/R/methods_mfx.R @@ -296,50 +296,6 @@ standard_error.betamfx <- function(model, - -# degrees of freedom ------------------ - - -#' @export -degrees_of_freedom.logitor <- function(model, ...) { - degrees_of_freedom.default(model$fit, ...) -} - - -#' @export -degrees_of_freedom.poissonirr <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.negbinirr <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.poissonmfx <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.logitmfx <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.negbinmfx <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.probitmfx <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.betaor <- degrees_of_freedom.logitor - - -#' @export -degrees_of_freedom.betamfx <- degrees_of_freedom.logitor - - - - # p values ------------------ diff --git a/R/methods_mhurdle.R b/R/methods_mhurdle.R index a28befd11..47775b8c2 100644 --- a/R/methods_mhurdle.R +++ b/R/methods_mhurdle.R @@ -61,12 +61,6 @@ ci.mhurdle <- function(x, ci = 0.95, ...) { } -#' @export -degrees_of_freedom.mhurdle <- function(model, method = NULL, ...) { - .degrees_of_freedom_no_dfresid_method(model, method) -} - - #' @export standard_error.mhurdle <- function(model, component = c("all", "conditional", "zi", "zero_inflated", "infrequent_purchase", "ip", "auxiliary"), ...) { component <- match.arg(component) diff --git a/R/methods_mice.R b/R/methods_mice.R index 93b25ddfd..ecadff56c 100644 --- a/R/methods_mice.R +++ b/R/methods_mice.R @@ -11,21 +11,6 @@ ci.mira <- function(x, ci = 0.95, ...) { } -# degrees of freedom ---------------------------- - -#' @export -degrees_of_freedom.mira <- function(model, ...) { - insight::check_if_installed("mice") - degrees_of_freedom(mice::pool(model), ...) -} - - -#' @export -degrees_of_freedom.mipo <- function(model, ...) { - as.vector(summary(model)$df) -} - - # p values --------------------------------------- #' @export diff --git a/R/methods_mmrm.R b/R/methods_mmrm.R index b97598df5..89b68b402 100644 --- a/R/methods_mmrm.R +++ b/R/methods_mmrm.R @@ -126,18 +126,3 @@ standard_error.mmrm_fit <- standard_error.mmrm #' @export standard_error.mmrm_tmb <- standard_error.mmrm - - -# degrees of freedom ------------------ - -#' @export -degrees_of_freedom.mmrm <- function(model, ...) { - summary_table <- stats::coef(summary(model)) - unname(summary_table[, "df"]) -} - -#' @export -degrees_of_freedom.mmrm_fit <- degrees_of_freedom.mmrm - -#' @export -degrees_of_freedom.mmrm_tmb <- degrees_of_freedom.mmrm diff --git a/R/methods_model_fit.R b/R/methods_model_fit.R index 1f02b2032..306a305a8 100644 --- a/R/methods_model_fit.R +++ b/R/methods_model_fit.R @@ -54,16 +54,6 @@ standard_error.model_fit <- function(model, ...) { -# degrees of freedom ------------------ - - -#' @export -degrees_of_freedom.model_fit <- function(model, ...) { - degrees_of_freedom(model$fit, ...) -} - - - # p values ------------------ diff --git a/R/methods_multcomp.R b/R/methods_multcomp.R index f906c1560..963cc85d1 100644 --- a/R/methods_multcomp.R +++ b/R/methods_multcomp.R @@ -103,12 +103,6 @@ standard_error.glht <- function(model, ...) { } -#' @export -degrees_of_freedom.glht <- function(model, ...) { - model$df -} - - #' @export p_value.glht <- function(model, ...) { s <- summary(model) diff --git a/R/methods_nestedLogit.R b/R/methods_nestedLogit.R index 90bc86169..c87df18bd 100644 --- a/R/methods_nestedLogit.R +++ b/R/methods_nestedLogit.R @@ -75,40 +75,6 @@ model_parameters.nestedLogit <- function(model, } -#' @export -degrees_of_freedom.nestedLogit <- function(model, - method = NULL, - component = "all", - verbose = TRUE, - ...) { - if (is.null(method)) { - method <- "wald" - } - if (tolower(method) == "residual") { - cf <- as.data.frame(stats::coef(model)) - dof <- rep(vapply(model$models, stats::df.residual, numeric(1)), each = nrow(cf)) - if (!is.null(component) && !identical(component, "all")) { - comp <- intersect(names(dof), component) - if (length(comp)) { - dof <- dof[comp] - } else { - if (verbose) { - insight::format_alert(paste0( - "No matching model found. Possible values for `component` are ", - toString(paste0("'", names(model$models), "'")), - "." - )) - } - dof <- Inf - } - } - } else { - dof <- Inf - } - dof -} - - #' @export standard_error.nestedLogit <- function(model, component = "all", diff --git a/R/methods_nlme.R b/R/methods_nlme.R index 5b23fc5e9..ecd99429d 100644 --- a/R/methods_nlme.R +++ b/R/methods_nlme.R @@ -97,9 +97,3 @@ standard_error.gls <- standard_error.default #' @export p_value.gls <- p_value.default - - -#' @export -degrees_of_freedom.gls <- function(model, method = NULL, ...) { - .degrees_of_freedom_no_dfresid_method(model, method) -} diff --git a/R/methods_other.R b/R/methods_other.R index 402f29ab8..1da9fccef 100644 --- a/R/methods_other.R +++ b/R/methods_other.R @@ -20,13 +20,6 @@ p_value.complmrob <- p_value.default ci.complmrob <- ci.default -#' @export -degrees_of_freedom.complmrob <- function(model, method = "wald", ...) { - .degrees_of_freedom_no_dfresid_method(model, method) -} - - - ############# .Gam -------------- diff --git a/R/methods_plm.R b/R/methods_plm.R index 12e2be790..271c9ee93 100644 --- a/R/methods_plm.R +++ b/R/methods_plm.R @@ -4,15 +4,6 @@ # plm --------------------------- -#' @export -degrees_of_freedom.plm <- function(model, method = "wald", ...) { - if (identical(method, "normal")) { - return(Inf) - } - model$df.residual -} - - #' @export standard_error.plm <- function(model, vcov = NULL, vcov_args = NULL, verbose = TRUE, ...) { dots <- list(...) diff --git a/R/methods_quantreg.R b/R/methods_quantreg.R index 9e61e68f7..bed08b33e 100644 --- a/R/methods_quantreg.R +++ b/R/methods_quantreg.R @@ -323,36 +323,3 @@ p_value.rqss <- function(model, p } - - - - -# degrees of freedom --------------------- - - -#' @export -degrees_of_freedom.rqs <- function(model, ...) { - tryCatch( - { - s <- suppressWarnings(summary(model, covariance = TRUE)) - cs <- lapply(s, function(i) i$rdf) - unique(unlist(cs)) - }, - error = function(e) { - NULL - } - ) -} - - - -#' @export -degrees_of_freedom.rqss <- degrees_of_freedom.multinom - - -#' @export -degrees_of_freedom.rq <- degrees_of_freedom.rqs - - -#' @export -degrees_of_freedom.nlrq <- degrees_of_freedom.mhurdle diff --git a/R/methods_selection.R b/R/methods_selection.R index 81582060b..46c227832 100644 --- a/R/methods_selection.R +++ b/R/methods_selection.R @@ -83,7 +83,6 @@ standard_error.selection <- function(model, component = c("all", "selection", "o } - #' @export simulate_model.selection <- function(model, iterations = 1000, @@ -100,10 +99,3 @@ simulate_model.selection <- function(model, #' @export ci.selection <- ci.default - - -#' @export -degrees_of_freedom.selection <- function(model, ...) { - s <- summary(model) - s$param$df -} diff --git a/R/methods_serp.R b/R/methods_serp.R deleted file mode 100644 index c4f0fff71..000000000 --- a/R/methods_serp.R +++ /dev/null @@ -1,14 +0,0 @@ -#' @export -degrees_of_freedom.serp <- function(model, method = "normal", ...) { - if (is.null(method)) { - method <- "wald" - } - - method <- match.arg(tolower(method), choices = c("analytical", "any", "fit", "wald", "residual", "normal")) - - if (method %in% c("residual", "fit")) { - model$rdf - } else { - degrees_of_freedom.default(model, method = method, ...) - } -} diff --git a/R/methods_survey.R b/R/methods_survey.R index 04674bf8f..4af36e799 100644 --- a/R/methods_survey.R +++ b/R/methods_survey.R @@ -141,7 +141,7 @@ p_value.svyglm.nb <- function(model, ...) { est <- stats::coef(model) se <- sqrt(diag(stats::vcov(model, stderr = "robust"))) - p <- 2 * stats::pt(abs(est / se), df = degrees_of_freedom(model, method = "any"), lower.tail = FALSE) + p <- 2 * stats::pt(abs(est / se), df = insight::get_df(model, type = "wald"), lower.tail = FALSE) .data_frame( Parameter = .remove_backticks_from_string(names(p)), diff --git a/R/methods_svy2lme.R b/R/methods_svy2lme.R index 90899b91a..e34e7bb88 100644 --- a/R/methods_svy2lme.R +++ b/R/methods_svy2lme.R @@ -105,9 +105,3 @@ p_value.svy2lme <- function(model, ...) { p = as.vector(p) ) } - - -#' @export -degrees_of_freedom.svy2lme <- function(model, ...) { - Inf -} diff --git a/R/methods_systemfit.R b/R/methods_systemfit.R index 166340c3b..9edd008de 100644 --- a/R/methods_systemfit.R +++ b/R/methods_systemfit.R @@ -33,7 +33,6 @@ model_parameters.systemfit <- function(model, } - #' @export standard_error.systemfit <- function(model, ...) { cf <- stats::coef(summary(model)) @@ -57,7 +56,6 @@ standard_error.systemfit <- function(model, ...) { } - #' @export p_value.systemfit <- function(model, ...) { cf <- stats::coef(summary(model)) @@ -81,25 +79,5 @@ p_value.systemfit <- function(model, ...) { } - -#' @export -degrees_of_freedom.systemfit <- function(model, ...) { - dof <- NULL - s <- summary(model)$eq - params <- insight::find_parameters(model) - f <- insight::find_formula(model) - system_names <- names(f) - - for (i in seq_along(system_names)) { - dfs <- rep(s[[i]]$df[2], length(params[[i]])) - df_names <- rep(names(params[i]), length(params[[i]])) - dof <- c(dof, stats::setNames(dfs, df_names)) - } - - dof -} - - - #' @export ci.systemfit <- ci.lm diff --git a/R/methods_truncreg.R b/R/methods_truncreg.R index dd260b243..ca04cd950 100644 --- a/R/methods_truncreg.R +++ b/R/methods_truncreg.R @@ -7,7 +7,3 @@ standard_error.truncreg <- standard_error.default #' @export p_value.truncreg <- p_value.default - - -#' @export -degrees_of_freedom.truncreg <- degrees_of_freedom.mhurdle diff --git a/R/methods_tseries.R b/R/methods_tseries.R deleted file mode 100644 index eefb3256d..000000000 --- a/R/methods_tseries.R +++ /dev/null @@ -1,4 +0,0 @@ -# classes: .garch - -#' @export -degrees_of_freedom.garch <- degrees_of_freedom.mhurdle diff --git a/R/methods_vgam.R b/R/methods_vgam.R index 750189fac..a0018afdb 100644 --- a/R/methods_vgam.R +++ b/R/methods_vgam.R @@ -22,19 +22,10 @@ standard_error.vgam <- function(model, ...) { } -#' @export -degrees_of_freedom.vgam <- function(model, ...) { - params <- insight::get_parameters(model) - out <- stats::setNames(rep(NA, nrow(params)), params$Parameter) - out[names(model@nl.df)] <- model@nl.df - out -} - - #' @export p_value.vgam <- function(model, ...) { stat <- insight::get_statistic(model) - stat$p <- as.vector(stats::pchisq(stat$Statistic, df = degrees_of_freedom(model), lower.tail = FALSE)) + stat$p <- as.vector(stats::pchisq(stat$Statistic, df = insight::get_df(model), lower.tail = FALSE)) stat[c("Parameter", "p", "Component")] } diff --git a/man/degrees_of_freedom.Rd b/man/degrees_of_freedom.Rd index 714ced31a..291bd55aa 100644 --- a/man/degrees_of_freedom.Rd +++ b/man/degrees_of_freedom.Rd @@ -2,58 +2,48 @@ % Please edit documentation in R/dof.R \name{degrees_of_freedom} \alias{degrees_of_freedom} -\alias{degrees_of_freedom.default} \alias{dof} \title{Degrees of Freedom (DoF)} \usage{ -degrees_of_freedom(model, ...) +degrees_of_freedom(model, method = "analytical", ...) -\method{degrees_of_freedom}{default}(model, method = "analytical", ...) - -dof(model, ...) +dof(model, method = "analytical", ...) } \arguments{ \item{model}{A statistical model.} -\item{...}{Currently not used.} +\item{method}{Type of approximation for the degrees of freedom. Can be one of +the following: +\itemize{ +\item \code{"residual"} (aka \code{"analytical"}) returns the residual degrees of +freedom, which usually is what \code{\link[stats:df.residual]{stats::df.residual()}} returns. If a +model object has no method to extract residual degrees of freedom, these +are calculated as \code{n-p}, i.e. the number of observations minus the number +of estimated parameters. If residual degrees of freedom cannot be extracted +by either approach, returns \code{Inf}. +\item \code{"wald"} returns residual (aka analytical) degrees of freedom for models +with t-statistic, \code{1} for models with Chi-squared statistic, and \code{Inf} for +all other models. Also returns \code{Inf} if residual degrees of freedom cannot +be extracted. +\item \code{"normal"} always returns \code{Inf}. +\item \code{"model"} returns model-based degrees of freedom, i.e. the number of +(estimated) parameters. +\item For mixed models, can also be \code{"ml1"} (or \code{"m-l-1"}, approximation of +degrees of freedom based on a "m-l-1" heuristic as suggested by \emph{Elff et +al. 2019}) or \code{"between-within"} (or \code{"betwithin"}). +\item For mixed models of class \code{merMod}, \code{type} can also be \code{"satterthwaite"} +or \code{"kenward-roger"} (or \code{"kenward"}). See 'Details'. +} -\item{method}{Can be \code{"analytical"} (default, DoFs are estimated based -on the model type), \code{"residual"} in which case they are directly taken -from the model if available (for Bayesian models, the goal (looking for -help to make it happen) would be to refit the model as a frequentist one -before extracting the DoFs), \code{"ml1"} (see \code{\link[=dof_ml1]{dof_ml1()}}), \code{"betwithin"} -(see \code{\link[=dof_betwithin]{dof_betwithin()}}), \code{"satterthwaite"} (see \code{\link[=dof_satterthwaite]{dof_satterthwaite()}}), -\code{"kenward"} (see \code{\link[=dof_kenward]{dof_kenward()}}) or \code{"any"}, which tries to extract DoF -by any of those methods, whichever succeeds. See 'Details'.} +Usually, when degrees of freedom are required to calculate p-values or +confidence intervals, \code{type = "wald"} is likely to be the best choice in +most cases.} + +\item{...}{Currently not used.} } \description{ Estimate or extract degrees of freedom of models parameters. } -\details{ -Methods for calculating degrees of freedom: -\itemize{ -\item \code{"analytical"} for models of class \code{lmerMod}, Kenward-Roger approximated -degrees of freedoms are calculated, for other models, \code{n-k} (number of -observations minus number of parameters). -\item \code{"residual"} tries to extract residual degrees of freedom, and returns -\code{Inf} if residual degrees of freedom could not be extracted. -\item \code{"any"} first tries to extract residual degrees of freedom, and if these -are not available, extracts analytical degrees of freedom. -\item \code{"nokr"} same as \code{"analytical"}, but does not Kenward-Roger approximation -for models of class \code{lmerMod}. Instead, always uses \code{n-k} to calculate df -for any model. -\item \code{"normal"} returns \code{Inf}. -\item \code{"wald"} returns residual df for models with t-statistic, and \code{Inf} for all other models. -\item \code{"kenward"} calls \code{\link[=dof_kenward]{dof_kenward()}}. -\item \code{"satterthwaite"} calls \code{\link[=dof_satterthwaite]{dof_satterthwaite()}}. -\item \code{"ml1"} calls \code{\link[=dof_ml1]{dof_ml1()}}. -\item \code{"betwithin"} calls \code{\link[=dof_betwithin]{dof_betwithin()}}. -} - -For models with z-statistic, the returned degrees of freedom for model parameters -is \code{Inf} (unless \code{method = "ml1"} or \code{method = "betwithin"}), because there is -only one distribution for the related test statistic. -} \note{ In many cases, \code{degrees_of_freedom()} returns the same as \code{df.residuals()}, or \code{n-k} (number of observations minus number of parameters). However, @@ -65,16 +55,15 @@ Furthermore, for other approximation methods like \code{"kenward"} or freedom. } \examples{ +\dontshow{if (require("lme4", quietly = TRUE)) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} model <- lm(Sepal.Length ~ Petal.Length * Species, data = iris) dof(model) model <- glm(vs ~ mpg * cyl, data = mtcars, family = "binomial") dof(model) \donttest{ -if (require("lme4", quietly = TRUE)) { - model <- lmer(Sepal.Length ~ Petal.Length + (1 | Species), data = iris) - dof(model) -} +model <- lmer(Sepal.Length ~ Petal.Length + (1 | Species), data = iris) +dof(model) if (require("rstanarm", quietly = TRUE)) { model <- stan_glm( @@ -86,4 +75,5 @@ if (require("rstanarm", quietly = TRUE)) { dof(model) } } +\dontshow{\}) # examplesIf} } diff --git a/tests/testthat/test-robust.R b/tests/testthat/test-robust.R index 23b7af317..ad84ff23f 100644 --- a/tests/testthat/test-robust.R +++ b/tests/testthat/test-robust.R @@ -354,7 +354,7 @@ skip_if_not_installed("lme4") test_that("robust-se lmer", { data(iris) set.seed(1234) - iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE)) + iris$grp <- as.factor(sample.int(3, nrow(iris), replace = TRUE)) m <- lme4::lmer( Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp), @@ -368,7 +368,7 @@ test_that("robust-se lmer", { test_that("robust-p lmer", { data(iris) set.seed(1234) - iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE)) + iris$grp <- as.factor(sample.int(3, nrow(iris), replace = TRUE)) m <- lme4::lmer( Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp), @@ -385,7 +385,7 @@ test_that("robust-p lmer", { test_that("robust-ci lmer", { data(iris) set.seed(1234) - iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE)) + iris$grp <- as.factor(sample.int(3, nrow(iris), replace = TRUE)) m <- lme4::lmer( Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp), diff --git a/tests/testthat/test-serp.R b/tests/testthat/test-serp.R index 3069ce80f..3dbf04646 100644 --- a/tests/testthat/test-serp.R +++ b/tests/testthat/test-serp.R @@ -1,5 +1,5 @@ skip_if_not_installed("serp") -skip_if_not_installed("insight", minimum_version = "0.19.8.4") +skip_if_not_installed("insight", minimum_version = "0.20.0") skip_if_not_installed("withr") # make sure we have the correct interaction mark for tests