mlumr implements Multilevel Unanchored Meta-Regression (ML-UMR), a population-adjusted indirect treatment comparison method for disconnected evidence networks. ML-UMR extends Multilevel Network Meta-Regression (ML-NMR; Phillippo et al., 2020) to the unanchored setting, where individual patient data (IPD) are available for one treatment and only aggregate data (AgD) are available for the comparator, with no common reference arm (e.g. comparison of single arm studies). In this setting, mlumr estimates treatment effects while adjusting for cross-trial differences in prognostic factors.
In terms of the software, mlumr is an adaptation of the GPL-3 licensed multinma package, which provides functionality for conducting ML-NMR and NMAs. mlumr uses similar Sobol quasi-Monte Carlo and Gaussian-copula integration machinery to marginalize over the comparator-population covariate distribution, and extends the implementation with Stan likelihoods for the unanchored two-treatment problem, including SPFA and relaxed-SPFA models for binomial, normal, and Poisson outcomes.
The package provides three complementary methods within a unified interface:
- ML-UMR (Bayesian): SPFA and Relaxed SPFA models via Stan, with quasi-Monte Carlo integration and Gaussian copula for population adjustment
- STC (Frequentist): Simulated treatment comparison via parametric G-computation with delta-method standard errors
- Naive (Benchmark): Unadjusted comparison of crude outcome summaries
Supported outcome families and link functions
| Family | Outcome type | Link functions |
|---|---|---|
| Binomial | Binary (0/1) | logit (default), probit, cloglog |
| Normal | Continuous | identity (default), log |
| Poisson | Count + exposure | log (default) |
Installation
Development version
# install.packages("remotes")
remotes::install_github("choxos/mlumr")Prerequisites
mlumr uses Stan for Bayesian model fitting. The default backend is rstan, with Stan model C++ code generated by rstantools and compiled during package installation. A C++ toolchain is required:
-
macOS: Install Xcode Command Line Tools (
xcode-select --install) - Windows: Install Rtools
-
Linux: Install
g++andmake(usually available by default)
Optional: cmdstanr backend
Users who prefer cmdstanr can switch backends after installation:
# Switch to cmdstanr (will offer to install cmdstanr + CmdStan if needed)
mlumr_engine("cmdstanr")
# Switch back to rstan
mlumr_engine("rstan")
# Check current engine
mlumr_engine()The engine preference persists for the current session. To set a permanent default, add to your .Rprofile:
options(mlumr.stan_engine = "cmdstanr")You can also override the engine for a single model fit:
fit <- mlumr(dat, model = "spfa", engine = "cmdstanr")When the package is attached with library(mlumr), it prints a short startup message with the installed version and GitHub repository.
Using mlumr alongside multinma
A subset of mlumr’s exported functions perform similar actions to their multinma counterparts and intentionally retain the same name (set_ipd(), set_agd(), add_integration(), unnest_integration(), distr(), marginal_effects(), qbern()/pbern()/dbern()). mlumr also exports several functions that are not available in multinma (mlumr(), naive(), stc(), combine_data(), check_integration(), conditional_effects(), conditional_predict(), prior_sensitivity(), calculate_dic()/loo()/waic(), compare_models()).
If both packages are attached in the same R session, R issues masking warnings on the shared names. The cleanest practice is to use only one package per session for any given analysis, matched to the network type (anchored connected → multinma; unanchored disconnected → mlumr). When you do need both attached (e.g. a methods-comparison sensitivity analysis), use the namespace prefix to disambiguate:
library(multinma)
library(mlumr)
# mlumr fits ML-UMR (disconnected, two-trial)
ipd_umr <- mlumr::set_ipd(ipd_df, treatment = "trt", outcome = "outcome",
covariates = c("age_group", "sex"))
fit_umr <- mlumr::mlumr(dat, model = "spfa")
# multinma fits ML-NMR (connected network)
net_nmr <- multinma::set_ipd(pso_ipd, study = studyc, trt = trtc, r = pasi75)
fit_nmr <- multinma::nma(net_nmr, regression = ~ age:.trt)Quick start
library(mlumr)
set.seed(2026)
# --- Prepare IPD (index treatment) ---
n_A <- 500
ipd_df <- data.frame(
trt = "Drug_A",
outcome = rbinom(n_A, 1, 0.55),
age_group = rbinom(n_A, 1, 0.40),
sex = rbinom(n_A, 1, 0.55)
)
ipd <- set_ipd(ipd_df, treatment = "trt", outcome = "outcome",
covariates = c("age_group", "sex"))
# --- Prepare AgD (comparator) ---
agd_df <- data.frame(
trt = "Drug_B", n_total = 400, n_events = 148,
age_group_mean = 0.35, sex_mean = 0.50
)
agd <- set_agd(agd_df, treatment = "trt",
outcome_n = "n_total", outcome_r = "n_events",
cov_means = c("age_group_mean", "sex_mean"),
cov_types = c("binary", "binary"))
# --- Combine and add integration points ---
dat <- combine_data(ipd, agd)
dat <- add_integration(dat, n_int = 64,
age_group = distr(qbern, prob = age_group_mean),
sex = distr(qbern, prob = sex_mean)
)
# --- Run all three methods ---
# Naive (instant)
naive_result <- naive(dat)
# STC (instant)
stc_result <- stc(dat)
# ML-UMR SPFA (Bayesian, takes a few minutes)
fit <- mlumr(dat, model = "spfa",
prior_intercept = prior_normal(0, 10),
prior_beta = prior_normal(0, 2.5),
chains = 4, iter = 4000, warmup = 2000, seed = 42)
summary(fit)
marginal_effects(fit, effect = "lor")Methods overview
| Feature | ML-UMR SPFA | ML-UMR Relaxed | STC | Naive |
|---|---|---|---|---|
| Covariate adjustment | Joint model | Joint model | Outcome regression | None |
| Effect modification | Assumed absent | Estimated | Not captured | N/A |
| Uncertainty | Posterior | Posterior | Delta method | Delta method |
| Population weighting | QMC integration | QMC integration | G-computation | None |
| Speed | Minutes | Minutes | Sub-second | Sub-second |
| Integration points required | Yes | Yes | Optional | No |
Key functions
| Function | Purpose |
|---|---|
set_ipd(), set_agd()
|
Prepare IPD and AgD with outcome and covariate specification |
combine_data() |
Combine IPD and AgD into a unified dataset |
add_integration() |
Generate QMC integration points with Gaussian copula |
mlumr() |
Fit ML-UMR SPFA or Relaxed model via Stan |
mlumr_engine() |
Get or set the Stan backend (rstan or cmdstanr) |
naive(), stc()
|
Frequentist benchmark methods |
predict() |
Population-specific predicted outcomes |
marginal_effects() |
Posterior treatment effect summaries |
conditional_effects() |
Covariate-conditional treatment effects |
conditional_predict() |
Predictions at specific covariate values |
calculate_loo(), calculate_waic(), calculate_dic(), compare_models()
|
Bayesian model comparison (LOO-CV, WAIC, DIC) |
When to use ML-UMR
| Method | Data required | Type of ITC | Pairwise only | Type of treatment effect | Target population |
|---|---|---|---|---|---|
| MAIC | IPD + AgD | Anchored or unanchored | Yes | Marginal | Comparator |
| STC | IPD + AgD | Anchored or unanchored | Yes | Marginal | Comparator |
| ML-NMR | IPD + AgD | Anchored | No | Marginal or conditional | Any pre-specified target |
| ML-UMR | IPD + AgD | Unanchored | No | Marginal or conditional | Any pre-specified target |
ML-UMR is most appropriate when:
- You have IPD for one treatment and AgD for the comparator
- No common reference arm connects the evidence (unanchored)
- Binary, continuous, or count outcomes are of interest
- Covariate distributions differ between trial populations
Vignettes
Detailed tutorials are available as package vignettes:
-
vignette("introduction")– Package overview, installation, and quick start -
vignette("data-preparation")– IPD/AgD setup, integration points, and correlation handling -
vignette("mlumr-models")– SPFA vs Relaxed models, priors, diagnostics, and LOO/WAIC/DIC model comparison -
vignette("stc-and-naive")– STC and naive methods with delta-method details -
vignette("model-comparison")– Side-by-side comparison of all methods with interpretation guidance -
vignette("worked-example")– Complete end-to-end analysis from simulated data
References
The ML-UMR methodology extends the ML-NMR framework:
Phillippo, D. M., Dias, S., Ades, A. E., Belger, M., Brnabic, A., Schacht, A., Saure, D., Kadziola, Z., & Welton, N. J. (2020). “Multilevel Network Meta-Regression for population-adjusted treatment comparisons.” Journal of the Royal Statistical Society: Series A, 183(3), 1189–1210. doi:10.1111/rssa.12579
Chandler, C. & Ishak, J. (2025). “Anchors Away: Navigating Unanchored Indirect Comparisons With Multilevel Unanchored Meta-Regression (ML-UMR).” ISPOR Europe 2025, MSR28. Value in Health, 28, S498. https://www.valueinhealthjournal.com/article/S1098-3015(25)05944-3/abstract
Chandler, C. & Ishak, J. (2026). “Surviving Unanchored Indirect Comparisons: An Extension of Multilevel Unanchored Meta-Regression (ML-UMR) for Survival Analyses.” ISPOR 2026, MSR131. Value in Health, 29(S6). https://www.ispor.org/heor-resources/presentations-database/presentation-cti/ispor-2026/poster-session-3-3/surviving-unanchored-indirect-comparisons-an-extension-of-multilevel-unanchored-meta-regression-ml-umr-for-survival-analyses
Citing mlumr
citation("mlumr")Authors
- Ahmad Sofi-Mahmudi (author, maintainer)
- Conor Chandler (author)
Acknowledgments
Portions of the package code, documentation, and Stan models were drafted and audited with the assistance of large language models: Anthropic’s Claude Opus 4.6 and 4.7 (via Claude Code) and OpenAI’s ChatGPT 5.4 and 5.5 (via Codex). All methodological choices, design decisions, and the final review and validation were performed by the named authors, who take responsibility for the package’s contents.
License
GPL-3. See https://www.gnu.org/licenses/gpl-3.0 for the full license text.
