Skip to contents

This tour walks through the non-Gaussian distributional families available for drmTMB. The biology of each is different — what kind of response it fits, what the link does, and how to read the mu coefficient. The same symbolize(fit) interface now applies to eleven package families (drmTMB, gllvmTMB, glmmTMB, brms, lme4, MCMCglmm, sdmTMB, stats::lm / stats::glm, metafor, mgcv, phylolm); see the Roadmap article for the full capability matrix.

The non-Gaussian families covered here all use the same symbolize(fit) interface. The differences are in the LaTeX, the biological reading on each coefficient, and the assumption table. Every phrase you see below is templated from inst/extdata/*.csv — no LLM at runtime.

Every fitted number shown below — in the worked-row widgets and the coefficient readings — is a point estimate; uncertainty (confidence or credible intervals) is not displayed.

For Gaussian and bivariate Gaussian, see vignette("symbolizer-drmtmb"). For the matching pedagogy on factors and interactions, see vignette("symbolizer-factors").

library(symbolizer)
library(drmTMB)
#> 
#> Attaching package: 'drmTMB'
#> The following object is masked from 'package:base':
#> 
#>     beta

Continuous responses

Student-t — robust regression

A heavier-tailed Gaussian alternative. The nu parameter controls tail heaviness: nu large means almost Gaussian, nu small means heavy outliers tolerated. drmTMB parameterises nu on the log(nu - 2) scale so the variance is always finite.

set.seed(1); n <- 100
dat <- data.frame(
  y = rt(n, df = 5) * 2 + 10 + 0.5 * rnorm(n),
  x = rnorm(n)
)
fit <- drmTMB(drm_formula(y ~ x, sigma ~ 1, nu ~ 1),
              family = student(), data = dat)
sym <- symbolize(fit)
render_math(sym$distribution$latex)

y_i \mid \mu_i,\, \sigma_i,\, \nu_i \sim \mathrm{Student\text{-}t}(\mu_i,\, \sigma_i,\, \nu_i)

Coefficient reading on mu: identical to Gaussian — a slope on the response scale.

Lognormal — positive continuous, right-skewed

Y > 0, and log(Y) is Gaussian. Coefficients on mu live on the log-response scale, so exp(beta) is the multiplicative effect on the geometric mean of Y.

set.seed(1); n <- 100
dat <- data.frame(y = exp(rnorm(n, 2 + 0.3 * rnorm(n), 0.4)),
                  x = rnorm(n))
fit <- drmTMB(drm_formula(y ~ x, sigma ~ 1),
              family = lognormal(), data = dat)
sym <- symbolize(fit)
parameter_interpretation(sym, scale = "biological")
submodel term_label coefficient_role estimate 95% CI biological_reading
mu (Intercept) intercept 2.02 1.93, 2.11 * Baseline geometric mean of y in the reference condition is exp(2.02)
mu x slope -0.0136 -0.102, 0.0751 A unit change in x multiplies the geometric mean of y by exp(-0.0136)
sigma (Intercept) intercept -0.764 -0.903, -0.626 * Baseline level of unexplained variability on the log scale

Rows marked * have a 95% confidence interval that excludes zero (CI method: wald).

Coefficient reading on mu: a unit change in x multiplies the geometric mean by exp(beta).

Three views of the lognormal fit

as_html_three_views(sym, id = "lognormal")
Skip three-views widget

What happens for each observation i – the per-individual reading.

Coefficient reading. On the response scale, \exp(\hat\beta) is the multiplicative effect on the geometric mean (the median) of the response: a one-unit increase multiplies the median by \exp(\hat\beta).

\begin{aligned} y_i \mid \mu_i,\, \sigma_i & \sim \mathrm{Lognormal}(\mu_i,\, \sigma_i^2) \quad\Longleftrightarrow\quad \log(y_i) \mid \mu_i,\, \sigma_i \sim \mathrm{Normal}(\mu_i,\, \sigma_i^2) \\ \mu_i & = \beta_{0} + \beta_{1} \, x_i \\ \log(\sigma_i) & = \gamma_{0} \end{aligned}
where:
  • y_i — response variable  \mathbb{R}^{100}
  • x_i — continuous predictor  column of X (length 100)
  • \mu_i — conditional mean of log(Y) on the log scale; after exp, the geometric mean (median) of Y  \mathbb{R}^{100}
  • \sigma_i — scale on the log-response  \mathbb{R}^{100}
  • \beta_{0}, \beta_{1} — mu submodel coefficients  \mathbb{R}^{2}
  • \gamma_{0} — sigma submodel coefficients  \mathbb{R}^{1}
pdf_alongside_html(sym, "fig-lognormal.pdf",
                   "Lognormal regression -- three views")

Download as PDF

Gamma — positive continuous, skewed

Y > 0, log link by convention (stats::Gamma(link = "log")). Coefficients are multiplicative on the mean response, like lognormal — but the variance grows as mu^2 * sigma^2 (a roughly constant coefficient of variation), whereas lognormal sets its spread on the log(Y) scale.

set.seed(1); n <- 100
dat <- data.frame(y = rgamma(n, shape = 2, rate = 0.5),
                  x = rnorm(n))
fit <- drmTMB(drm_formula(y ~ x, sigma ~ 1),
              family = stats::Gamma(link = "log"), data = dat)
sym <- symbolize(fit)
render_math(sym$distribution$latex)

y_i \mid \mu_i,\, \sigma_i \sim \mathrm{Gamma}(\mathrm{shape} = 1/\sigma_i^2,\, \mathrm{scale} = \mu_i \sigma_i^2)

When to choose Gamma over lognormal? Gamma is a member of the exponential family (it has nice GLM properties — link, canonical form). Lognormal is fully implied by log(Y) ~ Normal, which makes some predictive plots simpler but loses the GLM toolkit.

Proportion responses

Beta — proportions in (0, 1)

Y is strictly between 0 and 1. Mean via logit link, precision via log link (large sigma means a tighter distribution around the mean).

set.seed(1); n <- 100
dat <- data.frame(y = rbeta(n, 2, 5),
                  x = rnorm(n))
fit <- drmTMB(drm_formula(y ~ x, sigma ~ 1),
              family = beta(), data = dat)
sym <- symbolize(fit)
render_math(sym$distribution$latex)

y_i \mid \mu_i,\, \sigma_i \sim \mathrm{Beta}(\mu_i \sigma_i,\, (1 - \mu_i) \sigma_i)

Coefficient reading on mu: exp(beta) is the odds ratio for the mean proportion \mu / (1 - \mu) — a Beta response is a continuous proportion in (0, 1), not a binary success/failure trial. As an illustrative example (not the fit shown below), a coefficient of 0.3 would mean a unit increase in x multiplies those odds by exp(0.3) ≈ 1.35. The fitted slope for this widget is small and the fit is U-shaped (both Beta shape parameters < 1); read the actual fitted coefficient in the widget below.

Three views of the Beta fit

as_html_three_views(sym, id = "beta")
Skip three-views widget

What happens for each observation i – the per-individual reading.

Coefficient reading. On the response scale, \exp(\hat\beta) is the odds ratio for the mean proportion: a one-unit increase multiplies the odds \mu/(1-\mu) by \exp(\hat\beta) (logit link).

Heads-up – both implied shape parameters are below 1 here (\hat\alpha = \hat\mu\hat\sigma \approx 0.098 and \hat\beta = (1-\hat\mu)\hat\sigma \approx 0.25), so the fitted Beta is U-shaped: its density piles up near 0 and 1 rather than peaking at the mean. A precision \hat\sigma < 1 does that. Worth checking whether a U-shape matches your data.

\begin{aligned} y_i \mid \mu_i,\, \sigma_i & \sim \mathrm{Beta}(\mu_i \sigma_i,\, (1 - \mu_i) \sigma_i) \\ \mathrm{logit}(\mu_i) & = \beta_{0} + \beta_{1} \, x_i \\ \log(\sigma_i) & = \gamma_{0} \end{aligned}
where:
  • y_i — response variable  \mathbb{R}^{100}
  • x_i — continuous predictor  column of X (length 100)
  • \mu_i — conditional mu of y  \mathbb{R}^{100}
  • \sigma_i — Beta precision (larger sigma -> distribution tighter around mu)  \mathbb{R}^{100}
  • \beta_{0}, \beta_{1} — mu submodel coefficients  \mathbb{R}^{2}
  • \gamma_{0} — sigma submodel coefficients  \mathbb{R}^{1}
pdf_alongside_html(sym, "fig-beta.pdf",
                   "Beta regression -- three views")

Download as PDF

Beta-binomial — overdispersed binomial counts

Y is the count of successes out of N_i trials. Specify via cbind(successes, failures). sigma controls overdispersion: large sigma approaches binomial (no overdispersion), small sigma means strong overdispersion.

set.seed(1); n <- 80
trials <- sample(5:20, n, replace = TRUE)
p <- plogis(0.5 + 0.5 * rnorm(n))
dat <- data.frame(
  successes = rbinom(n, trials, p),
  failures  = trials - rbinom(n, trials, p),
  x         = rnorm(n)
)
fit <- drmTMB(drm_formula(cbind(successes, failures) ~ x, sigma ~ 1),
              family = beta_binomial(), data = dat)
#> Warning in sqrt(diag(cov)): NaNs produced
sym <- symbolize(fit)
render_math(sym$distribution$latex)

\mathrm{cbind(successes, failures)}_i \mid N_i,\, \mu_i,\, \sigma_i \sim \mathrm{BetaBinomial}(N_i,\, \mu_i,\, \sigma_i); \mathbb{E}[\mathrm{cbind(successes, failures)}_i] = N_i \mu_i

Coefficient reading on mu: same logit reading as Beta — exp(beta) is the odds ratio for the success probability.

Count responses

Poisson — counts with no dispersion parameter

Y in {0, 1, 2, ...}, log link on the mean count rate. The Poisson family forces variance = mean; if your data show overdispersion (variance > mean), prefer nbinom2.

set.seed(1); n <- 100
dat <- data.frame(y = rpois(n, lambda = exp(1 + 0.3 * rnorm(n))),
                  x = rnorm(n))
fit <- drmTMB(drm_formula(y ~ x),
              family = stats::poisson(), data = dat)
sym <- symbolize(fit)
render_math(sym$distribution$latex)

y_i \mid \mu_i \sim \mathrm{Poisson}(\mu_i)

Coefficient reading on mu: exp(beta) is the rate ratio — a multiplicative effect on the expected count.

Three views of the Poisson fit

as_html_three_views(sym, id = "poisson")
Skip three-views widget

What happens for each observation i – the per-individual reading.

Each observation is a count; the log of the expected count may shift with the predictors.

Coefficient reading. On the response scale, \exp(\hat\beta) is the rate ratio: a one-unit increase in the predictor multiplies the expected count by \exp(\hat\beta) (log link).

\begin{aligned} y_i \mid \mu_i & \sim \mathrm{Poisson}(\mu_i) \\ \log(\mu_i) & = \beta_{0} + \beta_{1} \, x_i \end{aligned}
where:
  • y_i — response variable  \mathbb{R}^{100}
  • x_i — continuous predictor  column of X (length 100)
  • \mu_i — conditional mu of y  \mathbb{R}^{100}
  • \beta_{0}, \beta_{1} — mu submodel coefficients  \mathbb{R}^{2}
pdf_alongside_html(sym, "fig-poisson.pdf",
                   "Poisson regression -- three views")

Download as PDF

Negative binomial (nbinom2) — counts with overdispersion

Y in {0, 1, 2, ...}, log link on the mean count rate. sigma parameterises overdispersion: size = exp(sigma). Small size means highly overdispersed (much higher variance than mean); large size approaches Poisson.

set.seed(1); n <- 100
dat <- data.frame(y = rnbinom(n, size = 3, mu = exp(1 + 0.3 * rnorm(n))),
                  x = rnorm(n))
fit <- drmTMB(drm_formula(y ~ x, sigma ~ 1),
              family = nbinom2(), data = dat)
sym <- symbolize(fit)
render_math(sym$distribution$latex)

y_i \mid \mu_i,\, \sigma_i \sim \mathrm{NegBin}(\mu_i,\, \mathrm{size} = \exp(\sigma_i)); \mathrm{Var}(y_i) = \mu_i + \mu_i^2 / \exp(\sigma_i)

Coefficient reading on mu: same as Poisson — exp(beta) is the rate ratio.

Zero-truncated nbinom2 — counts that are never zero

Y in {1, 2, 3, ...}. The truncation is built into the likelihood, not a data filter. The modelled mu is the mean of the underlying untruncated distribution; the observed truncated mean is larger.

set.seed(1); n <- 100
dat <- data.frame(
  y = pmax(1L, rnbinom(n, size = 2, mu = exp(1 + 0.3 * rnorm(n)))),
  x = rnorm(n)
)
fit <- drmTMB(drm_formula(y ~ x, sigma ~ 1),
              family = truncated_nbinom2(), data = dat)
sym <- symbolize(fit)
render_math(sym$distribution$latex)

y_i \mid \mu_i,\, \sigma_i \sim \mathrm{NegBin}^{+}(\mu_i,\, \mathrm{size}=\exp(\sigma_i)); y_i \in \{1, 2, 3, \ldots\}

Coefficient reading on mu: exp(beta) is the rate ratio on the untruncated mean. The observed (truncated) mean has a different expression that depends on size.

Bivariate Gaussian — two responses jointly

For paired continuous responses with a residual correlation between them, see vignette("symbolizer-drmtmb") Section 7. The bivariate Gaussian shape is structurally different — five submodels (mu1, mu2, sigma1, sigma2, rho12) instead of two or three — and has its own dedicated section in the drmTMB vignette.

Picking a family

Six rules of thumb:

  1. Continuous, roughly symmetric, fixed scalegaussian.
  2. Continuous, symmetric, heavier tails (outliers tolerated)student.
  3. Continuous, positive, right-skewedlognormal or Gamma. Use lognormal when interpretation is naturally on the log(Y) scale (e.g., body mass, lifespan). Use Gamma when the GLM framework matters (e.g., for diagnostics).
  4. Proportion in (0, 1)beta. Count of successes out of a known number of trialsbeta_binomial.
  5. Counts with variance = meanpoisson. Counts with variance > meannbinom2.
  6. Counts that are structurally non-zerotruncated_nbinom2.

If none of these fit, check symbolizer_capabilities()symbolize() will refuse with a clear message naming what’s not yet supported.