Author: František Bartoš

# Location-Scale Meta-Analysis

#### František Bartoš

#### 28th of April 2026

This vignette illustrates how to fit location-scale meta-analytic models with the `RoBMA` R package (Bartoš & Maier, 2020). We walk through the writing-to-learn dataset (`dat.bangertdrowns2004` in the `metadat` package), showing the `brma()` call with the `scale = ~ ...` argument alongside its `metafor::rma()` counterpart (Viechtbauer, 2010), and build from a simple random-effects model up to a model with different predictors in the location and scale parts.

A location-scale model parameterizes the between-study heterogeneity \(\tau\) as a regression on study-level covariates, allowing \(\tau\) to vary across subgroups or as a function of continuous moderators. The location side is the usual meta-regression on the effect.

All `brma()` calls keep the default prior distributions; see the Prior Distributions vignette for the prior definitions and customization options. For the non-location-scale workflow showing more features (also applicable to location-scale models) see the Bayesian Meta-Analysis vignette.

## Random-Effects Model

The writing-to-learn dataset contains 48 standardized mean differences from studies on the effectiveness of school-based writing interventions on academic achievement. Effect sizes `yi` and sampling variances `vi` are already provided.

    data("dat.bangertdrowns2004", package = "metadat")
    dat <- dat.bangertdrowns2004
    dat$ni100 <- dat$ni / 100
    dat$meta  <- as.factor(dat$meta)
    dat$imag  <- as.factor(dat$imag)

We start from a standard random-effects model with no scale predictor.

    fit1_metafor <- metafor::rma(yi, vi, data = dat)
    fit1_metafor
    #>
    #> Random-Effects Model (k = 48; tau^2 estimator: REML)
    #>
    #> tau^2 (estimated amount of total heterogeneity): 0.0499 (SE = 0.0197)
    #> tau (square root of estimated tau^2 value):      0.2235
    #> I^2 (total heterogeneity / total variability):   58.37%
    #> H^2 (total variability / sampling variability):  2.40
    #>
    #> Test for Heterogeneity:
    #> Q(df = 47) = 107.1061, p-val < .0001
    #>
    #> Model Results:
    #>
    #> estimate      se    zval    pval   ci.lb   ci.ub
    #>   0.2219  0.0460  4.8209  <.0001  0.1317  0.3122  ***
    #>
    #> ---
    #> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

    fit1_brma <- brma(
      yi = yi, vi = vi, measure = "SMD",
      data = dat, seed = 1
    )

    summary(fit1_brma, include_mcmc_diagnostics = FALSE)
    #>
    #> Bayesian Random-Effects Model (k = 48)
    #>
    #> Estimates
    #>      Mean    SD 0.025   0.5 0.975
    #> mu  0.220 0.048 0.130 0.220 0.317
    #> tau 0.227 0.053 0.131 0.224 0.340

The pooled effect and the single heterogeneity parameter `tau` track the REML estimates from the `metafor` package.

## Adding a Scale Predictor

Sample size is a natural candidate for explaining heterogeneity: smaller studies often produce more variable estimates than larger ones. We add the rescaled total sample size (`ni100 = ni / 100`) on both the location and the scale side.

    fit2_metafor <- suppressWarnings(metafor::rma(
      yi, vi,
      mods  = ~ ni100,
      scale = ~ ni100,
      data = dat
    ))
    fit2_metafor
    #>
    #> Location-Scale Model (k = 48; tau^2 estimator: REML)
    #>
    #> Test for Residual Heterogeneity:
    #> QE(df = 46) = 95.1352, p-val < .0001
    #>
    #> Test of Location Coefficients (coefficient 2):
    #> QM(df = 1) = 7.8268, p-val = 0.0051
    #>
    #> Model Results (Location):
    #>
    #>          estimate      se     zval    pval    ci.lb    ci.ub
    #> intrcpt    0.3017  0.0661   4.5629  <.0001   0.1721   0.4313  ***
    #> ni100     -0.0553  0.0198  -2.7976  0.0051  -0.0940  -0.0165   **
    #>
    #> Test of Scale Coefficients (coefficient 2):
    #> QM(df = 1) = 3.1850, p-val = 0.0743
    #>
    #> Model Results (Scale):
    #>
    #>          estimate      se     zval    pval    ci.lb    ci.ub
    #> intrcpt   -1.9209  0.6690  -2.8713  0.0041  -3.2321  -0.6097  **
    #> ni100     -0.9174  0.5141  -1.7847  0.0743  -1.9250   0.0901   .
    #>
    #> ---
    #> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

    fit2_brma <- brma(
      yi = yi, vi = vi, measure = "SMD",
      mods  = ~ ni100,
      scale = ~ ni100,
      data = dat, seed = 1
    )

    summary(fit2_brma, include_mcmc_diagnostics = FALSE)
    #>
    #> Bayesian Location-Scale Model (k = 48)
    #>
    #> Location
    #>             Mean    SD  0.025    0.5  0.975
    #> intercept  0.303 0.068  0.171  0.302  0.437
    #> ni100     -0.056 0.023 -0.103 -0.056 -0.013
    #>
    #> Scale
    #>                  Mean    SD  0.025    0.5 0.975
    #> exp(intercept)  0.348 0.118  0.148  0.338 0.608
    #> ni100          -0.375 0.225 -0.865 -0.366 0.042
    #> exp(Intercept) corresponds to the between-study heterogeneity tau; the meta-regression coefficients correspond to the multiplicative effects on log-scale.

The location coefficient on `ni100` matches the REML estimate from the `metafor` package. The scale block reports `exp(intercept)`, which is the baseline between-study heterogeneity \(\tau\), and a multiplicative log-scale coefficient on `ni100`. Note that `metafor::rma()` regresses \(\log(\tau^2)\) while `brma()` regresses \(\log(\tau)\), so each `metafor` package scale coefficient is exactly twice the matching `brma()` coefficient.

`regplot()` with `pi = TRUE` overlays the prediction interval on the bubble plot. Because \(\tau\) varies with `ni100`, the `brma()` prediction band narrows toward larger sample sizes, where the model expects less between-study heterogeneity. `metafor::regplot()` does not currently draw a prediction interval for location-scale models, so only the regression line and confidence band appear in the left panel.

    par(mfrow = c(1, 2), mar = c(4, 4, 2, 1), cex.axis = 0.8, cex.lab = 0.8, cex.main = 0.75)
    metafor::regplot(fit2_metafor, mod = "ni100", pi = TRUE,
                     main = "metafor", xlim = c(0, 6), ylim = c(-1, 2))
    regplot(fit2_brma, mod = "ni100", pi = TRUE,
            main = "RoBMA",   xlim = c(0, 6), ylim = c(-1, 2))

## Different Variables in Location and Scale

Variables in the location and scale parts can differ. The next fit adds metacognitive reflection (`meta`) on the location side and imaginative-component coding (`imag`) on the scale side.

    fit3_metafor <- suppressWarnings(metafor::rma(
      yi, vi,
      mods  = ~ ni100 + meta,
      scale = ~ ni100 + imag,
      data = dat
    ))
    fit3_metafor
    #>
    #> Location-Scale Model (k = 46; tau^2 estimator: REML)
    #>
    #> Test for Residual Heterogeneity:
    #> QE(df = 43) = 82.2711, p-val = 0.0003
    #>
    #> Test of Location Coefficients (coefficients 2:3):
    #> QM(df = 2) = 12.4826, p-val = 0.0019
    #>
    #> Model Results (Location):
    #>
    #>          estimate      se     zval    pval    ci.lb    ci.ub
    #> intrcpt    0.2303  0.0655   3.5166  0.0004   0.1019   0.3586  ***
    #> ni100     -0.0565  0.0188  -3.0113  0.0026  -0.0933  -0.0197   **
    #> meta1      0.1469  0.0690   2.1305  0.0331   0.0118   0.2820    *
    #>
    #> Test of Scale Coefficients (coefficients 2:3):
    #> QM(df = 2) = 5.0289, p-val = 0.0809
    #>
    #> Model Results (Scale):
    #>
    #>          estimate      se     zval    pval    ci.lb    ci.ub
    #> intrcpt   -2.3456  0.8354  -2.8079  0.0050  -3.9829  -0.7084  **
    #> ni100     -0.9995  0.6087  -1.6421  0.1006  -2.1925   0.1935
    #> imag1      2.1258  1.1857   1.7929  0.0730  -0.1981   4.4497   .
    #>
    #> ---
    #> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

    fit3_brma <- brma(
      yi = yi, vi = vi, measure = "SMD",
      mods  = ~ ni100 + meta,
      scale = ~ ni100 + imag,
      data = dat, seed = 1
    )

    summary(fit3_brma, include_mcmc_diagnostics = FALSE)
    #>
    #> Bayesian Location-Scale Model (k = 46)
    #>
    #> Location
    #>             Mean    SD  0.025    0.5  0.975
    #> intercept  0.229 0.069  0.095  0.228  0.369
    #> ni100     -0.058 0.023 -0.106 -0.058 -0.016
    #> meta[1]    0.173 0.078  0.026  0.171  0.336
    #>
    #> Scale
    #>                  Mean    SD  0.025    0.5 0.975
    #> exp(intercept)  0.291 0.113  0.100  0.281 0.542
    #> ni100          -0.338 0.237 -0.826 -0.333 0.108
    #> imag[1]         0.361 0.447 -0.600  0.383 1.180
    #> exp(Intercept) corresponds to the between-study heterogeneity tau; the meta-regression coefficients correspond to the multiplicative effects on log-scale.

Each scale coefficient is again roughly half of its `metafor` package counterpart, with `brma()` shrinking the larger `metafor` package estimates more strongly because of the weakly informative default prior distribution.

## Scale Predictor Prior Distributions

Scale regression coefficients are not on the effect-size scale: they describe multiplicative changes in \(\tau\) on the log scale and are therefore scale-free. The default prior distribution is `Normal(0, 0.5)`, which corresponds to a weakly informative prior distribution on the multiplicative effect. A coefficient of \(\pm 0.5\) corresponds to roughly \(\exp(\pm 0.5) \approx 0.6\) or \(1.65\), i.e., a \(40\%\) decrease or \(65\%\) increase in \(\tau\) per unit change in the predictor; values past \(\pm 1\) correspond to a halving or doubling, which the prior distribution treats as extreme.

`plot()` with `prior = TRUE` overlays the prior distribution on the posterior so the shift is visible. `parameter_scale = "ni100"` selects the scale-side coefficient (the analogous selector on the location side is `parameter_mods = "ni100"`).

    par(mar = c(4, 4, 1, 1))
    plot(fit2_brma, parameter_scale = "ni100", prior = TRUE, xlim = c(-2, 2))

## Other Inference Helpers

All inference helpers available for any other `brma()` fit work the same way for the location-scale fit specified via `scale = ~ ...`. This includes meta-regression bubble plots, marginal means, model comparison via Bayes factors, multilevel structures via `cluster`, and the full set of model-fit diagnostics. See the Bayesian Meta-Analysis vignette for more details.

## References

Bartoš, F., & Maier, M. (2020). RoBMA: An R package for robust Bayesian meta-analyses. https://CRAN.R-project.org/package=RoBMA
Viechtbauer, W. (2010). Conducting meta-analyses in R with the metafor package. Journal of Statistical Software, 36(3), 1–48. https://doi.org/10.18637/jss.v036.i03