Skip to content

drmTMB

0.7.0Package record

Distributional Regression Models Using Template Model Builder

0packages depend
719downloads / year
–test coverage
13/13flavors OK

Overview

About

Fast distributional regression models for univariate and bivariate responses using Template Model Builder. The current implementation focuses on Gaussian, Student-t, and skew-normal location-scale models, known sampling covariance, phylogenetic location effects, random-effect scale models, bivariate residual correlation, positive-continuous, 'Tweedie' semi-continuous, strict-proportion, zero-one bounded, and denominator-aware proportion families, fixed-effect Bernoulli/binomial event-probability models, and fixed-effect Poisson, negative-binomial, zero-inflated, zero-truncated, hurdle count, and ordinal cumulative-logit models. Additional response-family models are staged for later phases. Every fitted family also exposes a distributional-output and adequacy layer: randomized quantile-residual worm and QQ plots that detect fixed-effect shape and atom misspecification, and conditional-quantile, exceedance, and centile outputs with plug-in (uncalibrated) intervals.

Changes in 0.7.0

First CRAN-targeted release candidate. It was first submitted to CRAN on 24

August 2026; this resubmission candidate follows CRAN's example feedback and is

not yet accepted or available on CRAN. drmTMB fits distributional regression

models -- location, scale, shape, zero inflation, and residual correlation --

for one or two responses, using Template Model Builder.

Lognormal ordinary correlated slope

  • Complete-data ordinary lognormal() y ~ x + (1 + x | id) now has a point_fit_recovery ledger cell (mc-0720) for sd0, sd1, and group-level rho_re under the same design-17 map as Poisson (ρ = 0.999999 tanh(η)). This is not the independent-slope cell mc-0380 and not Wave 2.5 NB2 mc-0719. A slope predictor that is constant within every group now aborts before the fit (unidentified sd1 / rho_re). Gamma neighbour, REML, missing-response, labelled blocks, mixed (1 | g) + (1 + x | g), intervals, and coverage remain rejected.
Show all changes in 0.7.0Hide the rest of the changes in 0.7.0
  • **CRAN / win-builder Julia hang (post-#1061).** The ^julia invert filter correctly excluded test-julia-*.R, but test-binomial-response.R still called drmTMB(..., engine = "julia") inside expect_error(). Workflow G admits fixed-effect binomial into the Julia bridge, so that call reached JuliaCall::julia_setup() and hung Ligges R-release for ~10448s. drm_julia_setup() now hard-blocks the non-interactive CRAN lane unless DRMTMB_JULIA_TESTS=true, drm_skip_live_julia() matches the same predicate, and the obsolete binomial expect_error(engine = "julia") is replaced with a pure-R tag check.

Binomial ordinary correlated slope

  • Complete-data binomial logit cbind(success, failure) ~ x + (1 + x | id) now has a point_fit_recovery ledger cell (mc-0717) for sd0, sd1, and group-level rho_re under the log-sech Cholesky. This is not the independent-slope cell mc-0061. A slope predictor that is constant within every group now aborts before the fit (unidentified sd1 / rho_re). REML, missing-response, labelled blocks, mixed (1 | g) + (1 + x | g), intervals, and coverage remain rejected.

Poisson ordinary correlated slope

  • Complete-data Poisson log count ~ x + (1 + x | id) now has a point_fit_recovery ledger cell (mc-0718) for sd0, sd1, and group-level rho_re under the design-17 map ρ = 0.999999 tanh(η). This is not the independent-slope cell mc-0431 and not Wave 1 binomial mc-0717. REML, missing-response, labelled blocks, mixed (1 | g) + (1 + x | g), intervals, and coverage remain rejected.

NB2 ordinary correlated slope

  • Complete-data ordinary nbinom2() count ~ x + (1 + x | id) now has a point_fit_recovery ledger cell (mc-0719) for sd0, sd1, and group-level rho_re under the same design-17 map as Poisson (ρ = 0.999999 tanh(η)). This is not the independent-slope cell mc-0402 and not Wave 2 Poisson mc-0718. A slope predictor that is constant within every group now aborts before the fit (unidentified sd1 / rho_re). Zero-inflated or truncated NB2, REML, missing-response, labelled blocks, mixed (1 | g) + (1 + x | g), intervals, and coverage remain rejected.

Binomial responses accept a phylogenetic random effect

  • binomial() was the only common response family that could not take a structured random effect -- gaussian, poisson, nbinom2, Gamma and beta all accepted the identical phylo(1 | id, tree = tree) term while a binomial model aborted at the structured-effect gate (#1048). Phylogenetic logistic regression (a binary trait on a tree) is the canonical comparative-methods use of a binary response, so the hole was conspicuous. The first slice is deliberately narrow, matching how beta and zero_one_beta grew provider by provider: one unlabelled q1 phylo() intercept on mu, in either the Bernoulli or the two-column cbind(successes, failures) form. Phylogenetic slopes, labelled covariance blocks, spatial/animal/relmat providers, combination with ordinary random effects, and combination with missing-predictor mi() all refuse with explicit messages rather than fitting silently narrower models. Supporting recovery evidence (slope and sd_phylo essentially unbiased by 160 tips, Laplace small-sample attenuation ~9% at 40-80 tips) is recorded on #1048.

Fixed: penalized fits reported phylo_penalty and logLik off the optimum

  • A penalized (MAP) phylogenetic fit read its penalty from a bare obj$report(), which TMB evaluates at obj$env$last.par. After TMB::sdreport() that is a finite-difference step away from the optimum, so fit$phylo_penalty -- and therefore fit$logLik, which is -opt$objective + phylo_penalty -- were both slightly wrong. The error scaled with the penalty (order 1e-3 at sd_u = 0.5) and, being a diagnostic-time artefact, made both values depend on whether standard errors had been requested at all: the same fit at the same optimum reported different numbers under se = TRUE and se = FALSE. The practical consequence was in drm_phylo_penalty_sweep(), whose logLik column is the basis for deciding whether a coupling is data-informed or prior-shaped. The error differed per row, so it did not cancel in exactly the comparison the sweep exists to make. Estimates were never affected -- opt$par and sdreport() were always at the optimum. check_drm()'s log(sigma) clamp row had the same defect and is fixed alongside. The existing regression test could not catch this because it derived its "expected" penalty from the same bare report() call, so both sides of the assertion moved together; it now derives the expectation from parList(opt$par), and a new test asserts that se cannot move a reported estimate.

Experimental MSPL accepts probit and complementary log-log

  • estimator = "mspl" previously required binomial(link = "logit") exactly. It now also accepts binomial(link = "probit") and binomial(link = "cloglog"). Everything else about the route is unchanged: still one complete Bernoulli or grouped-binomial model, one ordinary q = 1 or correlated q = 2 grouping block, engine = "tmb", no REML, no intervals.
  • **The basis is measured, not assumed.** Kosmidis and Firth (2021, Theorem 1 with Section 3.1) prove the Jeffreys penalty yields finite estimates for any link whose working weight vanishes in both tails, which logit, probit and cloglog all do. drmTMB's own TMB-Laplace evidence: **no non-finite estimate in 43,972 completed fits**, and Wald standard errors calibrated in the identified regime (probit mean(SE)/sd(beta) in [0.946, 1.008], cloglog in [0.957, 1.027]). Artifacts under docs/dev-log/simulation-artifacts/2026-08-11-mspl-nonlogit-links/. **Scope of that measurement:** Bernoulli responses with two fixed-effect columns. Grouped-binomial and wider designs inherit the n_eff extrapolation noted below without direct measurement -- which was already true of the logit route and is not made worse here, only left unresolved for two more links.
  • **The soft-penalty scale is unchanged and is a logit constant.** c_n = 2 * sqrt(p / n_eff) comes from a delta-method argument at beta = 0 for the logit link; the same argument gives about 1.25 * sqrt(p / n_eff) for probit and 1.31 for cloglog. Using the logit constant for all three was measured to move the estimate by roughly **1% of one standard error** (at q = 1 with two fixed-effect columns; not measured at q = 2), so it is kept rather than made link-specific -- a per-link constant would define a different estimator.
  • **Know this before using it on rare events.** Under deep separation with a random slope, the standard error is frequently unavailable: vcov() and summary() return NA with a drmTMB_mspl_wald_unavailable warning rather than a fabricated number, and in the most extreme cells measured this affected the large majority of converged fits. The point estimate remains finite -- that is what the penalty is for -- but inference is not available there for any link.
  • MSPL start values now place the intercept at the link of the observed event rate instead of at zero. At beta = 0 cloglog implies an event rate of 1 - exp(-1) = 0.632, so a rare-event design previously began several log units from its own intercept; this removes a class of avoidable optimizer failures. Slopes still start at zero and the start remains deterministic and finite.

Boundary intervals are now flagged on every route

  • **confint(method = "bootstrap") warns at a variance-component or correlation boundary** (class drmTMB_bootstrap_boundary_warning, conf.status = "bootstrap_at_boundary"). The Wald and profile routes already flagged their own boundary cases; bootstrap did not, which made it the one route that could return a clean-looking interval for a target the other two warn about. **Resampling does not repair a boundary** — a percentile interval whose draws pile up at zero is reporting the constraint, not the sampling distribution.
  • The flag fires when at least 5% of retained resamples land on the bound, and requires at least 20 retained draws, because a share computed from a handful of resamples is noise rather than evidence. Calibration at R = 200: a true SD of 0 put **43%** of draws on the bound; a true SD of 0.25 put **5%** there, with a lower endpoint of exactly zero; a true SD of 0.9 put **none** there.
  • **check_drm() now states what it does not check.** It reads the fit, so a random-effect SD comfortably clear of zero passes every fit-level check while confint() still warns about that same target's interval — measured on a 10-group fit with an SD estimate of 0.1936, every check ok, and 43% of bootstrap draws on the bound. A new interval_reliability_scope note records that interval reliability is not assessed there and points at conf.status. Previously that all-clear could reasonably be read as permission to report.

Offsets in mu for every univariate family

  • offset() in the mu formula now works for **all** univariate families, not only Poisson, nbinom2(), and Bernoulli/binomial. Newly accepted: Gaussian, student(), skew_normal(), lognormal(), Gamma(), tweedie(), beta(), beta_binomial(), zero_one_beta(), and cumulative_logit().
  • **Read the offset on the family's link scale.** For log-link families it is the usual offset(log(exposure)) rate model. For identity-link families it is a known additive shift of the mean. For logit-link families it is a known log-odds shift — a calibration term, **not** an exposure; offset(log(effort)) on a logit-link family does not give a rate model.
  • A zero_one_beta() offset shifts only the interior beta component and leaves zoi/coi untouched. A cumulative_logit() offset shifts the latent location against fixed cutpoints rather than an intercept.
  • **Still rejected, deliberately:** truncated_nbinom2() and its hurdle path (both renormalise the observed mean over a restricted support, so an exposure term would not scale the reported mean — extending them needs a decision on whether the offset targets the latent untruncated rate or the observed mean), every bivariate family (no per-response offset contract yet), Gaussian sufficient-statistic aggregation, and every distributional parameter other than mu.
  • Correctness is pinned by a link-agnostic identity: a constant offset c must lower the fitted intercept by exactly c and leave every slope unchanged. tests/testthat/test-offset-families.R checks that for each family.
  • Fixes a documentation defect: the drmTMB() help previously claimed offset(log(exposure)) support for zero-truncated negative-binomial mu formulas, which the code rejected.

Live Workflow G engine = "julia" FE gate (#499)

  • Skip-safe live tests now round-trip DRM.jl's **eleven** admitted Workflow G fixtures through drmTMB(..., engine = "julia") against committed expected.toml numbers (drmTMB **0.6.0** pin). Measured locally: **11/11** pass when JuliaCall + DRM.jl are available.
  • The R bridge now admits those Workflow G fixed-effect families (Gaussian, bivariate Gaussian, Student-t, lognormal, Poisson, NB2, Gamma, Beta, Binomial) without requiring a phylo() term; large-p phylo routes for the count / non-Gaussian set remain. Beta-binomial stays gated.
  • Marshalling fixes that the live gate surfaced: expand cbind(successes, failures) into data columns, and rewrite meta_V(V = v) / drmTMB::meta_V(...) to positional meta_V(v) for DRM.jl's StatsModels parser.
  • **Claim fence:** experimental live parity for the eleven cells only — not a CRAN-default Julia engine, not closure of all of #499 (FIML / remaining honest scope stay open).

Binomial models accept probit and cloglog links (new in 0.7.0)

  • binomial(link = "probit") and binomial(link = "cloglog") now fit, alongside the existing binomial(link = "logit"). predict(), summary(), and predict_parameters() back-transform through the fitted link rather than assuming logit. Other binomial links (for example cauchit) are still rejected.
  • The link is evaluated on the **log scale** throughout (a tail-safe log-normal CDF for probit; a log1mexp form for cloglog), not by computing a probability and clamping it. This keeps accuracy in the extreme tails; see docs/design/252-binomial-link-generalisation.md §3 and inst/COPYRIGHTS.
  • **This is a fitting capability, not an interval or coverage claim.** The new links inherit binomial's existing capability-ledger evidence; no new recovery or coverage campaign was run for them, and the census is unchanged.
  • The DRM.jl bridge continues to reject probit and cloglog: DRM.jl implements the logit mean only, so engine = "julia" errors rather than silently fitting a different model.
  • **Superseded later in 0.7.0:** the maximum-softly-penalized-likelihood (MSPL) entry point was initially logit-only. It now also admits probit and complementary log-log links under the explicitly bounded, experimentally supported contract described in “Experimental MSPL accepts probit and complementary log-log” above.

Default uncertainty story

  • **Fixed effects / routine Wald targets:** start with confint(fit) (method = "wald"). It is the fastest fitted-object route when TMB::sdreport() succeeded.
  • **Random-effect SDs / variance components:** prefer confint(fit, parm = ..., method = "profile") after profile_targets(fit) lists the row as profile-ready.
  • **Boundary rows:** read profile.boundary and conf.status. A usable profile interval at a variance-component boundary warns with class drmTMB_profile_boundary_warning. That warning does **not** repair coverage; treat the interval as indicative of scale, not as a calibrated level interval (see ?confint.drmTMB Boundary intervals; D-117 evidence).
  • **No nominal-coverage-everywhere claim.** A computable interval is not coverage certification. Report a route as inference-ready only when the capability guide names that exact cell.

See also the vignette *First-week intervals: fit, profile, and boundary*.

REML capability wording now matches the callable surface

  • The capability guide now records the bounded O2 binomial REML route: one ordinary unlabelled location (mu) random intercept (mc-0060) or independent slope (mc-0062). This route is diagnostic-only despite deterministic agreement with glmmTMB(REML = TRUE); it has no recovery or coverage claim. Fixed-only, multiple-term, correlated, labelled, structured, and missing-response binomial REML remain unavailable.
  • README and ?drmTMB now state the same public non-Gaussian REML boundary without requiring the capability guide: binomial O2 only, both diagnostic-only; O3 remains package-private; mc-0227 stays public ML point_fit_recovery. Other non-Gaussian families reject REML = TRUE.
  • The retained cumulative-logit AGHQ plus Cox-Reid campaign is now identified as evidence for a package-private estimator. It does not grant a public drmTMB() fit or reader-facing reporting permission

The NEWS section is longer than shown here.

From NEWS.md in the release

Install

Health

CRAN checks
13OK
Slowest check: 21.1 min · r-oldrel-windows-x86_64
Status changes
  • OK13 OKNow
  • OK7 OK2026-09-16
Advisories

none known

Documentation

In release 0.7.0
READMEYes · 6,968 wordsVignettesYes · 32 · evaluation depends on the environmentNEWSYes · 67% structured · mentions 0.7.0Citation fileYes · computed when R runs itWebsiteYes · pkgdown
Help pages
86 (8 internal)includes a package overview page
Examples that run
100%67 run in a plain check (3 of them under a condition)
Exported functions with examples
91%
Documented parameters
91%
Return-value docs
100%
Help pages citing references
2%

Downloads

719
CRAN downloads in the past year
Rank #17,575 · ~2/day · ~60/mo
Daily download trend is not available in this view yet.
65330 days
71990 days
7191 year
Compare downloads with other packages →
Also on17 r2u1 autocran

Repository

0Stars
0Forks
159Open issues
56Open PRs
4Releases
3,699Commits
3Commit identities
License file reads as GPL-3.0 · 3,699 commits · Last activity 2026-10-17 · Default branch at 0.7.1, ahead of CRAN 0.7.0 (checked 2026-10-11)
Responsiveness
How these are sampled
PRs merged (all time)
93%
Median days to close, 50 most recently updated closed issues
24
Median days to close, 50 most recently updated closed PRs
0

Issues over time

2026-09-16 · 1552026-10-18 · 159
PracticesBeta

9 development-tooling and community-health practices detected across 6 families in the upstream repository

Checks run against github.com/itchyshin/drmtmb on 2026-10-11.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows

Governance and community (1)
Contributing guide
Docs source (3)
pkgdown

GitHub Pages site last deployed 2026-10-11 · The repository has a site deploy workflow

Reproducibility and dev environment (1)
data-raw/
Show all practicesHide 2 practices
CRAN release process (1)
cran-comments.md
Git structural (1)
.gitattributes
How this is detected·Detection ruleset v3 (2026-09-26)
AI coding toolsBeta

This repository shows signs of AI coding tools.

  • Claude Codefirst seen 2026-05-07
    Seen in the repository: .claude, .claude/agents, .mcp.json, CLAUDE.md
    Named in .Rbuildignore: .claude, .mcp.json, CLAUDE.md
    Pull request it wrote: opened by a project member
    Commits: 14 by its own account · at least 1,112 crediting it in the message
  • Codexfirst seen 2026-05-07
    Seen in the repository: .codex
    Named in .Rbuildignore: .codex
  • Cursorfirst seen 2026-08-01
    Seen in the repository: .cursor
    Named in .Rbuildignore: .cursor
    Pull request it wrote: opened by a project member
    Commits: at least 226 crediting it in the message
Shared conventions any agent may read, so they name no particular tool.
Seen in the repository: .agents, .agents/skills, AGENTS.md
Models named in its commits
  • Claude Opus 4.866 commits · Jun to Jul 2026
  • Claude Opus 5.520 commits · Oct 2026
  • Claude Fable 517 commits · Jul 2026
  • Claude Sonnet 5.513 commits · Oct 2026

Some of these counts are a minimum, because the search stopped before the oldest commits.

Counts are commits, not lines of code. Commits by a tool's accounts count once across all of its accounts. Commits crediting it are the largest count among its credit lines, a minimum.How this is detected·Detection ruleset v4 (updated 2026-09-27)

Dependencies

Declared dependencies
30 external dependencies (excludes base and recommended)

Installing drmTMB adds 6 packages (5 with compiled code, 5.7 MB of source tarballs). Heaviest: Rcpp 1.8 MB, RcppEigen 1.7 MB, rlang 766 KB.

Depends (1)
R >= 4.1.0
Imports (7)
clilifecycleMatrixmethodsstatsTMB (>= 1.9.6)utils
LinkingTo (2)
Enhances (0)
none
Reverse dependencies
0direct
0indirect

Nothing depends on this yet.

Datasets

People & History

People (1)
Author, Maintainer since 0.7.0 (2026), Copyright holder
Releases (1)
  • 0.7.0Latest
    2026-09-15 · current release
  • R
    R 4.6.0 released · 2026-04-24

Package metadata

First published
2026-09-15
Total releases
1 / 1 yrs
License
GPL (>= 3) OSI
Minimum R
≥ 4.1.0
Download size
5.5 MB

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("drmTMB")

The package provides a citation file that builds its entry when R runs it. Run citation() to see it.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for drmTMB version 0.7.0 [Data set]. HJJB, LLC. Data release v2026-10-18. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy