--- title: "Using lmmix" output: rmarkdown::html_vignette bibliography: references.bib link-citations: true vignette: > %\VignetteIndexEntry{Using lmmix} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ## Model scope `lmmix` fits Gaussian linear mixed models with random effects, structured residual covariance, or both components in the same model. The package directly optimizes a profiled ML or REML objective and does not delegate estimation to another mixed-model package. This vignette focuses on practical use. The mathematical formulation, covariance parameterizations, likelihood criteria, and inference derivations are presented separately in the vignette *Estimation and inference in lmmix*. ```{r} library(lmmix) ``` ## Prepare the data The included `multicentre` data have three treatments, three measurement occasions, three centers and subjects nested within center and treatment. ```{r data-summary} str(multicentre) colSums(is.na(multicentre)) ``` The fixed, random and repeated formulas jointly determine the variables used by the analysis. Missing rows are handled with `na.omit`, `na.exclude`, or `na.fail`. The default is `na.omit`; `na.exclude` restores omitted positions in fitted values, residuals, and augmented data. ## Fit a combined covariance model This model contains a random center intercept and an AR(1) residual covariance within subject. ```{r combined-fit} fit <- lmm( data = multicentre, formula = Y ~ Drug * Time, random = ~ 1 | Center, repeated = ~ Time | Center:Drug:Subject, structure = "ar1", method = "REML", ddf = "satterthwaite" ) fit ``` The three formulas have distinct roles: | Argument | Role in the fitted model | |:--|:--| | `formula` | Defines the response and fixed-effects matrix `X` | | `random` | Defines the random-effects matrix `Z` and grouping factor for `G` | | `repeated` | Defines the ordering variable and independent blocks for `R` | For the residual structures other than `id`, each repeated-measures group must have at most one observation per ordering value. ## Inspect convergence before inference The optimizer code and Hessian diagnostic are part of the fitted object. ```{r convergence} fit$convergence[c( "code", "message", "optimizer", "iterations", "hessian_positive_definite" )] fit$convergence$attempts ``` A nonzero convergence code or a non-positive-definite likelihood Hessian requires investigation before interpreting standard errors or denominator degrees of freedom. The fitting function emits a warning in either case. ## Fixed effects and type III tests `summary()` combines coefficient-level inference, type III tests, covariance parameters and information criteria. ```{r summary} summary(fit) ``` Individual components are also available through standard methods. ```{r inference} fixef(fit) vcov(fit) anova(fit) confint(fit) confint(fit, parm = "theta_") ``` `anova()` performs type III fixed-effect tests for one model. With multiple models it performs likelihood-ratio comparisons, automatically refitting REML models with ML when their fixed effects differ. Satterthwaite, Kenward-Roger, and residual denominator degrees of freedom are available. Kenward-Roger is restricted to REML fits. ```{r kenward-roger-and-comparison, eval=FALSE} fit_kr <- lmm( data = multicentre, formula = Y ~ Drug * Time, random = ~ 1 | Center, repeated = ~ Time | Center:Drug:Subject, structure = "ar1", ddf = "kenward-roger" ) fit_reduced <- lmm( data = multicentre, formula = Y ~ Drug + Time, random = ~ 1 | Center, repeated = ~ Time | Center:Drug:Subject, structure = "ar1" ) anova(fit_reduced, fit) # Use a simulated null reference for a covariance comparison. anova( smaller_ml_fit, larger_ml_fit, test = "parametric.bootstrap", nsim = 999, seed = 2026 ) ``` ## Covariance parameters and random effects `VarCorr()` returns the estimated covariance components on their natural scale. `ranef()` always returns a named list with one tibble per random term. This stable contract also applies when the model has only one random term; a marginal model returns an empty list. ```{r covariance} VarCorr(fit) ranef(fit) ranef(fit)[[1L]] ``` For a random-slope model, the random-effect covariance is unstructured. Its variances and correlations appear as separate rows in `VarCorr()`. ## Estimated marginal means Marginal means use equal weights over nuisance-factor levels. Numeric covariates not requested in `specs` are held at their observed means. This construction targets population marginal means in the sense of @searle1980. ```{r lsmeans} lsmeans(fit, ~Drug) lsmeans(fit, ~Time) ``` Pairwise contrast matrices are generated automatically. The `adjust` argument is passed to `stats::p.adjust()`. When p-values are adjusted, `conf_adjust = "auto"` reports simultaneous Bonferroni confidence intervals. Use `conf_adjust = "none"` for pointwise intervals. ```{r pairwise} lsmeans(fit, pairwise ~ Drug, adjust = "holm") ``` Reference values for numeric covariates can be overridden with `at`: ```{r at-example, eval=FALSE} lsmeans(fit, ~Drug, at = list(Time = "2")) ``` When `emmeans` is installed, `lmmix` supplies the required fixed-effects basis and model-specific denominator degrees of freedom. ```{r emmeans, eval=requireNamespace("emmeans", quietly = TRUE)} emmeans::emmeans(fit, ~Drug) ``` ## Predictions, residuals and tidy output Conditional fitted values include empirical random effects. Marginal fitted values use fixed effects only. ```{r predictions} head(fitted(fit, type = "conditional")) head(fitted(fit, type = "marginal")) head(residuals(fit, type = "pearson")) ``` For `predict(fit, newdata)`, known grouping levels receive their fitted random effect. New groups cause an error unless `allow.new.levels = TRUE` is supplied; when allowed, their random contribution is zero. Use `re.form = NA` or `re.form = ~ 0` for fixed-effects-only predictions. A fitted random-effects formula, or a list of fitted formulas, selects a subset of random terms. Standard errors and intervals are available directly. Confidence intervals describe the expected response. Prediction intervals additionally include the fitted residual variance. Both condition on empirical random effects selected through `re.form`; BLUP estimation uncertainty is not added. ```{r prediction-intervals, eval=FALSE} predict(fit, se.fit = TRUE, re.form = NA) predict(fit, interval = "confidence", re.form = NA) predict(fit, interval = "prediction", level = 0.90, re.form = NA) ``` ## Simulation, updating, weights, and offsets `simulate()` draws marginal Gaussian response vectors from the fitted mean and covariance. Supplying a seed makes the result reproducible without changing the caller's random-number state. `update()` refits a modified formula or model argument. ```{r simulation-update, eval=FALSE} simulate(fit, nsim = 50, seed = 2026) update(fit, . ~ . - Drug:Time) update(fit, structure = "cs") ``` Known relative precision weights rescale the residual covariance on both sides by `diag(1 / sqrt(weights))`. Formula offsets, explicit offsets, and custom fixed-effect contrasts are also supported. ```{r weighted-offset-model, eval=FALSE} weighted_fit <- lmm( data = analysis_data, formula = response ~ treatment + offset(baseline), random = ~ 1 | subject, weights = precision, contrasts = list(treatment = "contr.sum") ) ``` ## Diagnostic plots The S3 method `plot.lmm()` returns a `ggplot2` object. Three diagnostics are available through `which`: standardized residuals against fitted values, a normal Q-Q plot, and observed against fitted values. ```{r diagnostic-plots, fig.show='hold', out.width='48%', fig.alt='Residual and normal Q-Q diagnostic plots'} plot(fit, which = "residuals") plot(fit, which = "qq") ``` Because the returned object is a `ggplot`, layers and themes can be added in the usual way. ```{r customize-plot, fig.alt='Observed values plotted against fitted values'} plot(fit, which = "fitted") + ggplot2::theme_minimal() ``` For correlated residual structures, the plotted Pearson residuals are scaled by their marginal residual standard deviations. They are not decorrelated innovations, so residual dependence should also be assessed within the repeated-measures groups. The `generics` methods return tibbles. Printed tables use readable headings without dots, such as `Std Error`, `p value`, `Conf Low`, and `Conf High`. The underlying tibbles retain the standard `broom` column names required for programmatic use. Input column names are preserved by `augment()` and `ranef()`. ```{r broom} generics::tidy(fit) generics::glance(fit) head(generics::augment(fit)) ``` ## Alternative model specifications The same interface covers marginal, random-effects and combined models. ```{r alternatives, eval=FALSE} # Marginal model with unstructured repeated-measures covariance fit_marginal <- lmm( data, response ~ treatment * time, repeated = ~ time | subject, structure = "un" ) # Random intercept and slope with independent residuals fit_random <- lmm( data, response ~ treatment + time, random = ~ 1 + time | subject, structure = "id" ) # Independent crossed random intercepts fit_crossed <- lmm( data, response ~ treatment + time, random = list( center = ~ 1 | center, subject = ~ 1 | subject ) ) # Combined random intercept and Toeplitz residual covariance fit_combined <- lmm( data, response ~ treatment * time, random = ~ 1 | center, repeated = ~ time | center:subject, structure = "toep" ) # Four-band Toeplitz covariance, including the main diagonal fit_banded <- lmm( data, response ~ treatment * time, random = ~ 1 | center, repeated = ~ time | center:subject, structure = "toep(4)" ) ``` ## Practical limits Version `0.4.0` identifies independent connected components induced by the random and repeated grouping structures. The likelihood is evaluated by factoring one covariance matrix per component and aggregating their GLS contributions. This substantially reduces work for many subject-level or nested designs. The fitted object still stores the complete dense marginal covariance, and some inference calculations remain dense. Crossed effects can connect all observations into one component. Consequently, `lmmix` is not yet a large-scale sparse mixed-model engine and does not promise a fixed observation limit. The practical cost depends on the size of the largest connected component, the number of covariance parameters, and the requested inference. Generalized responses remain outside the Gaussian model scope.