--- title: "Getting started with cevcmm" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with cevcmm} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 6, fig.height = 4, fig.align = "center" ) set.seed(1) ``` ## What this package fits **cevcmm** fits Varying Coefficient Mixed-Effects Models (VCMMs): $$ y_i = \beta_0(t_i) + \sum_{k=1}^{K} x_{ik}\,\beta_k(t_i) + z_i^\top \alpha + \varepsilon_i, $$ where each $\beta_k(t)$ is a smooth function of $t$ (cubic B-splines with a second-order-difference penalty), $\alpha \sim N(0, \Sigma_\alpha)$ are random effects with one of three covariance structures (`diag`, `kronecker`, `separable`), and $\varepsilon_i \sim N(0, \sigma_\varepsilon^2)$. The package implements two estimators from Jalili and Lin (2025): - **SS** (sufficient-statistics): iterates to convergence using only the aggregated summary $(a,\,b,\,C,\,Z^\top Z,\,Z^\top y,\,X^\top Z)$. Raw data is not needed once the summaries exist. - **CSL** (one-step communication-efficient): a single Newton refinement from a pilot estimator. Asymptotically equivalent to SS at a fraction of the cost when the pilot is good enough. This vignette walks through the simplest case: a single varying coefficient, diagonal random effects, all on one machine. ## Setup ```{r setup} library(cevcmm) ``` ## Simulate a small dataset $N = 500$ observations, $K = 1$ varying covariate, $q = 3$ independent random effects. ```{r simulate} set.seed(1) N <- 500L q <- 3L t <- runif(N) x <- runif(N) Z <- matrix(rnorm(N * q), N, q) beta_0 <- 2 beta_1_fun <- function(u) sin(2 * pi * u) alpha_true <- rnorm(q, sd = 0.4) sigma_eps <- 0.5 y <- beta_0 + beta_1_fun(t) * x + as.vector(Z %*% alpha_true) + rnorm(N, sd = sigma_eps) ``` ## Fit A single `vcmm()` call. With `method = "auto"` (default), CSL is picked when $N \cdot q > 10^5$ or $q > 50$; otherwise SS. This small example picks SS. ```{r fit} fit <- vcmm(y, X = x, Z = Z, t = t, method = "auto", re_cov = "diag", control = vcmm_control(sigma_eps = 0.5, sigma_alpha = 0.4, update_variance = TRUE)) fit ``` ## Inspect the fit All standard S3 methods work on a `vcmm_fit`. ```{r inspect} # Fixed-effects coefficient vector (intercept + spline basis coefs) head(coef(fit)) # Same vector, reshaped: intercept + (basis x covariate) matrix fx <- fixef(fit) fx$intercept dim(fx$varying) # Random effects ranef(fit) # Sample size and residual SD nobs(fit) fit$sigma_eps # Log-likelihood, AIC, BIC logLik(fit) AIC(fit); BIC(fit) ``` A full `summary()` includes a coefficient table with z-tests: ```{r summary} summary(fit) ``` ## Recover the varying coefficient `varying_coef()` evaluates $\hat\beta_k(t)$ at any grid with optional pointwise standard errors. ```{r curve, fig.cap = "Estimated and true varying coefficient."} t_grid <- seq(0, 1, length.out = 100L) vc <- varying_coef(fit, t_new = t_grid, k = 1L, se.fit = TRUE) plot(t_grid, vc$fit, type = "l", lwd = 2, col = "steelblue", xlab = "t", ylab = expression(hat(beta)[1](t)), ylim = range(vc$fit - 2 * vc$se.fit, vc$fit + 2 * vc$se.fit, beta_1_fun(t_grid))) polygon(c(t_grid, rev(t_grid)), c(vc$fit + 2 * vc$se.fit, rev(vc$fit - 2 * vc$se.fit)), col = adjustcolor("steelblue", alpha.f = 0.25), border = NA) lines(t_grid, beta_1_fun(t_grid), col = "red", lty = 2, lwd = 2) legend("topright", c("estimate", "truth"), col = c("steelblue", "red"), lty = c(1, 2), lwd = 2, bty = "n") ``` The estimate tracks the true $\sin(2\pi t)$ across the unit interval; the band is the pointwise 95% Wald interval. ## Predict on new data ```{r predict} new_idx <- sample.int(N, 5L) newdata <- list(t = t[new_idx], X = x[new_idx], Z = Z[new_idx, , drop = FALSE]) predict(fit, newdata = newdata) y[new_idx] ``` With `se.fit = TRUE`: ```{r predict-se} pred <- predict(fit, newdata = newdata, se.fit = TRUE) cbind(fit = pred$fit, se = pred$se.fit) ``` ## Built-in diagnostic plots `plot(fit, which = 1)` shows the varying coefficient with its confidence band; `which = 2` requires the training data and shows residual diagnostics; `which = 3` shows random-effect diagnostics. See `?plot.vcmm_fit`. ```{r plot, fig.cap = "Built-in plot.vcmm_fit panel 1."} plot(fit, which = 1) ``` ## Where to go next - **Distributed fitting** — when data lives on multiple nodes or won't fit in memory: `vignette("distributed-fitting", package = "cevcmm")`. - **Origin-destination migration** — Kronecker covariance for OD-flow data: `vignette("od-migration", package = "cevcmm")`. ## Reference Jalili, L. and Lin, L.-H. (2025). *Scalable and Communication-Efficient Varying Coefficient Mixed Effect Models: Methodology, Theory, and Applications.* arXiv:2511.12732; under review at *Journal of the American Statistical Association*.