This is the 1.0 long-term-support release. It resolves the remaining open
issues, fixes a correctness bug in predictInterval() for nested random
effects, repairs and extends the shinyMer() explorer, adds a new
plotREimpact() visualization, refreshes the documentation, and tidies the
test suite for low-maintenance, long-term use.
predictInterval() gained a new.levels argument for unobserved groups.
When newdata contains a grouping level that was not in the fitted model, the
default new.levels = "zero" keeps the historical behavior (the random effect
is dropped, so the prediction rests on the fixed effects plus residual
variation). The new new.levels = "draw" instead samples each unobserved
group's effect from the estimated random-effect covariance (VarCorr), so the
interval reflects between-group uncertainty — the analogue of
brms::posterior_predict(allow_new_levels = TRUE). Observations sharing an
unobserved level share the sampled effect. The default is unchanged, so
existing results are identical.plotREimpact() function for visualizing REimpact() output (#84,
#85). Plots the weighted-average fitted value for each expected-rank bin of
a grouping factor, with confidence intervals, faceted by case. Passing a
named list of REimpact() results overlays them on shared axes so the
influence of different grouping factors (or the same factor across models)
can be compared directly — previously this required hand-assembling the data
frames. Uses a clean theme_minimal() look.plotFEsim() now highlights significant fixed effects (#85). Terms whose
interval excludes the null line are drawn in solid black and the rest in
grey, matching the convention already used by plotREsim(), on a cleaner
theme_minimal() canvas with labelled axes.shinyMer() gained a "Model Summary" tab (#78). The interactive
explorer now opens a dedicated tab summarizing the fitted model: the
modelInfo() overview (observations, grouping factors, AIC, residual
sigma), the original model call, the fixed-effect estimates, the random
effect variances/correlations (VarCorr), and the number of levels per
grouping factor (ngrps).shinyMer() can now restrict the Random / Average draw to a subset of
the data (#32). When the "Random Obs" or "Average Obs" scenario is
selected, a sidebar control lets you pick a model-frame variable and value
to filter on; the chosen case is drawn from that subset (via the existing
draw(..., varList = ) machinery), enabling much richer on-the-fly
exploration of specific cases.hsb data (student SES vs. school-mean SES)
that separates within-group and contextual effects, mirroring the easystats
modelbased "effects in context" article (cited). It demonstrates FEsim()/
plotFEsim(), wiggle() + predictInterval(), and the new plotREimpact()
on a single, self-contained model.# (so they
rendered as body text) and two sub-sections were both numbered "Step 3c";
these are corrected. The predictInterval()-vs-bootMer() comparison
figure, which no longer matched the surrounding text, has been regenerated
with the current code and now shows the methods agreeing closely. A latent
display() call (from arm, which was not attached) was qualified to
arm::display().inst/CITATION now derives its version and year from the package metadata
(rather than hard-coding a stale version), lists all package authors, and a
citation footer points users to the methodological foundations —
Gelman and Hill (2007), the arm package's sim(), and lme4 (Bates et
al. 2015). The package-level help page (?merTools) gained matching
"Influences and acknowledgements" and "References" sections.Fixed two shinyMer() defects in the "Substantive Effect" tab. The
fixed-effect impact ("wiggle") plot crashed for any non-numeric fixed
effect (object 'newvals' not found), and the numeric/factor branch used
class(x) %in% ... inside if(), which errors with "the condition has
length > 1" for multi-class objects (e.g. ordered factors) on R >= 4.2.
Both are corrected (is.numeric() dispatch, and factor/character values
now wiggle across their observed levels), and the per-case faceting index
is computed correctly. The app's data table was also migrated from the
deprecated shiny::renderDataTable() to DT::renderDT(), the server now
declares a session argument, and the substantive-effect interval uses a
correct two-sided width.
Fixed non-reproducible predictInterval() for partially-observed nested /
interaction random effects (#124). For a model such as
y ~ 1 + (1 | a / b), a prediction frame mixing observed and unobserved
levels of the interaction grouping factor (a:b) returned seed-dependent
point estimates, and batch predictions disagreed with row-by-row
predictions. The mapping from the random-effect model matrix back to a
grouping level used max.col(), which returns a column even for an all-zero
row (an unobserved interaction level) and breaks the resulting tie at
random — so an unobserved level silently borrowed a randomly chosen
observed level's random effect. All-zero rows are now detected and routed
through the existing new-level path, which zeroes that random-effect term's
contribution so the prediction falls back to the fixed effects plus any
observed higher-level random effects, exactly as the out-of-sample warning
describes. Observed-level predictions are bit-for-bit unchanged.
Restored single RNG stream in predictInterval(). The refactor of
predictInterval() into component helpers inadvertently had each helper
(simulate_random_effects(), simulate_fixed_effects()) call
set.seed(seed) internally when invoked from the main function, resetting
the RNG stream mid-call. This produced numerically different output for
any user-supplied seed compared to CRAN releases. Fixed by passing
seed = NULL from predictInterval() to the helpers; the outer
set.seed(seed) now pins a single, sequential stream (sigma → random
effects → fixed effects → residuals) exactly as before the refactor.
Verified against origin/master with a 16-case harness: 14 of 16 cases
are now bit-for-bit identical to master, and the remaining 2 differ only
by the intentional GLMM binomial-residual simulation fix below.
Fixed parse error caused by debug statements inserted mid-function call in predictInterval()
(now correctly handles the function call structure)
Fixed GLMM residual variance simulation to properly return NULL for all GLMM/NLMM models (no Gaussian residual variance exists for discrete distributions)
Added !is.null(sigma_vec) checks in combine_components() to handle cases where
GLMMs don't have Gaussian residual variance to add (prevents errors with sigma_vec = NULL)
Removed seed parameter from simulate_residual_variance() (seeds are now handled at the
predictInterval() level for reproducibility)
Updated test expectations to reflect that GLMMs return NULL from simulate_residual_variance()
Replaced bare subbars() with reformulas::subbars() in the random-effect
prediction path to resolve the deprecation warning from lme4, which has
migrated subbars to the reformulas package.
Fixed predictInterval() on models with multiple random-effect term
blocks per grouping factor (#118). Models using the double-bar syntax
((x + y || g)), explicit splits ((1|g) + (0 + x|g)), or mixed
correlated + uncorrelated specs previously failed with
Error in dimnames(reMatrix) <- *vtmp* : 'dimnames' applied to non-array
because lme4::ranef(..., condVar = TRUE) returns postVar as a list
of per-block arrays in those cases, and the level-filtering code
assumed a 3-D array. simulate_random_effects() now normalizes the
list to a single block-diagonal array (zero off-diagonals between
uncorrelated blocks, preserving full covariance within correlated
blocks) before indexing, so the mvtnorm::rmvnorm() path sees the
mathematically correct joint posterior covariance. Correlated-only
models are unaffected (guarded by is.list() check).
Fixed averageObs() / findFormFuns() on matrix-LHS models (#83).
averageObs(gm1) previously errored on two-column binomial GLMMs such
as glmer(cbind(successes, failures) ~ ..., family = binomial) because
collapseFrame() attempted to take the mean of the matrix response
column, and a latent bug in the weights-selection path tried to index a
(weights) column that does not exist in the model frame for cbind
specifications. Matrix response columns are now detected and dropped
before averaging. Behavior change: for matrix-LHS models the
returned frame no longer contains the response column; for scalar-LHS
models the response is still included as before. Callers that key off
column count or column names from averageObs() should treat
matrix-LHS output as predictors-only. The output remains valid
newdata for predict() and predictInterval(), which ignore the
response column.
rnorm(N, yhat, sigma) from gamma-distributed sigmasimulate_glmm_response() (binomial/poisson/gamma)include.resid.var = TRUE and GLMM with type = "probability": Simulates from conditional
distribution (theoretically correct for discrete distributions)include.resid.var = TRUE and GLMM with type = "linear.prediction": Returns linear
predictor without Gaussian noise (correct behavior - GLMMs don't have additive Gaussian noise)tests/comparisons/predictInterval-regression.R, a standalone
cross-version numeric regression harness. It pins a canonical set of LMM
and GLMM inputs — covering which, level, stat,
ignore.fixed.terms, fix.intercept.variance, and single-row-newdata
cases — and serializes predictInterval() output to an RDS bundle so
two package versions can be compared bit-for-bit via a diff subcommand.
Invoke it whenever touching simulation internals to confirm the change
does not silently alter user-facing numeric output. See the README for a
worked git worktree-based workflow.tests/testthat/helper-seed.R that sets RNGversion("4.1.0") and an
explicit RNGkind(). This prevents silent stream differences across
R-oldrel / R-release / R-devel on CI.Config/testthat/parallel: false).
File-level set.seed() behaves unpredictably under parallel workers
with separate RNG state, which was the root cause of several of the
intermittent CI failures observed during the 0.9.0 development cycle.11213 for consistency, preserving a single
differing seed in two tests that explicitly assert that different seeds
produce different results.thetaExtract() test in test-helpers.R from a brittle
numeric-equality check against a value calibrated to an older seed, into
behavioral assertions (type, length, bounds).actions/checkout to @v5 and set
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true on both workflows to address
the GitHub Actions Node.js 20 deprecation (scheduled for 2026-09-16).Refactored predictInterval() into modular component functions for improved maintainability and testability. The main function now orchestrates five internal helper functions:
simulate_residual_variance() - Draws residual standard deviation samples from the posteriorsimulate_fixed_effects() - Simulates fixed effect predictions with proper variance-covariance handlingsimulate_random_effects() - Simulates random effect contributions for all grouping factorscombine_components() - Combines fixed, random, and residual variance componentssummarise_predictions() - Computes prediction intervals from simulation resultsThis refactoring reduces the main predictInterval() function from ~520 lines to ~180 lines while preserving complete backward compatibility
Added comprehensive unit tests for all helper functions (43 new tests)
All existing tests pass without modification, ensuring numeric accuracy is preserved
predictInterval() function now clearly shows the high-level algorithm flowsimulate_random_effects()predictInterval()vctrs package impacting dplyr::bind_rows() usage in REsim (#133)vcov in the merDeriv packageaes_string() calls (#127)broom to broom.mixed because of upstream package reorganizationaverageObs could not be calculated when model weights were specified in the
original model (closes #110)subBoot now works with glmerMod objects as wellreMargins a new function that allows the user to marginalize the prediction over breaks in the
distribution of random effect distributions, see ?reMargins and the new reMargins vignette (closes #73)merModLists is now supported using the future.apply
package and the future_lapply functions, optionallySuggests fieldpredictInterval() would return a data.frame of the
wrong dimensions when predicting a single row of observations for a glmrstanarm dependencies in the package vignettedontrun to donttest for long-running examples (CRAN compliance)merModList objects (#92)merModList functions now apply the Rubin
correction for multiple imputationfixef and ranef generics for merModList objectsfastdisp generic for merModListsummary generic for merModListprint generic for merModListmerModList including examples and a new
imputation vignettemodelInfo generic for merMod objects that provides simple summary
stats about a whole modelstd.error of a multiply imputed merModList
when calling modelRandEffStatsREimpact where some column names in newdata would prevent the
prediction intervals from being computed correctly. Users will now be warned.wiggle where documentation incorrectly stated the arguments to
the function and the documentation did not describe function correctlyreadme.rmd to package graphics with the R package, per CRANmerMod has functions specified
in the formula, the draw and wiggle functions will check for this and attempt
to respect these variable transformations. Where this is not possible a warning
will be issued. Most common transformations are respected as long as the the
original variable is passed untransformed to the model.predictInterval that allows the user to return the full
interval, the fixed component, the random component, or the fixed and each random
component separately for each observationrstanarm to the VignetteexpectedRank output more tidy like and allow function to calculate
expected rank for all terms at once
plyr and replace with dplyrvarList will now throw an error if == is used instead of =predictInterval did not included random effects in calculations
when newdata had more than 1000 rows and/or user specified parallel=TRUE.
Note: fix was to disable the .paropts option for predictInterval ... user
can still specify for temporary backward compatibility but this should be
either removed or fixed in the permanent solution.predictInterval when only specific levels
of a grouping factor are in newdata with the colon specification of
interactionslme4 to ensure compatibility with latest changes.dplyr tbl and tbl_df objects to data.frames when they are passed
to predictInterval and issue a warningnewdata in predictInterval before
failing if coercion is unsuccessfulpredictInterval which includes better
handling of large numbers of parameters and simulations, performance
tweaks for added speed (~10x), and parallel backend support (currently not optimized)probit models and limited support for other glmm link functions, with warning (still do not know how to handle sigma parameter
for these)blmer objects from the blme packagemerModList object for lists of merMod objects fitted to subsets
of a dataset, useful for imputation or for working with extremely large datasetsprint method for merModList to mimic output of summary.merModVarCorr method for merModListn.sims for the predictInterval function from 100 to 1,000
to give better coverage and reflect performance increaselevel in predictInterval to be 0.8 instead of 0.95
to reflect that 0.95 prediction intervals are more conservative than most users
needpredictInterval to allow prediction intervals from glmer and lmer
objectsFEsim and REsim to extract distributions of model parametersshinyMer an interactive shiny application for exploring lmer
and glmer modelsexpectedRank function to interpret the ordering of effectsREimpact to simulate the impact of grouping factors on the outcomedraw function to allow user to explore a specific observationwiggle function for user to build a simulated set of counterfactual
cases to explore