pecme

Penalized ECME Estimation for Censored Linear Mixed Models

pecme fits Gaussian random-intercept linear mixed models

Y*ij = xij’β + bj + eij,   eij ~ N(0, σ2),   bj ~ N(0, σb2)

where the response Y* may be left-, right-, or interval-censored, and/or completely missing, using the ECME algorithm (Liu & Rubin, 1994), with simultaneous penalized variable selection for beta: none, lasso, adaptive (Adaptive Lasso), scad, mcp, elastic (Elastic Net), ridge.

Installation

# from a local checkout / the unzipped source tree:
install.packages("devtools")
devtools::document("path/to/pecme")   # regenerates NAMESPACE/man from
                                       # the roxygen comments already in R/
devtools::install("path/to/pecme")

The package should be checked locally with R CMD check, and the test suite can be run with testthat::test_dir("tests/testthat") before use in a final analysis.

Quick start

library(pecme)

sim <- simulate_pecme_data(
  n_groups = 40, n_per_group = 10, p = 12, n_active = 4,
  beta_active = 1.8, sigma = 0.6, sigma_b = 0.5,
  censor_type = "left", censor_prob = 0.2, seed = 1
)

fixed <- reformulate(paste0("x", 1:12), response = "y")

# one fit at a fixed lambda
fit <- pecme(fixed, random_var = "group", data = sim$data,
             censor = "censor", left = "left", right = "right",
             penalty = "lasso", lambda = 0.3)
summary(fit)

# grid search, BIC-selected, parallel across lambda on a 32-core machine
g <- grid_pecme(fixed, random_var = "group", data = sim$data,
                 censor = "censor", left = "left", right = "right",
                 penalty = "scad", nlambda = 40, criterion = "bic",
                 workers = 32)
plot(g)

response is not a separate argument: pecme()/grid_pecme() read it from the left-hand side of fixed_formula (here, y).

See vignette("pecme-intro") for a full walk-through (single fits, grid search, missing response, missing covariates).

Diagnostics and valid inference for penalized fits

Thesis-reporting metrics

pecme_metrics() collects everything you’d typically report for a mixed-model fit in one call: MSE, RMSE, MAE, MAPE, SMAPE, a predictive (OLS-style) R-squared and the marginal/conditional pseudo-R-squared that are the standard for mixed models (Nakagawa & Schielzeth, 2013), logLik, AIC, BIC, EBIC, and GCV.

pecme_metrics(fit)                                   # in-sample
pecme_metrics(fit, newdata = test_df)                # out-of-sample (response column auto-detected)
pecme_metrics(fit, loo = TRUE, loo_folds = 10)        # + leave-one-group-out CV

On LOO and WAIC: pecme is a frequentist penalized-likelihood estimator – it does not produce posterior draws, so a literal WAIC (or DIC) is not a well-defined quantity here, and pecme_metrics() deliberately reports $WAIC as NA with an explanatory note rather than fabricate one. What it does provide, via loo = TRUE, is a genuine out-of-sample criterion in the same spirit: a leave-one-group- out (or leave-one-fold-out) cross-validated predictive log-likelihood, computed by actually refitting the model with each group held out – this is the frequentist counterpart of what WAIC and PSIS-LOO both aim to approximate, at the cost of being more expensive to compute.

Review-sensitive implementation notes

The current implementation explicitly addresses the review points that affect statistical validity and reproducibility: censoring thresholds are tied to the requested censor_prob; the outer penalized objective uses the correct minimization monotonicity direction; failed variance optimization cannot create artificial zero likelihood/objective values; the "random" initialization changes values actually passed to the optimizer; transformed responses are taken from the evaluated model frame; refit utilities preserve the original analysis data and fitting arguments; EBIC uses the number of selected penalized predictors; and convergence/inner-optimizer diagnostics are retained in the top-level fitted object.

pecme_effective_df() is deliberately described as a working Ridge-type/conditional approximation where a full effective-df result has not been derived for the complete censored mixed-effects estimator. Likewise, pecme_lambda_max() is a data-dependent reference scale, not a formally established exact sparsity threshold.

Package layout

R/
  utils-math.R        Gauss-Hermite quadrature (cached), log-sum-exp
  truncation.R         Truncated-normal moments & log-lik (incl. "missing")
  estep.R               E-step, sequential and cluster-parallel over groups
  loglik.R              Observed-data marginal log-likelihood
  penalty.R              Penalty values + closed-form coordinate updates
  coordinate-descent.R    Penalized CM-step for beta
  objective.R              Full penalized objective / Q-function
  variance-update.R         EM and true-ECME updates for sigma, sigma_b
  standardize.R              Design-matrix standardization
  random-effects-init.R       lmer()-based starting values
  missing-data.R                Missing y / missing X handling, MI combiner
  validate.R                     Input validation
  prepare.R                       Formula/data -> matrices (no listwise deletion)
  engine.R                         Core ECME loop for one (penalty, lambda)
  lambda-grid.R                     Data-dependent lambda_max / grid
  parallel-utils.R                   Cluster setup/teardown
  fit.R                               pecme_setup()/pecme_run()/pecme()
  grid-search.R                       grid_pecme()
  metrics.R                            AIC/BIC/EBIC/GCV, prediction metrics, effective df
  thesis-metrics.R                      pecme_metrics(), pecme_loo()
  quadrature-check.R                    pecme_quadrature_check()
  pecme-bootstrap.R                     pecme_bootstrap() (cluster bootstrap)
  methods.R                             print/summary/coef/predict/plot/...
  simulate.R                             simulate_pecme_data()
tests/testthat/        Unit tests
vignettes/pecme-intro.Rmd  Worked example

License

MIT