--- title: "Multilevel Meta-Analysis" author: "František Bartoš" date: "28th of April 2026" output: rmarkdown::html_vignette: self_contained: yes bibliography: ../inst/REFERENCES.bib csl: ../inst/apa.csl link-citations: true vignette: > %\VignetteIndexEntry{Multilevel Meta-Analysis} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown_notangle} --- ```{r child = "_vignette-nowrap.md", echo = FALSE, eval = TRUE} ``` ```{r setup, include = FALSE} source("vignette-cache.R", local = knitr::knit_global()) cached_fits <- vignette_cache( name = "v10-metafor-parity-multilevel", objects = c("fit1_brma"), packages = c("metafor", "metadat") ) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = vignette_cache_eval(cached_fits), message = FALSE, warning = FALSE, fig.width = 7, fig.height = 3.5, dev = "png", fig.retina = 3 ) if (.Platform$OS.type == "windows") { knitr::opts_chunk$set(dev.args = list(type = "cairo")) } ``` ```{r load-models, include = FALSE} library("metafor") library("RoBMA") data("dat.konstantopoulos2011", package = "metadat") dat <- dat.konstantopoulos2011 vignette_cache_load(cached_fits) ``` ```{r precompute-models, include = FALSE, eval = FALSE} library("metafor") library("RoBMA") data("dat.konstantopoulos2011", package = "metadat") dat <- dat.konstantopoulos2011 fit1_brma <- brma( yi = yi, vi = vi, measure = "SMD", cluster = district, data = dat, seed = 1 ) vignette_cache_save(cached_fits) ``` This vignette illustrates how to use the `RoBMA` R package [@RoBMA] with multilevel meta-analytic data. We walk through the school-calendar dataset from @konstantopoulos2011fixed, showing the `brma()` call with the `cluster` argument alongside its `metafor::rma.mv()` counterpart [@metafor]. All `brma()` calls keep the default prior distributions; see the [*Prior Distributions*](v01-prior-distributions.html) vignette for the prior definitions and customization options. For the non-multilevel workflow showing more features (also applicable to the multilevel models) see the [*Bayesian Meta-Analysis*](v02-bayesian-meta-analysis.html) vignette. The `RoBMA` R package currently supports the simple multilevel structure shown here, with one cluster grouping above the estimate level (parameterized by total heterogeneity $\tau^2$ and cluster-level allocation $\rho$). Broader support for multivariate models and more complex random-effects structures is planned for a future release. ## Multilevel Random-Effects Model The school-calendar dataset from the `metadat` package contains 56 standardized mean differences nested in 11 school districts. Effect sizes `yi` and sampling variances `vi` are already provided, so no `escalc()` step is needed. ```{r data} data("dat.konstantopoulos2011", package = "metadat") dat <- dat.konstantopoulos2011 head(dat) ``` `metafor::rma.mv()` fits a multilevel random-effects model with the compound-symmetric structure `random = ~ school | district`, parameterized by the total heterogeneity $\tau$ and the within-district correlation $\rho$. ```{r fit1-metafor} fit1_metafor <- metafor::rma.mv(yi, vi, random = ~ school | district, data = dat) fit1_metafor ``` The matching Bayesian fit replaces the `random = ...` argument with `cluster = district`. `brma()` parameterizes the multilevel model in the same compound-symmetric form: a total heterogeneity $\tau$ and a cluster-level allocation $\rho$ where $\tau_{between} = \tau\sqrt{\rho}$ and $\tau_{within} = \tau\sqrt{1 - \rho}$. `measure = "SMD"` selects the default prior distributions for standardized mean differences. ```{r fit1-brma, eval = FALSE} fit1_brma <- brma( yi = yi, vi = vi, measure = "SMD", cluster = district, data = dat, seed = 1 ) ``` `summary()` reports posterior means, credible intervals, and (suppressed here) MCMC convergence diagnostics for `mu`, `tau`, and `rho`. ```{r fit1-brma-summary} summary(fit1_brma, include_mcmc_diagnostics = FALSE) ``` The posterior mean for the pooled effect tracks the REML estimate from the `metafor` package, with comparable cluster-level allocation `rho` and total heterogeneity `tau`. ## Heterogeneity: $\tau$ and $\rho$ `metafor::confint()` reports profile-likelihood confidence intervals for `tau^2`, `tau`, and `rho`. ```{r heterogeneity-confint} confint(fit1_metafor) ``` `summary_heterogeneity()` is the Bayesian counterpart, reporting posterior summaries of the same quantities along with the partitioned within- and between-cluster components. ```{r heterogeneity-bayes} summary_heterogeneity(fit1_brma) ``` `plot()` visualizes the posterior, and `prior = TRUE` overlays the prior distribution so the shift from prior to posterior is visible. Side-by-side panels for `tau` and `rho` show the bulk of the posterior moving away from the weakly informative defaults. ```{r tau-rho-posterior, fig.width = 7, fig.height = 3.2} par(mfrow = c(1, 2), mar = c(4, 4, 2, 1), cex.axis = 0.8, cex.lab = 0.8, cex.main = 0.75) plot(fit1_brma, parameter = "tau", prior = TRUE, main = "tau", xlim = c(0, 1)) plot(fit1_brma, parameter = "rho", prior = TRUE, main = "rho", xlim = c(0, 1)) ``` The `tau` posterior concentrates around 0.3 with credible interval comparable to the profile-likelihood bounds, while the `rho` posterior favors a moderate-to-high cluster-level allocation, broadly consistent with the REML point estimate of 0.67. ## Other Inference Helpers All inference helpers available for any other `brma()` fit work the same way for the multilevel fit specified via `cluster`. This includes meta-regression and location-scale models, model comparison, and fit diagnostics. See the [*Bayesian Meta-Analysis*](v02-bayesian-meta-analysis.html) vignette for the full walkthrough; the only thing that changes here is the addition of `cluster = district`. ## References