Here, we’ll use an example dataset taken from the `metafor`

website, which also comes preloaded with the `metafor`

package.^{1}

library(metafor) #> Loading required package: Matrix #> Loading 'metafor' package (version 2.4-0). For an overview #> and introduction to the package please type: help(metafor). library(concurve) library(ggplot2) dat.hine1989 #> study source n1i n2i ai ci #> 1 1 Chopra et al. 39 43 2 1 #> 2 2 Mogensen 44 44 4 4 #> 3 3 Pitt et al. 107 110 6 4 #> 4 4 Darby et al. 103 100 7 5 #> 5 5 Bennett et al. 110 106 7 3 #> 6 6 O'Brien et al. 154 146 11 4

I will quote Wolfgang here, since he explains it best,

"As described under help(dat.hine1989), variables

n1iandn2iare the number of patients in the lidocaine and control group, respectively, andaiandciare the corresponding number of deaths in the two groups. Since these are 2×2 table data, a variety of different outcome measures could be used for the meta-analysis, including the risk difference, the risk ratio (relative risk), and the odds ratio (see Table III). Normand (1999) uses risk differences for the meta-analysis, so we will proceed accordingly. We can calculate the risk differences and corresponding sampling variances with:

dat <- escalc(measure = "RD", n1i = n1i, n2i = n2i, ai = ai, ci = ci, data = dat.hine1989) dat #> study source n1i n2i ai ci yi vi #> 1 1 Chopra et al. 39 43 2 1 0.0280 0.0018 #> 2 2 Mogensen 44 44 4 4 0.0000 0.0038 #> 3 3 Pitt et al. 107 110 6 4 0.0197 0.0008 #> 4 4 Darby et al. 103 100 7 5 0.0180 0.0011 #> 5 5 Bennett et al. 110 106 7 3 0.0353 0.0008 #> 6 6 O'Brien et al. 154 146 11 4 0.0440 0.0006

"Note that the

yivalues are the risk differences in terms of proportions. Since Normand (1999) provides the results in terms of percentages, we can make the results directly comparable by multiplying the risk differences by 100 (and the sampling variances by \(100^{2}\)):

dat$yi <- dat$yi * 100 dat$vi <- dat$vi * 100^2

We can fit a fixed-effects model with the following

fe <- rma(yi, vi, data = dat, method = "FE")

Now that we have our metafor object, we can compute the consonance function using the `curve_meta()`

function.

fecurve <- curve_meta(fe)

Now we can graph our function.

ggcurve(fecurve[[1]], nullvalue = TRUE)

We used a fixed-effects model here, but if we wanted to use a random-effects model, we could do so with the following, which will use a restricted maximum likelihood estimator for the random-effects model

re <- rma(yi, vi, data = dat, method = "REML")

And then we could use `curve_meta()`

to get the relevant list

recurve <- curve_meta(re)

Now we can plot our object.

ggcurve(recurve[[1]], nullvalue = TRUE)

We could also compare our two models to see how much consonance/overlap there is

curve_compare(fecurve[[1]], recurve[[1]], plot = TRUE) #> [1] "AUC = Area Under the Curve" #> [[1]] #> #> #> AUC 1 AUC 2 Shared AUC AUC Overlap (%) Overlap:Non-Overlap AUC Ratio #> ------ ------ ----------- ---------------- ------------------------------ #> 2.084 2.084 2.084 100 Inf #> #> [[2]]

The results are practically the same and we cannot actually see any difference, and the AUC % overlap also indicates this.

`concurve`

can also handle complex data structures from `metafor`

that are clustered.

### copy data from Berkey et al. (1998) into 'dat' dat <- dat.berkey1998 ### construct list of the variance-covariance matrices of the observed outcomes for the studies V <- lapply(split(dat[, c("v1i", "v2i")], dat$trial), as.matrix) ### construct block diagonal matrix V <- bldiag(V) ### fit multivariate model res <- rma.mv(yi, V, mods = ~ outcome - 1, random = ~ outcome | trial, struct = "UN", data = dat) ### results based on sandwich method (a <- robust(res, cluster = dat$trial)) #> #> Number of outcomes: 10 #> Number of clusters: 5 #> Outcomes per cluster: 2 #> #> Test of Moderators (coefficients 1:2): #> F(df1 = 2, df2 = 3) = 41.6138, p-val = 0.0065 #> #> Model Results: #> #> estimate se tval pval ci.lb ci.ub #> outcomeAL -0.3392 0.1010 -3.3597 0.0437 -0.6605 -0.0179 * #> outcomePD 0.3534 0.0675 5.2338 0.0136 0.1385 0.5683 * #> #> --- #> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 l <- concurve::curve_meta(res, method = "uni", robust = TRUE, cluster = dat$trial, adjust = TRUE, steps = 1000) ggcurve(data = l[[1]], type = "c") + theme_minimal()

The interval function is quite narrow because there were so many iterations that were set by us.

1. Viechtbauer W. *Conducting Meta-Analyses in R with the Metafor Package*.; 2010. https://www.jstatsoft.org/v36/i03/.