Meta-analysis of estimates based on correlated outcomes in brms

This is related to the issue I raised which has been closed (Multiple response variables in meta-analysis. · Issue #1212 · paul-buerkner/brms · GitHub) which Paul has already kindly reviewed. I suggested a feature to allow users to meta-analyse results which were based on correlated outcome (response) variables.

Paul explained that the feature was not needed as the desired model could be obtained by arranging the data into long format and using fcor. However, I have been unable to do get this to work (I read the response to a previous question (Brms: Multivariate meta-analysis syntax) to help with the model specification on the RHS). Can someone please advise where I am going wrong in trying to specify the known standard errors and known correlation?

Commented reproducible example below.

## Dataset in long format. Two trials, two response variables. Effect estimates and standard errors for each combination (4 effect estimates)
mydf_lng <- structure(list(trial = c(1L, 1L, 2L, 2L), 
                           response = c("1", "2", "1", "2"), 
                           y = c(1.405, -1.652, 0.047, -0.169), 
                           se = c(0.642,0.697, 0.055, 0.114)),
                      row.names = c(NA, -4L), class = "data.frame")

## Correlation matrix indicating correlation between each effect estimate. Effect estimates within trials are correlated. Those between trials are not.
cors <- structure(c(1, -0.921, 0, 0,
                    -0.921, 1, 0, 0,
                    0, 0, 1, -0.48,
                    0, 0, -0.48, 1), .Dim = c(4L, 4L), .Dimnames = list(NULL, NULL))

## Works, specify se but not cors
mod1 <- brm(y|se(se) ~ 0 + response + (0 + response | trial) , data = mydf_lng, data2 = list(cors = cors))

## Works, specify cors but not se
mod2 <- brm(y ~ 0 + response + (0 + response | trial) + fcor(cors), data = mydf_lng, data2 = list(cors = cors))

## Error message "Error: Invalid addition arguments for this model" when try to specify both the se and correlation
mod3 <- brm(y|se(se) ~ 0 + response + (0 + response | trial) + fcor(cors), data = mydf_lng, data2 = list(cors = cors))

Many thanks!

You need to pass the covariance matrix to fcor() in this case. That is, the input to fcor needs to contain the SE information already. Then, no se() is needed anymore. If you then want to avoid estimating sigma, you additionally need to set it to for example via prior = prior(constant(1), class = "sigma")

1 Like

Thanks for the amazingly quick reply. I will do both.
That actually makes it more straightforward for me to implement as I have the coefficients and variance-covariance matrix from the original (IPD-derived) models.

PS presumably if I wanted to nest one outcome within a hierarchy but not others (eg response 1 but not response 2, I would be able to do so by setting-up indicator variables and writing

~ 0 + response1 + response2 + (0 + response1 | trial) + fcor(cors)

Yes. Indeed.

1 Like

Very enlightening, Paul. Of note, functions that construct variance-covariance matrices (eg, metafor::vcalc()) usually request the know sampling variances , not SE.

When you say

Does it matter if the covariance matrix was constructed based on the variance, not SE?

I guess not based on the Stan code that brms uses for meta-analyses (see below), but would like to confirm.


transformed data {
  vector<lower=0>[N] se2 = square(se);

Does anyone else know? :)

The sampling variance is just the SE squared, so there shouldn’t be a difference

EDIT: As in, just pass the same matrix to fcor() that you would to `vcalc°

1 Like