Skip to content

Fix the VIFs of the zero-inflation component of glmmTMB models in check_collinearity() - #991

Merged
strengejacke merged 4 commits into
easystats:mainfrom
jmgirard:glmmtmb-zero-inflation-vif
Oct 19, 2026
Merged

strengejacke merged 4 commits into
easystats:mainfrom
jmgirard:glmmtmb-zero-inflation-vif

Conversation

@jmgirard

@jmgirard jmgirard commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

check_collinearity() gave wrong VIFs for the zero-inflation component of glmmTMB models whose zero-inflation formula differs from the conditional formula. .zi_term_assignment() called insight::get_modelmatrix() on a formula and got no "assign" attribute, so .term_assignments() fell back to the term blocks of the conditional formula.

An example is a poisson model with ziformula = ~ x2 + x1 + f, where f has three levels. With y ~ x1, main returns one row, x2, with the VIF of x1. With y ~ x1 + f, the x2 row has the VIF of x1, and the x1 row has the VIF of f. There is no f row.

What changes

  • The term blocks of the glmmTMB zero-inflation component come from model.matrix(x, component = "zi"). glmmTMB 1.1.12, the minimum in DESCRIPTION, has this argument. If the call fails, the component gets the "Could not extract model terms" alert, not the conditional blocks.
  • The zero-inflation component keeps or drops its intercept by its own formula, for glmmTMB and pscl models. Before, insight::has_intercept() decided this from the conditional formula, so ziformula = ~ 0 + x2 + x1 + f lost its x2 row.
  • If the zero-inflation component gets no VIFs with component = "all" and verbose = TRUE, a message says so. Before, the zero-inflation part was checked with verbose = FALSE and dropped with no message. glmmTMB models with ziformula = ~0 stay silent.
  • The hurdle, zeroinfl, and zerocount methods had the default verbose = verbose. If a message was due for these models on main, for example for zeroinfl(y ~ x1 | x2 + x1), the call failed with "promise already under evaluation". The default is now TRUE.

Tests

  • glmmTMB poisson models with ziformula = ~ x2 + x1 + f and the conditional formulas y ~ x1, y ~ x1 + f, and y ~ f + x2. Four more zero-inflation formulas: ~ log(x2 + 5) + x1 + f, ~ x2 * f + x1, ~ x2 + x1 + f + (1 | g), and ~ x2 + x1 + f with missing values in x2. Each VIF equals the generalized VIF computed directly from cov2cor(vcov(m)$zi), within 1e-8.
  • Zero-inflation formulas with one term, with only an intercept, and with only a random effect, for the new message, and the same with verbose = FALSE.
  • An intercept in only one of the two parts, for glmmTMB and pscl.
  • pscl zeroinfl() and hurdle() with the default verbose, and their zero-inflation VIFs against the direct computation. The VIF tests pass on main too.

The new glmmTMB tests and the pscl verbose tests fail on main and pass with this change. The full test suite has one failure, "test_performance - lavaan" in test-test_performance.R, which also fails on main with lavaan 0.7.2.

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.

🔵 Needs a closer look

Handle intercept detection for ziformula = ~1 when the conditional formula omits its intercept.

No open issues 🎉

What changed in this PR

Fixes incorrect zero-inflation VIF calculations for glmmTMB and pscl models.

Changes:

  • Uses component-specific model matrices and intercept handling.
  • Improves diagnostics and verbose behavior.
  • Adds regression tests and updates package metadata.
File Summary
tests/​testthat/​test-check_collinearity.R Adds zero-inflation regression coverage.
R/​check_collinearity.R Corrects component handling and diagnostics.
NEWS.md Documents the fixes.
DESCRIPTION Updates the development version.

Review effort: Lite

… = ~1` from its model matrix in `check_collinearity()`
@jmgirard

Copy link
Copy Markdown
Contributor Author

Copilot summary point addressed in f3924c7: for glmmTMB models with ziformula = ~1, find_formula() drops the zero-inflation formula, so the intercept check fell back to the conditional formula. With y ~ 0 + x1 + f, ziformula = ~1, component = "zero_inflated" then printed a false "Model without intercept" message (the VIFs were not affected). The check now reads the zero-inflation model matrix in that case, and a test covers it.

@strengejacke
strengejacke merged commit 0b3ca1f into easystats:main Oct 19, 2026
9 of 20 checks passed
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.

3 participants