Introduction
bayesma covers a broad range of meta-analytic models, but applied synthesis sometimes requires departures from the built-in options. The package supports three levels of customisation with increasing flexibility and complexity.
Level 1: Modify priors or add constraints
The simplest customisation changes only the prior distributions, without touching the model structure.
Example: Use an informative prior on from a published prior predictive analysis.
fit_informative <- bayesma(
data,
model_type = "random_effect",
tau_prior = half_normal(0, 0.25),
mu_prior = normal(0, 0.5)
)This requires only knowledge of the *_prior arguments. See ?priors for all available constructors:
normal(mu, sigma)
half_normal(mu, sigma)
half_cauchy(mu, sigma)
half_student_t(nu, mu, sigma)
exponential(rate)
uniform(lower, upper)Constraints on the pooled effect can be added via mu_constraint:
fit_positive <- bayesma(
data,
model_type = "random_effect",
mu_constraint = "positive"
)This restricts — appropriate when the direction of the effect is known a priori (e.g., a toxin that cannot be beneficial).
Level 2: Extend an existing model
The second level modifies the Stan data or adds blocks to the generated model without replacing the core likelihood. The workflow is:
- Extract the autogenerated Stan code with
bayesma(data, return_stage = "code"). - Edit the Stan code.
- Pass the modified code back to
bayesma()viacustom_model.
Example: Add a study-level covariate to the random-effects model.
base_code <- bayesma(data, model_type = "random_effect", return_stage = "code")
modified_code <- base_code |>
stringr::str_replace(
"vector\\[N\\] y;",
"vector[N] y;\n vector[N] x_cov;"
) |>
stringr::str_replace(
"target \\+= normal_lpdf\\(y \\| mu \\+ u\\[study\\], se\\);",
"target += normal_lpdf(y | mu + beta * x_cov + u[study], se);"
)
fit_extended <- bayesma(
data,
custom_model = modified_code,
custom_data = list(x_cov = data$covariate)
)The custom_data argument passes additional data blocks to Stan. The Stan code must declare matching entries in the data {} block.
Level 3: Fully custom Stan model
The most flexible option passes a complete Stan program written from scratch. bayesma provides the data preparation pipeline and posterior extraction infrastructure; the user supplies the model.
Required data block structure
The data block must include at minimum:
data {
int<lower=1> N; // number of observations
vector[N] y; // effect estimates
vector<lower=0>[N] se; // standard errors
array[N] int<lower=1> study; // study indicator (for RE models)
}For one-stage binary models, replace y and se with:
array[N] int<lower=0> events;
array[N] int<lower=1> n;
vector[N] treat;Required generated quantities block
For compatibility with bayesma_extract() and bayesma_output(), the generated quantities {} block must export b_Intercept (the pooled effect):
generated quantities {
real b_Intercept = mu;
}Example: Three-level model
A three-level (study > sample > effect) model for dependent effects:
data {
int<lower=1> N;
int<lower=1> K; // number of studies
int<lower=1> J; // number of samples
vector[N] y;
vector<lower=0>[N] se;
array[N] int<lower=1> study;
array[N] int<lower=1> sample;
}
parameters {
real mu;
real<lower=0> tau_study;
real<lower=0> tau_sample;
vector[K] z_study;
vector[J] z_sample;
}
transformed parameters {
vector[K] u_study = tau_study * z_study;
vector[J] u_sample = tau_sample * z_sample;
}
model {
target += normal_lpdf(mu | 0, 1);
target += cauchy_lpdf(tau_study | 0, 0.5);
target += cauchy_lpdf(tau_sample | 0, 0.5);
target += std_normal_lpdf(z_study);
target += std_normal_lpdf(z_sample);
target += normal_lpdf(y | mu + u_study[study] + u_sample[sample], se);
}
generated quantities {
real b_Intercept = mu;
}Pass this to bayesma():
Validation and diagnostics
Custom models should be checked for:
-
Identifiability:
pairs()plots of correlated parameters reveal non-identifiable structure. - Prior coverage: Prior predictive simulation should produce plausible ranges for all parameters.
- Convergence: and bulk ESS > 400 for all parameters.
-
Divergent transitions: Zero divergences at
adapt_delta = 0.95. Use the non-centred parameterisation for random effects (as in the examples above) to reduce divergences.
Limitations
Custom models bypass all built-in argument validation. The user is responsible for ensuring the model is correctly specified, identified, and that the custom_data list contains all variables referenced in the Stan data {} block.
