Skip to content

glmmTMB ordinal support - #1221

Merged
strengejacke merged 9 commits into
mainfrom
strengejacke/issue1220
Sep 16, 2026
Merged

strengejacke merged 9 commits into
mainfrom
strengejacke/issue1220

Conversation

@strengejacke

Copy link
Copy Markdown
Member

Fixes #1220

@jmgirard

jmgirard commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for starting this! Two things I noticed testing it on the wine data:

  1. In get_parameters(), out[-1, ] runs after the thresholds are prepended, so it drops 1|2 and keeps (Intercept).
  2. The threshold rows of vcov(full = TRUE) are on glmmTMB's internal softmax scale, so the SEs don't match clm (0.99 vs 0.55 for 1|2); they need the delta method (see Standard errors of category threshold parameters for the new ordinal family glmmTMB/glmmTMB#1323).

I have a branch that handles both, plus get_statistic() (which currently errors on the row-count mismatch with summary()), get_predicted() via type = "probs" with clm-style intervals, get_variance() (latent residual variance, as for clmm), and tests against clm/clmm:

main...jmgirard:insight:glmmtmb-ordinal

Happy to open it as a PR, or you can cherry-pick from it into this one, whichever you prefer. One thing on the parameters side: .se_fixed_effects_glmmTMB() takes SEs from coef(summary()), which lacks the thresholds, so model_parameters() errors; falling back to insight::get_varcov() for the ordinal family would fix it.

Thresholds are stored by glmmTMB as softmax-parameterized family
parameters (psi) and the intercept is fixed to zero via an internal map.
To match ordinal::clm()/clmm(), find_parameters() and get_parameters()
now return the thresholds ahead of the slopes and drop the intercept,
get_varcov() transforms the covariance matrix to the threshold scale
with the delta method, get_statistic() derives Wald statistics from it
(it previously errored on the row-count mismatch), and get_predicted()
returns per-category probabilities via predict(type = "probs") for
"expectation" and the most likely category for "classification".
strengejacke and others added 2 commits September 8, 2026 07:55
Clears the two lint-changed-files diagnostics and the one spelling
error introduced by the glmmTMB ordinal() support. The remaining
lints and spelling words in these checks predate this branch.
@strengejacke

Copy link
Copy Markdown
Member Author

Great, thanks a lot! Let me check how get_parameters.glmmTMB() handles ordinal families, and if this is in line with ordinal::clm() and similar (i.e. thresholds are also returned).

Also, I noticed that vcov() for glmmTMB-ordinal returns fixed effects first, and then threshold estimates. We have to make sure this is in line with get_parameters(), so standard errors will correctly match in parameters.

@jmgirard

Copy link
Copy Markdown
Contributor

Good questions, luckily both should be covered in the branch already.

get_parameters() returns the thresholds first and then the slopes, with the same names and order as ordinal::clm()/clmm(); find_parameters(m_tmb) is identical() to find_parameters(m_clm) in test-glmmTMB-ordinal.R. For the covariance matrix, you're right that glmmTMB's vcov() puts the fixed effects first, and the threshold rows there are also on the internal softmax scale, so get_varcov() doesn't use it directly. It builds the delta-method matrix itself (R/utils_glmmtmb_ordinal.R) in the same order as get_parameters(), and the tests check the SEs against clm()/clmm(). On the parameters side, easystats/parameters#1253 takes SEs from get_varcov() matched by name, so model_parameters() matches clmm() column for column there as well.

On CI: the ordinal work is lint- and spelling-clean now; what's still red comes from main (the brms tests on Windows, styling on test-brms_dpars.R, and the older lints and spelling words). Happy to help clean those up in a separate PR if useful.

@strengejacke

Copy link
Copy Markdown
Member Author

Short note: Please don't focus too much on CI-tests, they're not fully reliable, AFAIK, and also yield some false-positives. Main formatting is now done by air, so not all lintr-comments must be followed (although there are always some useful comments).

@strengejacke

Copy link
Copy Markdown
Member Author

Let me start a copilot review, I'll also review this PR later in office.

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

Unresolved moderate issues affect prediction dispatch, covariance transformation, and prediction argument forwarding.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds glmmTMB::ordinal() support across parameter extraction, covariance/statistic calculations, predictions, and variance estimates.

Changes:

  • Adds threshold-aware parameters and delta-method covariance handling.
  • Supports probability and classification predictions.
  • Adds tests and documentation updates.
File summaries
File Summary / review note
tests/testthat/test-glmmTMB-ordinal.R Adds ordinal model coverage.
R/utils_glmmtmb_ordinal.R Adds ordinal helpers; moderate issue with forwarding prediction arguments.
R/get_varcov.R Adds ordinal covariance handling; moderate issue with supplied robust covariances.
R/get_statistic.R Adds ordinal Wald statistics.
R/get_predicted_mixed.R Adds ordinal prediction dispatch; moderate issue missing the expected alias.
R/get_parameters_mixed.R Adds threshold parameter extraction.
R/find_parameters_mixed.R Adds ordinal parameter discovery.
R/compute_variances.R Adds ordinal variance handling.
NEWS.md Documents ordinal support; nit regarding placement under the development section.
inst/WORDLIST Adds softmax vocabulary.
Review details

Suppressed comments (2)

R/get_predicted_mixed.R:120

  • expected is an established alias that .get_predicted_args() normalizes to expectation (R/get_predicted_args.R:108-110), but it is absent from this dispatch list. Consequently, get_predicted(x, predict = "expected") skips this ordinal handler and the generic glmmTMB path returns a transformed scalar link prediction rather than the per-category probability table. Include expected here.
    ordinal_types <- c(
      "expectation",
      "expected",
      "response",
      "prediction",

R/utils_glmmtmb_ordinal.R:138

  • This ordinal path drops the ... arguments before calling predict(), even though get_predicted.glmmTMB() forwards those arguments for other families and the public API documents them as prediction-method arguments. Options such as na.action or other supported predict.glmmTMB() controls are therefore silently ignored for ordinal models; preserve the remaining dots when constructing this call while overriding the arguments managed by insight.
  rez <- stats::predict(
    x,
    newdata = my_args$data,
    type = "probs",
    re.form = my_args$re.form,
    allow.new.levels = my_args$allow_new_levels,
    se.fit = !classification
  • Files reviewed: 10/10 changed files
  • Comments generated: 2
  • Review effort level: Lite

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

Comment thread R/get_varcov.R
Comment thread NEWS.md
jmgirard added a commit to easystats/parameters that referenced this pull request Sep 11, 2026
insight 1.5.4 was released to CRAN without the ordinal support, so the
previous floor (1.5.3.2) no longer enforces easystats/insight#1221.
…rward dots

insight 1.5.4 was released without the ordinal support, so the NEWS
entry moves from the released section to (devel). get_varcov() now
rejects supplied covariance matrices for the ordinal family explicitly
(they would be on the internal softmax scale), and the ordinal
prediction path forwards remaining dot-arguments to predict(), as the
other families do.
@strengejacke

Copy link
Copy Markdown
Member Author

Great, thanks a lot! Looks good to me!

@strengejacke

Copy link
Copy Markdown
Member Author

Will run a final local check, and then merge

@strengejacke
strengejacke merged commit 23013e9 into main Sep 16, 2026
13 of 19 checks passed
@strengejacke
strengejacke deleted the strengejacke/issue1220 branch September 16, 2026 10:15
strengejacke added a commit to easystats/parameters that referenced this pull request Sep 16, 2026
…ight#1221) (#1253)

* fix standard errors for glmmTMB ordinal() models

The thresholds of glmmTMB's ordinal family are not part of the summary
coefficient table, so .se_fixed_effects_glmmTMB() silently recycled the
slope SEs over the thresholds (or errored when the lengths were not
multiples). Standard errors are now taken from insight::get_varcov(),
which returns them on the threshold scale via the delta method.

* require insight >= 1.5.4.1

insight 1.5.4 was released to CRAN without the ordinal support, so the
previous floor (1.5.3.2) no longer enforces easystats/insight#1221.

* Add remotes

* set versoin in NEWS

* add glmmTMB to remotes

---------

Co-authored-by: Daniel <mail@danielluedecke.de>
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.

glmmTMB ordinal support

3 participants