Skip to content

LMMs default to Satterthwaite df - #1276

Merged
mattansb merged 37 commits into
mainfrom
default-satterthwaite
Oct 20, 2026
Merged

mattansb merged 37 commits into
mainfrom
default-satterthwaite

Conversation

@mattansb

Copy link
Copy Markdown
Member

Following discussion in #989 and #1273, this PR uses default Satterthwaite df for lmerModTest objects (from {lmerTest}) and when {lmerTest} is installed also for lmerMod objects.

library(parameters)

data("sleepstudy", package = "lme4")

m1 <- lmerTest::lmer(Reaction ~ Days + (Days | Subject), data = sleepstudy)
model_parameters(m1)
#> # Fixed Effects
#> 
#> Parameter   | Coefficient |   SE |           95% CI | t(17.00) |      p
#> -----------------------------------------------------------------------
#> (Intercept) |      251.41 | 6.82 | [237.01, 265.80] |    36.84 | < .001
#> Days        |       10.47 | 1.55 | [  7.21,  13.73] |     6.77 | < .001
#> 
#> # Random Effects
#> 
#> Parameter                     | Coefficient |   SE |         95% CI
#> -------------------------------------------------------------------
#> SD (Intercept: Subject)       |       24.74 | 5.84 | [15.58, 39.28]
#> SD (Days: Subject)            |        5.92 | 1.25 | [ 3.92,  8.95]
#> Cor (Intercept~Days: Subject) |        0.07 | 0.32 | [-0.51,  0.60]
#> SD (Residual)                 |       25.59 | 1.51 | [22.80, 28.72]
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald t-distribution with Satterthwaite approximation.

m1 <- lme4::lmer(Reaction ~ Days + (Days | Subject), data = sleepstudy)
model_parameters(m1)
#> # Fixed Effects
#> 
#> Parameter   | Coefficient |   SE |           95% CI | t(17.00) |      p
#> -----------------------------------------------------------------------
#> (Intercept) |      251.41 | 6.82 | [237.01, 265.80] |    36.84 | < .001
#> Days        |       10.47 | 1.55 | [  7.21,  13.73] |     6.77 | < .001
#> 
#> # Random Effects
#> 
#> Parameter                     | Coefficient |   SE |         95% CI
#> -------------------------------------------------------------------
#> SD (Intercept: Subject)       |       24.74 | 5.84 | [15.58, 39.28]
#> SD (Days: Subject)            |        5.92 | 1.25 | [ 3.92,  8.95]
#> Cor (Intercept~Days: Subject) |        0.07 | 0.32 | [-0.51,  0.60]
#> SD (Residual)                 |       25.59 | 1.51 | [22.80, 28.72]
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald t-distribution with Satterthwaite approximation.
#>   Uncertainty intervals for random effect variances computed using a Wald
#>   z-distribution approximation.


remove.packages("lmerTest")
#> Removing package from 'C:/Users/user/AppData/Local/R/win-library/4.6'
#> (as 'lib' is unspecified)
unloadNamespace("lmerTest")

m1 <- lme4::lmer(Reaction ~ Days + (Days | Subject), data = sleepstudy)
model_parameters(m1)
#> Warning: Package `lmerTest` required for Satterthwaite df (default).
#>   Please install it by running `install.packages("lmerTest")`.
#> Warning: Package `lmerTest` required for Satterthwaite df (default).
#>   Please install it by running `install.packages("lmerTest")`.
#> Warning: Package `lmerTest` required for Satterthwaite df (default).
#>   Please install it by running `install.packages("lmerTest")`.
#> # Fixed Effects
#> 
#> Parameter   | Coefficient |   SE |           95% CI | t(174) |      p
#> ---------------------------------------------------------------------
#> (Intercept) |      251.41 | 6.82 | [237.94, 264.87] |  36.84 | < .001
#> Days        |       10.47 | 1.55 | [  7.42,  13.52] |   6.77 | < .001
#> 
#> # Random Effects
#> 
#> Parameter                     | Coefficient |   SE |         95% CI
#> -------------------------------------------------------------------
#> SD (Intercept: Subject)       |       24.74 | 5.84 | [15.58, 39.28]
#> SD (Days: Subject)            |        5.92 | 1.25 | [ 3.92,  8.95]
#> Cor (Intercept~Days: Subject) |        0.07 | 0.32 | [-0.51,  0.60]
#> SD (Residual)                 |       25.59 | 1.51 | [22.80, 28.72]
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald t-distribution approximation.

Created on 2026-10-14 with reprex v2.1.1

@mattansb
mattansb requested review from jmgirard and strengejacke and a balanced review from Copilot October 13, 2026 21:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Robust covariance CIs are ignored under the new default, and three active snapshot expectations were deleted.

5 open findings
What changed in this PR

Changes linear lme4 models to default to Satterthwaite degrees of freedom when lmerTest is available.

Changes:

  • Adds lmerMod S3 wrappers selecting Satterthwaite defaults.
  • Updates tests, snapshots, documentation, and package metadata.
  • Adjusts related lavaan and random-effects tests.
File Description
R/​methods_lme4.R Implements the new defaults.
R/​1_model_parameters.R Documents Satterthwaite behavior.
NAMESPACE Registers new S3 methods.
DESCRIPTION Bumps package and roxygen2 versions.
NEWS.md Announces the breaking change.
tests/​testthat/​test-lmerTest.R Tests mixed-model defaults.
tests/​testthat/​test-random_effects_ci.R Limits assertions to random effects.
tests/​testthat/​test-lavaan.R Updates dependency and expected terminology.
tests/​testthat/​_snaps/​model_parameters.mixed.md Records Satterthwaite output.
tests/​testthat/​_snaps/​glmer.md Updates robust mixed-model output.
man/​p_value.Rd Updates generated documentation.
man/​model_parameters.Rd Updates generated documentation.
man/​model_parameters.glmmTMB.Rd Updates generated documentation.
man/​model_parameters.default.Rd Updates generated documentation.
man/​model_parameters.brmsfit.Rd Updates generated documentation.
man/​ci.default.Rd Updates generated documentation.
Files not reviewed (6)
  • man/ci.default.Rd: Generated file
  • man/model_parameters.Rd: Generated file
  • man/model_parameters.brmsfit.Rd: Generated file
  • man/model_parameters.default.Rd: Generated file
  • man/model_parameters.glmmTMB.Rd: Generated file
  • man/p_value.Rd: Generated file

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/testthat/_snaps/glmer.md Resolved
Comment thread R/methods_lme4.R Resolved
Comment thread NEWS.md Resolved
Comment thread R/1_model_parameters.R Resolved
Comment thread R/methods_lme4.R Resolved
@strengejacke

Copy link
Copy Markdown
Member

There are some failing tests, related to lmerTest,

test-model_parameters_std_mixed.R, test-model_parameters.blmerMod.R, and some others fail with:

Error in `lmerTest::as_lmerModLmerTest(x)`: Unable to extract deviance function from model fit

Maybe, once lmerTest is loaded, they call the new .lmerMod methods? Maybe we should instead:

  1. Add .attempt_satterthwaite_method() to model_parameters.coxme() (because this is called for model_parameters.merMod())
  2. Inside attempt_satterthwaite_method() check whether model is of class lmerMod() and then proceed.
  3. Remove all newly added .lmerMod methods

@strengejacke

Copy link
Copy Markdown
Member

All tests for linear mixed models now should have skip_if_not_installed("lmerTest"), to make sure that tests won't fail when lmerTest is not installed

@mattansb

Copy link
Copy Markdown
Member Author

lmerMod is a subclass of merMod from {lme4} package (not from {lmerTest}, which has a lmerModLmerTest class which is a subclass of lmerMod).

.attempt_satterthwaite_method() is only ever reached if the object is an lmerMod - having .attempt_satterthwaite_method() in model_parameters.merMod() (model_parameters.coxme()) will require a lot of conditioning to get it to only work on lmerMod models, which the previous PR (#1273) did poorly.

@strengejacke

Copy link
Copy Markdown
Member

Can't we just add if (inherits(model, "lmerMod")) in attempt_satterthwaite_method()?

@strengejacke

Copy link
Copy Markdown
Member

The current implementation seems to fail for lmer-Models now, see #1276 (comment)

@jmgirard jmgirard left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a good change. I found one regression and a few smaller things.

Satterthwaite default fails when the model data is gone. If the data is not in scope, lmerTest cannot rebuild the deviance function. This happens, for example, with a model saved with saveRDS() and loaded in a new session. Then model_parameters(), ci() and p_value() error, where main gives Wald results:

library(lme4)
d <- sleepstudy
m <- lmer(Reaction ~ Days + (1 | Subject), data = d)
saveRDS(m, "m.rds")
# new session
m <- readRDS("m.rds")
parameters::model_parameters(m)
#> Error: Unable to extract deviance function from model fit

Could the default fall back to "wald" (with an alert if verbose = TRUE) when Satterthwaite fails? An explicit ci_method = "satterthwaite" can still error.

Install prompt and repeated warning without lmerTest. insight::check_if_installed() defaults to prompt = interactive(), so in an interactive session each call on an lme4 model asks to install lmerTest. The reprex also shows the warning three times for one model_parameters() call, and it ignores verbose. Maybe pass prompt = FALSE and quietly = !verbose, and warn only once per call?

Files that look committed by accident. The PR deletes 24 snapshot files (equivalence_test/*.svg, tinyplot/*.svg, include_reference.md, lcmm.md, mipo.md, plm.md, weightit.md, and others), adds tests/testthat/_snaps/glmmTMB.new.md, and removes 8 lines from man/dominance_analysis.Rd. This looks like a local devtools::test() / document() run with some Suggests packages missing. Can these be restored?

Minor. test-random_effects_ci.R now uses effects = "random", so the fixed-effect rows with ci_random = TRUE are no longer checked. Pinning the new Satterthwaite values would keep that coverage.

@strengejacke

Copy link
Copy Markdown
Member

I have updated some files and will commit soon

@strengejacke

Copy link
Copy Markdown
Member

Still not working, this is failing:
test-model_parameters_std_mixed.R

> data(iris)
> set.seed(1234)
> iris$grp <- as.factor(sample(1:3, nrow(iris), replace = TRUE))
> model <- lme4::lmer(
+   Sepal.Length ~ Species * Sepal.Width + Petal.Length + (1 | grp),
+   data = iris
+ )
> params <- model_parameters(
+     model,
+     standardize = "refit",
+     effects = "fixed",
+     vcov = "CR",
+     ci_method = "wald",
+     vcov_args = list(type = "CR1", cluster = iris$grp),
+     verbose = FALSE
+   )
Error in `lmerTest::as_lmerModLmerTest()`:
! Unable to extract deviance function from model fit

Hide Traceback
     ▆
  1. ├─parameters::model_parameters(...) at [tests/testthat/test-model_parameters_std_mixed.R:234:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
  2. ├─parameters:::model_parameters.lmerMod(...) at [parameters/R/1_model_parameters.R:395:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
  3. │ └─base::eval.parent(cl) at [parameters/R/methods_lme4.R:127:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
  4. │   └─base::eval(expr, p)
  5. │     └─base::eval(expr, p)
  6. └─parameters (local) `<fn>`(...)
  7.   ├─base::do.call(".extract_parameters_mixed", fun_args) at [parameters/R/methods_coxme.R:140:7](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
  8.   └─parameters:::.extract_parameters_mixed(...)
  9.     ├─base::suppressMessages(do.call("ci", fun_args)) at [parameters/R/extract_parameters.R:528:7](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 10.     │ └─base::withCallingHandlers(...)
 11.     ├─base::do.call("ci", fun_args) at [parameters/R/extract_parameters.R:528:7](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 12.     ├─bayestestR::ci(...)
 13.     ├─parameters:::ci.lmerMod(...) at [bayestestR/R/ci.R:70:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 14.     │ └─base::eval.parent(cl) at [parameters/R/methods_lme4.R:146:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 15.     │   └─base::eval(expr, p)
 16.     │     └─base::eval(expr, p)
 17.     └─parameters (local) `<fn>`(...)
 18.       └─parameters:::.ci_generic(...) at [parameters/R/methods_lme4.R:39:5](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 19.         └─parameters::ci_satterthwaite(model, ci = ci) at [parameters/R/ci_generic.R:44:5](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 20.           └─parameters::dof_satterthwaite(model) at [parameters/R/ci_satterthwaite.R:4:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 21.             ├─insight::get_df(model, "satterthwaite") at [parameters/R/dof_satterthwaite.R:4:3](vscode-file://vscode-app/c:/Program%20Files/Positron/resources/app/out/vs/code/electron-browser/workbench/workbench.html#)
 22.             └─insight:::get_df.lmerMod(model, "satterthwaite")
 23.               ├─insight:::.degrees_of_freedom_satterthwaite(x)
 24.               └─insight:::.degrees_of_freedom_satterthwaite.lmerMod(x)
 25.                 └─lmerTest::as_lmerModLmerTest(x)

@mattansb

Copy link
Copy Markdown
Member Author

Could the default fall back to "wald" (with an alert if verbose = TRUE) when Satterthwaite fails? An explicit ci_method = "satterthwaite" can still error.

Yes - can you think of any way other than checking if lmerTest::as_lmerModLmerTest() fails inside .attempt_satterthwaite_method()?

Maybe pass prompt = FALSE and quietly = !verbose, and warn only once per call?

But we do want them to prompted, no? I can try some trickery like this to have that specific prompt only happen once every say 8 hours?

foo <- function() {
  .last_lmerTest_prompt <- getOption(".last_lmerTest_prompt", Sys.time() - 8*3600)
  .eight_hours_ago <- Sys.time() - 8*3600

  if (.last_lmerTest_prompt <.eight_hours_ago) {
    insight::check_if_installed("zzz", stop = FALSE)
    options(.last_lmerTest_prompt = Sys.time())
  }
  invisible(NULL)
}

foo()
#> Warning: Package `zzz` required for this function to work.
#>   Please install it by running `install.packages("zzz")`.
foo()
foo()

Created on 2026-10-15 with reprex v2.1.1

Files that look committed by accident [...]

@jmgirard Can you take care of that? I'm not sure how to revert that?

Minor. test-random_effects_ci.R now uses effects = "random"

Fixed.

Still not working, this is failing:
test-model_parameters_std_mixed.R

That's related to Jeffery's first point.

@jmgirard

Copy link
Copy Markdown
Contributor

I restored tests/testthat/_snaps/model_parameters.glmgee.md (08b89db). That was the last of the accidentally deleted files. The others are no longer in the diff.

On the fallback: I do not see a better check than trying the conversion. Whether lmerTest::as_lmerModLmerTest() works depends on how the model was fit, not on its class. In the failing test-model_parameters_std_mixed.R example, the original model converts. The model refit by standardize = "refit" does not. So something like this at the end of .attempt_satterthwaite_method():

if (installed) {
  converted <- tryCatch(
    lmerTest::as_lmerModLmerTest(model),
    error = function(e) NULL
  )
  if (!is.null(converted)) {
    return("satterthwaite")
  }
}

return(fallback)

An alert for verbose = TRUE can go in the same place. The conversion builds the deviance function, so it has a cost. One conversion per call is better than one in each of ci(), p_value() and the other methods.

That example also has a second problem. It passes ci_method = "wald" and still ends up in Satterthwaite. When vcov is given, .extract_parameters_mixed() calls ci() without method = ci_method (the if (!is.null(vcov)) branch in R/extract_parameters.R). So ci.lmerMod() picks the new default. I expect that adding method = ci_method to those fun_args fixes that case, but I tested only the ci() call. With method = "wald", ci() on the refit model with vcov = "CR" runs without error. Without method, the same call fails with "Unable to extract deviance function".

@mattansb

Copy link
Copy Markdown
Member Author

Okay I think I have it resolved now - this is the logic and it seems to work:

  1. If {lmerTest} is installed, try to convert the model to a class lmerModLmerTest. This object will be passed along so it will only hopefully be coerced once (very cheap, very cost effective)

Then, for setting the ci_method:

.attempt_satterthwaite_method <- function(
  method,
  model,
  effects,
  fallback = "wald",
  bootstrap = FALSE,
  verbose = TRUE
) {
  # Cases where we don't want to interfere
  if (!is.null(method) || effects == "random" || isTRUE(bootstrap)) {
    return(method)
  }

  if (inherits(model, "lmerModLmerTest")) {
    return("satterthwaite")
  }

  # Then the model is DEFNITLY NOT coercible because we already tried to coerce it
  if (requireNamespace("lmerTest", quietly = TRUE)) {
    return(fallback)
  }

  # Model is potentially coercible if lmerTest were installed?
  installed <- insight::check_if_installed(
    package = "lmerTest",
    reason = "for Satterthwaite df (default)",
    stop = FALSE,
    prompt = interactive() && isTRUE(verbose)
  )

  # This is a workaround for the fact that check_if_installed() returns FALSE
  # even if the package is not installed, but the user chooses to install it. In
  # that case, we need to check again if the package is actually installed.
  if (!installed) {
    installed <- requireNamespace("lmerTest", quietly = TRUE)
  }

  # if lmerTest is newly installed, and the model is coercible...
  if (installed && inherits(.attempt_to_lmerModLmerTest(model, "lmerModLmerTest"))) {
    return("satterthwaite")
  }

  return(fallback)
}

I also pass ci_method to all ci() calls in .extract_parameters_mixed() - take a look at tell me if this is what you meant.


I don't know why (locally) snapshots for the CI method for random effect has changed. @strengejacke any idea where this is happening?

Snapshot of code has changed:
old[18:22] vs new[18:20]
    
    Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
      using a Wald t-distribution with Satterthwaite approximation.
-     Uncertainty intervals for random effect variances computed using a Wald
-     z-distribution approximation.

We're so close guys I can taste it! (Had I know it would be this hard I probably wouldn't have attempted this PR 😅)

mattansb and others added 3 commits October 16, 2026 00:26
… CIs

- The lmerMod wrappers share one helper. It uses Satterthwaite df when no
  method is given and lmerTest is installed. If that fails (for example, a
  saved model whose data is gone), it runs the call again with the merMod
  default and shows a message. Errors that the default method also raises are
  reported unchanged.
- The wrappers no longer coerce the model to lmerModLmerTest. insight::get_df()
  coerces it anyway, and keeping the lmerMod class restores the footer line
  about random effect variances.
- No install prompt; the lmerTest check respects verbose.
- Satterthwaite CIs now use a robust vcov when one is given, and
  .extract_parameters_mixed() passes ci_method as `method` to the nested ci()
  and p_value() calls.
- The random effect variance footer also shows for lmerModLmerTest models.
- Tests for robust vcov, the fallback without model data, and missing lmerTest.
@jmgirard

Copy link
Copy Markdown
Contributor

@mattansb I pushed a commit (160dabf) that fixes the remaining issues from my review. Please pull before your next change.

What changed:

  • The four lmerMod wrappers share one helper, .eval_satterthwaite_default(). If no method is given and lmerTest is installed, it uses Satterthwaite. If that fails, for example for a model saved with saveRDS() whose data is gone, it runs the call again with the merMod default and shows a message. If the default also fails, you get the original error.
  • The wrappers no longer convert the model to lmerModLmerTest. insight::get_df() converts it anyway. This also answers your snapshot question: the footer line about random effect variances checks for the class lmerMod, so it disappeared after the conversion. I also added lmerModLmerTest to that check in format.R.
  • No install prompt, and the lmerTest message respects verbose.
  • Robust vcov: passing ci_method to ci() did not work, because ci.lmerMod() reads method. .extract_parameters_mixed() now passes method = ci_method to the nested ci() and p_value() calls. The Satterthwaite branch of .ci_generic() now passes vcov on. The FPC snapshots in glmer.md changed: the CIs now use the robust SE.
  • Docs and NEWS describe when the default applies and the fallback.
  • New tests in test-lmerTest.R cover the robust vcov, the fallback when the data is gone, and a missing lmerTest.

The mixed-model tests pass locally. test-mipo.R and the Bayes test in test-standardize_parameters.R fail on this branch with or without my commit, so they are not caused by it.

@mattansb

Copy link
Copy Markdown
Member Author

Okay, I'm now thinking we're over engerring this. Going back to the main justification for this change - having model_parameters() match summary(), maybe we can:

  • Limit the default ci_method = "satterthwaite" to lmerTest::lmer() models only.
  • For other lmerMod models (specifically lme4::lmer()) issue a (warning? A message?) suggestion to set ci_method = "satterthwaite"

I think this will both save a lot of checking on our side and will be more aligned with the user's behavior (if they chose to use lme4::lmer() instead of lmerTest::lmer()...)

What do you think @jmgirard ?

@jmgirard

Copy link
Copy Markdown
Contributor

@mattansb Agreed, let's limit the default to lmerModLmerTest. One more reason for it: right now the result for an lme4::lmer() model depends on whether lmerTest happens to be installed.

Since lmerTest fits already store what Satterthwaite needs, most of the fallback in .eval_satterthwaite_default() should become unnecessary, and the lmerMod wrappers can become lmerModLmerTest methods. A quick test with the data dropped after fitting would confirm that.

I'd keep the method = ci_method pass-through in .extract_parameters_mixed() (otherwise vcov = "CR" still overrides an explicit ci_method = "wald" for lmerTest fits) and the format.R footer fix.

For the lme4::lmer() suggestion, I'd use a message rather than a warning, shown once per session and only when ci_method isn't set and verbose = TRUE.

Some of these are reverted back to the orig tests
@mattansb

Copy link
Copy Markdown
Member Author

Okay, done!

These are the only tests that are failing - @jmgirard maybe you can figure those out?

image

- The robust vcov test now fits the model with lmerTest::lmer(), because
  lme4::lmer() models no longer get Satterthwaite by default.
- The "message once" test resets the option first, because an earlier test
  in the same session can already have shown the message.
- The printing test for compare_parameters() expects the profile CI for the
  glm, because ci_method now defaults to the model's own method.
- Fix typos in the lmerMod message.
- Update the compare_parameters() help page for the new ci_method default.
@mattansb

Copy link
Copy Markdown
Member Author

@jmgirard I think we can merge this!

@jmgirard jmgirard left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other points from my earlier review are fixed, thanks. I found one more problem from the new ci_method = NULL default in compare_parameters(). With a Bayesian model and the default ci_method, the call now errors. On main it uses "eti".

m_lm <- lm(mpg ~ wt, data = mtcars)
m_stan <- rstanarm::stan_glm(mpg ~ wt, data = mtcars, refresh = 0)
compare_parameters(m_lm, m_stan)
#> Error: missing value where TRUE/FALSE needed

The same happens with only the Bayesian model. An explicit ci_method, such as "hdi" or "wald", still works. The cause is the check for Bayesian models: !NULL %in% c(...) is logical(0), so the if gets NA. I left a suggestion on that line. With it, the default gives the same table as ci_method = "eti", and the compare_parameters tests pass. A test with a Bayesian model and the default ci_method would catch this in the future.

Also, this PR and #1287 both set the version to 0.30.0.11, so the one that merges second needs a new version number.

Comment thread R/compare_parameters.R Resolved
Co-authored-by: Jeffrey Girard <me@jmgirard.com>
@mattansb
mattansb merged commit 497a5b7 into main Oct 20, 2026
9 of 21 checks passed
@mattansb
mattansb deleted the default-satterthwaite branch October 20, 2026 06:00
@mattansb

Copy link
Copy Markdown
Member Author

Thanks @jmgirard for all the work on this (much more than I expected...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants