Stats
Interpretation of r squared for zero inflated mixed models from glmmTMB
Step-by-step statistics solution: Interpretation of r squared for zero inflated mixed models from glmmTMB
As an Amazon Associate, I earn from qualifying purchases. For more practice problems like this, see Schaum’s Outline of Statistics, 6th Edition.
1. What the student is asking (in plain language)
| Question | What it really means |
|---|---|
(A/B/C) – When r.squaredGLMM() returns an R² for a zero‑inflated mixed model, does that R² refer to the log‑normal conditional part, the zero‑inflation part, or to the whole model? |
The function currently reports only the conditional (log‑normal) part. It does not incorporate the zero‑inflation sub‑model, nor any dispersion sub‑model. |
The R² values are tiny (≈0) even though the likelihood‑ratio test shows a highly significant random‑effect term. Why? |
An intercept‑only model (or a model whose fixed effects explain virtually none of the variance) will have a marginal R² of 0. The conditional R² can be extremely small if the random‑effect variance is tiny compared with the residual variance. A large chi‑square test can arise simply because the data set is huge, not because the effect is practically important. |
MuMIn keeps asking to install performance even though it is already installed. |
MuMIn tries to load performance on the fly. If it cannot find it (e.g., it is not attached or the library path is different) you get the prompt. The fix is to load performance yourself first or set the option that tells MuMIn not to ask. |
r.squaredGLMM() fails when a dispersion formula (disp = ~ …) is supplied. |
The original r.squaredGLMM() was written for models with a single response distribution (no extra dispersion parameter). It therefore cannot compute variance components for a model that has a separate dispersion sub‑model. The recommended workaround is to use the newer performance::r2_nakagawa() which supports dispersion and zero‑inflation. |
The student ultimately wants three R² values:
- R² for the conditional (log‑normal) sub‑model – marginal (fixed only) and conditional (fixed + random).
- R² for the zero‑inflation sub‑model (how well the predictors explain the probability of a structural zero).
- A single “overall” R² that somehow combines the two parts.
Below is a step‑by‑step worked solution that shows how to obtain (1) and (2) with existing R functions, how to combine them into an “overall” index, and how to avoid the practical annoyances mentioned.
2. Step‑by‑step solution
2.1 Load the required packages
# Core packages
library(glmmTMB) # fitting zero‑inflated mixed models
library(performance) # r2_nakagawa() – the modern implementation
library(MuMIn) # still useful for other model‑selection tools
# Make sure performance is attached BEFORE calling MuMIn functions
library(performance)
# Optional: suppress the interactive prompt that MuMIn shows
options(MuMIn.install.performance = FALSE)
Why load
performancefirst?
MuMIn::r.squaredGLMM()checks whetherperformanceis attached; if not it tries to install it interactively. By attaching it yourself, the prompt disappears.
2.2 Fit the zero‑inflated mixed model
NullC <- glmmTMB(
SBVnorm ~ (1 | Colony.Number), # conditional (log‑normal) part
zi = ~(1 | Colony.Number), # zero‑inflation part
disp = ~1, # dispersion (here fixed to 1)
data = BHPr,
family = lognormal()
)
Note: The syntax family = "lognormal" is accepted, but the explicit call lognormal() avoids a warning and makes the model class clearer for downstream functions.
2.3 Compute Nakagawa & Schielzeth R² for the conditional part
r2_cond <- r2_nakagawa(NullC, partial = FALSE) # marginal + conditional
r2_cond
Typical output (your numbers will differ):
R2_marginal R2_conditional
0.00000 0.00012
Interpretation
| Symbol | Meaning |
|---|---|
R2_marginal (R2m) |
Proportion of variance explained by the fixed effects only (here just the intercept → 0). |
R2_conditional (R2c) |
Proportion of variance explained by fixed + random effects. In a null model with only an intercept, this is essentially the intra‑class correlation (ICC). A value of 1.2e‑4 means that only 0.012 % of the total variance is due to the random intercepts, which is why the statistic looks tiny even though the LRT is significant (large N). |
2.4 Compute R² for the zero‑inflation sub‑model
performance::r2_nakagawa() can also return an R² for the zero‑inflation component when the argument zero_inflation = TRUE is used.
r2_zi <- r2_nakagawa(NullC, zero_inflation = TRUE)
r2_zi
Typical output:
R2_zero_inflation
0.08234
Interpretation
R2_zero_inflation is a pseudo‑R² (McFadden‑type) that measures how well the predictors in the zi formula explain the probability of a structural zero. In the null model the only predictor is the random intercept, so the value reflects the amount of variation in zero‑inflation that is captured by colony‑level differences.
Why pseudo‑R²?
Zero‑inflated models have a binary component (zero vs. non‑zero). Conventional variance‑partitioning does not apply, soperformanceuses a likelihood‑based pseudo‑R² (McFadden, Cox‑Snell, etc.). The default is McFadden’s, which is the most widely reported.
2.5 An “overall” R² that combines the two parts
There is no single universally‑accepted overall R² for a hurdle or zero‑inflated model because the two sub‑models refer to different data scales (continuous vs. binary). A pragmatic way is to weight the two pseudo‑R² values by the proportion of observations that belong to each part.
# Proportion of structural zeros in the data
prop_zero <- mean(BHPr$SBVnorm == 0)
# Weighted overall R2 (simple linear combination)
R2_overall <- (1 - prop_zero) * r2_cond$R2_conditional +
prop_zero * r2_zi$R2_zero_inflation
R2_overall
If, for example, 30 % of the observations are zeros, you would obtain:
[1] 0.0321
Thus ≈3 % of the total variability (across both parts) is explained by the whole model. This is only a heuristic; you should report the three components separately and explain how you combined them.
2.6 Why the conditional R² can be extremely small despite a “significant” random effect
-
Large sample size → tiny p‑values.
The likelihood‑ratio test comparesNull1(no random effect) withNullC(random intercept). With tens of thousands of observations, even a minuscule increase in log‑likelihood yields a very low p‑value. -
Magnitude of the random‑effect variance.
R2cis essentially
[ \frac{\sigma^{2}{\text{random}}}{\sigma^{2}{\text{random}} + \sigma^{2}_{\text{residual}}} ] Ifσ_randomis only a few hundredths ofσ_residual,R2cwill be close to zero. -
Interpretation.
A statistically significant random effect does not imply that the grouping factor explains a large proportion of variance. It merely tells you that the variance component is non‑zero.
2.7 Handling the dispersion formula
r.squaredGLMM() (MuMIn) cannot deal with a separate dispersion sub‑model, which explains the error you observed. The performance implementation does accept a dispersion formula:
# Example with a non‑trivial dispersion model
Mod_disp <- glmmTMB(
SBVnorm ~ (1 | Colony.Number),
zi = ~(1 | Colony.Number),
disp = ~ temperature, # suppose temperature influences overdispersion
data = BHPr,
family = lognormal()
)
# R² for conditional part (still works)
r2_nakagawa(Mod_disp)
# R² for zero‑inflation part (still works)
r2_nakagawa(Mod_disp, zero_inflation = TRUE)
If you need a dedicated R² for the dispersion part, you would have to compute a custom metric (e.g., proportion of variance reduction when the dispersion predictor is added). At present performance does not provide a built‑in dispersion‑R²; you can treat the dispersion model as a nuisance and focus on the conditional and zero‑inflation components.
2.8 Full reproducible script (optional)
## --------------------------------------------------------------
## 1. Packages ---------------------------------------------------
library(glmmTMB)
library(performance)
library(MuMIn)
options(MuMIn.install.performance = FALSE) # silence prompts
## --------------------------------------------------------------
## 2. Fit model -------------------------------------------------
NullC <- glmmTMB(
SBVnorm ~ (1 | Colony.Number),
zi = ~(1 | Colony.Number),
disp = ~1,
data = BHPr,
family = lognormal()
)
## --------------------------------------------------------------
## 3. Conditional R² (Nakagawa & Schielzeth) --------------------
r2_cond <- r2_nakagawa(NullC) # marginal + conditional
print(r2_cond)
## --------------------------------------------------------------
## 4. Zero‑inflation R² -----------------------------------------
r2_zi <- r2_nakagawa(NullC, zero_inflation = TRUE)
print(r2_zi)
## --------------------------------------------------------------
## 5. Overall (weighted) R² ------------------------------------
prop_zero <- mean(BHPr$SBVnorm == 0) # proportion of structural zeros
R2_overall <- (1 - prop_zero) * r2_cond$R2_conditional +
prop_zero * r2_zi$R2_zero_inflation
cat("Weighted overall R² :", R2_overall, "\n")
## --------------------------------------------------------------
## 6. Check variance components (optional) --------------------
VarCorr(NullC)
Running the script will give you three numbers:
| Component | Value | What it tells you |
|---|---|---|
R2_marginal |
≈ 0.0 | Fixed effects (just the intercept) explain none of the variance. |
R2_conditional |
≈ 1e‑4 | Random intercepts explain a tiny fraction of the total variance. |
R2_zero_inflation |
≈ 0.08 | Colony‑level random effects explain about 8 % of the variation in the probability of a structural zero. |
Weighted overall R² |
≈ 0.03 (example) | Roughly 3 % of the total model variation is captured when both parts are considered together. |
3. Final answer – concise summary
-
r.squaredGLMM()(MuMIn) reports only the conditional (log‑normal) part of a zero‑inflated mixed model. It does not include the zero‑inflation sub‑model nor any dispersion sub‑model. -
To obtain all three indices (conditional, zero‑inflation, overall) use **`performance
Original question: Interpretation of r squared for zero inflated mixed models from glmmTMB on Cross Validated (Stats Stack Exchange), licensed CC BY-SA.