Proportion Meta-analysis

 

Menu location: Analysis_Meta-Analysis_Proportion.

 

This function enables you to calculate an overall proportion from a set of proportions, for example from a systematic review of studies of adherence with a particular drug treatment.

 

This function can also be applied to a review of diagnostic test studies to give an overall sensitivity or specificity as follows:

 

    DISEASE/OUTCOME
    Present Absent
TEST: +: a (true +ve) b (false +ve)
  -: c (false -ve) d (true -ve)

 

Sensitivity = a/(a+c)

Specificity = d/(b+d)

 

Another way to summarise diagnostic test performance is via the diagnostic odds ratio:

 

Diagnostic odds ratio = true/false = (a * d)/(b * c)

 

In order to run a meta-analysis of diagnostic odds ratios simply use the odds ratio meta-analysis function with the experimental group as the true (test correct) outcomes and the control group as the false outcomes – enter a as experimental group responders; a+d as experimental group number; b as control group responders; and b+c as control group total.

 

Many study designs can be expressed as a proportion, and relatively complex statistical models can be explored using sets of proportions – for example a random effects logistic regression. You should seek the assistance of a statistician if you want to pursue analyses deeper than the summaries that this StatsDirect function offers.

 

The inconsistency of results across studies is summarised in the I² statistic, which is the percentage of variation across studies that is due to heterogeneity rather than chance – see the heterogeneity section for more information.

 

Beyond this meta-analysis function, logistic regression can be used to compare pooled proportions. Consult with a statistician if you are considering a random effects logistic model.

 

DATA INPUT:

You enter the number of subjects responding (with the study outcome) and the total number of subjects studied. You may also enter a title for each study.

 

Technical Validation

StatsDirect first transforms proportions via the Freeman-Tukey double arcsine method (Freeman and Tukey, 1950, Miller 1978) then performs an inverse-variance weighted fixed and random effects meta-analysis by conventional methods (DerSimonian and Laird, 1986). The appropriate weight is n+0.5 but some other software uses n+1. In our own simulation testing of the variance options within the formula 1/(n+c), varying c from 0.5 to 1, we found that the n+1 method (Stuart and Ord, 1994) is conservative, avoiding underestimation of the true variance of the transformed proportion, but the original n+0.5 method (Freeman et al, 1950) method is closer to the true variance in absolute terms. Note that there is no fixed transformation of a binomial proportion that provides optimal variance stabilization, which depends on your data - iterative variance stabilization methods may emerge with further research. The pooled proportion can be calculated as the back-transform of the weighted mean of the transformed proportions (Miller 1978):

 

$\displaystyle \hat{p}=\left\{1-\text{sgn}⁡(\cos{(\hat{x})})\times\sqrt{1-{\left[\sin{(\hat x)}+\frac{(\sin{(\hat x)}-1/\sin{(\hat x)})}n\right]}^2}\ \right\} \times 0.5$

$\displaystyle \hat x=\frac{\sum ⁢xw⁢}{\sum ⁢w}$

$\displaystyle x=\sin^{-1}\left(\sqrt{r/(n+1)}\right)+\sin^{-1} \left( \sqrt{(r+1)/(n+1)}\right)$

$\displaystyle w=n+0.5$

$\displaystyle q=\sum w(x-\hat x)^2$

$\displaystyle \tau^2=\frac{q-(k-1)}{\sum w-\sum w^2/\sum w}$

$\displaystyle w_r=\frac{1}{\tau^2+1/w}$

$\displaystyle \hat x_r=\frac{\sum xw_r}{\sum w_r}$

$\displaystyle \hat{p_r}=\left\{1-\text{sgn}⁡(\cos{(\hat{x}_r)})\times\sqrt{1-{\left[\sin{(\hat x_r)}+\frac{(\sin{(\hat x_r)}-1/\sin{(\hat x_r)})}n\right]}^2}\ \right\} \times 0.5$

- where p hat is the fixed effects pooled proportion, x is the Freeman-Tukey transformed proportion, w is the inverse variance weight for the transformed proportion, q is the Cochran q statistic, tau squared is the moment-based estimate of the between-studies variance, w r is the DerSimonian-Laird weight, p hat r is the random effects estimate of the pooled proportion, and n in the back-transforms to p hat and p hat r is the harmonic mean of the study sample sizes.

 

An alternative, simpler, back transform (Stuart-Ord), which is the default choice of inverse transform in StatsDirect, is:

$\displaystyle \hat p=\sin (\hat x/2)^2$

This form is strictly less accurate than the Miller method above but it is less susceptible to the bias effects of non-linear transformations, giving more credible estimates of pooled proportions where the true population value is close to 0 or 1.

 

 

Example

The following data represent adherence with medication from 22 fictitious trials of a class of drug:

 

Trial Adherent Total
Brown 214 311
Lamont 58 65
Lally 59 67
Orwell 182 285
Wagner 65 73
Werner 66 116
Venner 99 183
Adams 600 696
Brenner 45 57
Borrowdale 165 277
Byers 32 35
Daniels 49 60
Darling 175 199
Ehert 155 311
Fern 64 81
Mullen 526 537
Orton 104 107
Jones 97 102
Ning 2310 4612
Sherraton 72 91
Zu 37 37
Tarone 31 87

 

To analyse these data in StatsDirect first prepare them in three workbook columns and label these columns appropriately. Alternatively, open the test workbook using the file open function of the file menu. Then select proportion from the meta-analysis section of the analysis menu, and then select the columns 'Total', 'Adherent' and 'Trial' as prompted.

 

For this example:

 

Method: Stuart-Ord (inverse double arcsine square root)

 

Stratum Proportion 95% CI (exact)  
1 0.688103 0.633392 0.739187 Brown
2 0.892308 0.790618 0.955591 Lamont
3 0.880597 0.778215 0.947015 Lally
4 0.638596 0.579853 0.694424 Orwell
5 0.890411 0.795436 0.951484 Wagner
6 0.568966 0.473763 0.660561 Werner
7 0.540984 0.465895 0.614723 Venner
8 0.862069 0.834196 0.886827 Adams
9 0.789474 0.66113 0.88621 Brenner
10 0.595668 0.5353 0.653966 Borrowdale
11 0.914286 0.769425 0.981962 Byers
12 0.816667 0.695604 0.904764 Daniels
13 0.879397 0.825884 0.921178 Darling
14 0.498392 0.441461 0.555354 Ehert
15 0.790123 0.685373 0.872724 Fern
16 0.979516 0.963644 0.989731 Mullen
17 0.971963 0.920245 0.99418 Orton
18 0.95098 0.889304 0.983894 Jones
19 0.500867 0.486332 0.515402 Ning
20 0.791209 0.693308 0.869362 Sherraton
21 1 0.905109 1 Zu [97.5% one-sided CI]
22 0.356322 0.256493 0.466236 Tarone

 

Stratum Standardized effect Variance % Weights (fixed, random)  
1 1.955196 0.00321 3.708333 4.657589 Brown
2 2.45427 0.015267 0.779762 4.459405 Lamont
3 2.419139 0.014815 0.803571 4.466536 Lally
4 1.850661 0.003503 3.39881 4.652575 Orwell
5 2.450333 0.013605 0.875 4.485712 Wagner
6 1.707983 0.008584 1.386905 4.56713 Werner
7 1.65241 0.00545 2.184524 4.619459 Venner
8 2.379077 0.001436 8.291667 4.688254 Adams
9 2.176196 0.017391 0.684524 4.426224 Brenner
10 1.762619 0.003604 3.303571 4.650846 Borrowdale
11 2.508913 0.028169 0.422619 4.265199 Byers
12 2.243481 0.016529 0.720238 4.439636 Daniels
13 2.426484 0.005013 2.375 4.626852 Darling
14 1.567591 0.00321 3.708333 4.657589 Ehert
15 2.181244 0.01227 0.970238 4.50708 Fern
16 2.848202 0.00186 6.39881 4.680878 Mullen
17 2.780486 0.009302 1.279762 4.555298 Orton
18 2.675681 0.009756 1.220238 4.547858 Jones
19 1.572531 0.000217 54.910714 4.709554 Ning
20 2.184792 0.010929 1.089286 4.528741 Sherraton
21 2.978651 0.026667 0.446429 4.286939 Zu [97.5% one-sided CI]
22 1.282717 0.011429 1.041667 4.520646 Tarone

 

Fixed effects (inverse variance)

Pooled proportion = 0.63958 (95% CI = 0.629281 to 0.649814)

 

Non-combinability of studies

Cochran Q = 1553.004499 (df = 21) P < 0.0001

Moment-based estimate of between studies variance = 0.268086

I² (inconsistency) = 98.6% (95% CI = 98.5% to 98.8%)

 

Random effects (DerSimonian-Laird)

Pooled proportion = 0.785824 (95% CI = 0.689259 to 0.868571)

 

Bias indicators

Begg-Mazumdar: Kendall's tau = -0.272727 P = 0.0803

Egger: bias = -0.692257 (90% CI = -7.606501 to 6.221986) P = 0.8646

Harbord: bias = 6.349191 (90% CI = 2.914719 to 9.783663) P = 0.0046

 

The differences between trials are very large (99% inconsistency), therefore a random effects model should be followed. The weights table shows both the fixed and random effects weights – the random effects weights used to calculate the pooled proportion are similar across the studies, unlike the fixed effects weights. We conclude that the adherence for this class of drug is approximately 79%, and with 95% confidence at least 69%. Of the bias indicators, only Harbord's test points to small-study effects: the smaller trials reported higher adherence than the pooled proportion predicts.

R code

This R code reproduces the example above. It needs no packages and was checked with R 4.6.1. Paste it into R, or save it as a script and run it.

# Proportion meta-analysis: the StatsDirect help example (adherence with medication in
# 22 fictitious trials; the test workbook's Meta-analysis worksheet columns Trial,
# Adherent and Total) in R
trial <- c("Brown", "Lamont", "Lally", "Orwell", "Wagner", "Werner", "Venner", "Adams",
           "Brenner", "Borrowdale", "Byers", "Daniels", "Darling", "Ehert", "Fern",
           "Mullen", "Orton", "Jones", "Ning", "Sherraton", "Zu", "Tarone")
adherent <- c(214, 58, 59, 182, 65, 66, 99, 600, 45, 165, 32, 49, 175, 155, 64, 526,
              104, 97, 2310, 72, 37, 31)
total <- c(311, 65, 67, 285, 73, 116, 183, 696, 57, 277, 35, 60, 199, 311, 81, 537,
           107, 102, 4612, 91, 37, 87)

# Base R has no meta-analysis function, so the pooled proportions are computed as the
# formulae above give them: each proportion is transformed by the Freeman-Tukey double
# arcsine, pooled with inverse variance weights (n + 0.5), and the pooled transform is
# taken back to a proportion by the Stuart-Ord inverse, sin(x/2)^2
six <- function(x) formatC(x, digits = 6, format = "f", drop0trailing = TRUE)
pv <- function(p) {
  if (p < 0.0001) "P < 0.0001" else
    paste("P =", formatC(p, digits = 4, format = "f", drop0trailing = TRUE))
}
k <- length(total)
z <- qnorm(0.975)
p <- adherent / total

# Each study's proportion with its exact (Clopper-Pearson) 95% confidence interval, as
# binom.test() gives it; when every subject responds, as in the Zu trial, the interval
# is one sided and its lower limit is the 97.5% limit
ci <- t(sapply(seq_len(k), function(i) binom.test(adherent[i], total[i])$conf.int))
one_sided <- ifelse(adherent == 0 | adherent == total, "[97.5% one-sided CI]", "")
cat("Method: Stuart-Ord (inverse double arcsine square root)\n")
print(data.frame(Study = seq_len(k), Proportion = six(p), Lower = six(ci[, 1]),
                 Upper = six(ci[, 2]), Trial = paste(trial, one_sided)),
      row.names = FALSE, right = FALSE)

# The transformed proportions, their variances and the fixed and random effects weights
x <- asin(sqrt(adherent / (total + 1))) + asin(sqrt((adherent + 1) / (total + 1)))
v <- 1 / (total + 0.5)
w <- 1 / v
xf <- sum(w * x) / sum(w)
se_f <- 1 / sqrt(sum(w))
q <- sum(w * (x - xf)^2)
tau2 <- max(0, (q - (k - 1)) / (sum(w) - sum(w^2) / sum(w)))
wr <- 1 / (tau2 + v)
xr <- sum(wr * x) / sum(wr)
se_r <- 1 / sqrt(sum(wr))
print(data.frame(Study = seq_len(k), Transform = six(x), Variance = six(v),
                 Fixed = six(100 * w / sum(w)), Random = six(100 * wr / sum(wr)),
                 Trial = paste(trial, one_sided)), row.names = FALSE, right = FALSE)

inv <- function(t) sin(t / 2)^2
cat("Fixed effects (inverse variance)\n")
cat("Pooled proportion = ", six(inv(xf)), " (95% CI = ", six(inv(xf - z * se_f)),
    " to ", six(inv(xf + z * se_f)), ")\n", sep = "")

# Cochran's Q against chi-square on k - 1 df, the DerSimonian-Laird estimate of the
# between-studies variance, and I-squared, which is lambda / (df + lambda) for the
# noncentrality parameter lambda = Q - df, with the confidence interval that StatsDirect
# gives by default (the noncentral chi-square method of Hedges and Pigott): the lambda
# at which the observed Q is the 97.5% point of the noncentral chi-square distribution
# on df degrees of freedom, and the lambda at which it is the 2.5% point, each turned
# into an I-squared; a limit is 0 when the central distribution already puts Q below
# that point
cat("Non-combinability of studies\n")
cat("Cochran Q = ", six(q), "  (df = ", k - 1, ")  ",
    pv(pchisq(q, k - 1, lower.tail = FALSE)), "\n", sep = "")
cat("Moment-based estimate of between studies variance =", six(tau2), "\n")
df <- k - 1
i2 <- function(lambda) 100 * lambda / (df + lambda)
lambda_at <- function(prob) {
  if (pchisq(q, df) < prob) return(0)
  uniroot(function(l) pchisq(q, df, ncp = l) - prob, c(0, 10 * (q + df)),
          tol = 1e-10)$root
}
one <- function(x) formatC(x, digits = 1, format = "f")
cat("I2 (inconsistency) = ", one(i2(max(0, q - df))), "% (95% CI = ",
    one(i2(lambda_at(0.975))), "% to ", one(i2(lambda_at(0.025))), "%)\n", sep = "")

cat("Random effects (DerSimonian-Laird)\n")
cat("Pooled proportion = ", six(inv(xr)), " (95% CI = ", six(inv(xr - z * se_r)),
    " to ", six(inv(xr + z * se_r)), ")\n", sep = "")

# Bias indicators, all on the proportion scale with each study's standard error taken
# from its exact confidence interval. Begg-Mazumdar: Kendall's tau between the
# standardised deviates from the pooled proportion and the variances, with the exact P
# that cor.test() gives when there are no ties. Egger: the intercept of the regression
# of the standardised proportion on precision, with a 90% interval and its t test
cat("Bias indicators\n")
se <- (ci[, 2] - ci[, 1]) / 2 / z
wx <- 1 / se^2
ts <- (p - sum(p * wx) / sum(wx)) / sqrt(se^2 - 1 / sum(wx))
begg <- cor.test(ts, se^2, method = "kendall")
cat("Begg-Mazumdar: Kendall's tau =", six(begg$estimate), " ", pv(begg$p.value), "\n")
egger <- lm(I(p / se) ~ I(1 / se))
cat("Egger: bias = ", six(coef(egger)[1]), " (90% CI = ",
    six(confint(egger, level = 0.9)[1, 1]), " to ",
    six(confint(egger, level = 0.9)[1, 2]), ")  ",
    pv(summary(egger)$coefficients[1, 4]), "\n", sep = "")

# Harbord's test as StatsDirect adapts it to proportions: each study's score is the
# excess of responders over the number expected at the pooled fixed effects proportion,
# with the binomial variance, and the bias is the intercept of the regression of
# score / sqrt(variance) on sqrt(variance)
pf <- inv(xf)
score <- adherent - total * pf
vs <- total * pf * (1 - pf)
harbord <- lm(I(score / sqrt(vs)) ~ sqrt(vs))
cat("Harbord: bias = ", six(coef(harbord)[1]), " (90% CI = ",
    six(confint(harbord, level = 0.9)[1, 1]), " to ",
    six(confint(harbord, level = 0.9)[1, 2]), ")  ",
    pv(summary(harbord)$coefficients[1, 4]), "\n", sep = "")

# The report's charts: a funnel plot of each proportion against its standard error,
# with the pooled fixed effects proportion and its 95% limits, then a forest plot for
# each model with the studies in order from the top and the pooled estimate at the foot
plot(p, se, ylim = rev(c(0, max(se))), xlim = c(0, 1), xlab = "Proportion",
     ylab = "Standard error", main = "Bias assessment plot")
abline(v = pf)
s <- seq(0, max(se), length.out = 50)
lines(pf - z * s, s, lty = 2)
lines(pf + z * s, s, lty = 2)
forest <- function(est, lower, upper, weight, title) {
  rows <- c(trial, "combined")
  y <- rev(seq_along(rows))
  old <- par(mar = c(5, 7, 4, 10))
  plot(est, y, type = "n", xlim = c(0, 1), yaxt = "n", ylab = "",
       xlab = "proportion (95% confidence interval)", main = title)
  segments(lower, y, upper, y)
  points(est[1:k], y[1:k], pch = 15, col = "grey", cex = 3 * sqrt(weight / max(weight)))
  points(est[1:k], y[1:k], pch = 20)
  points(est[k + 1], y[k + 1], pch = 18, cex = 2)
  abline(v = est[k + 1], lty = 3)
  axis(2, at = y, labels = rows, las = 1, tick = FALSE, cex.axis = 0.7)
  axis(4, at = y, tick = FALSE, las = 1, cex.axis = 0.7,
       labels = sprintf("%.2f (%.2f, %.2f)", est, lower, upper))
  par(old)
}
forest(c(p, inv(xf)), c(ci[, 1], inv(xf - z * se_f)), c(ci[, 2], inv(xf + z * se_f)), w,
       "Proportion meta-analysis plot [fixed effects]")
forest(c(p, inv(xr)), c(ci[, 1], inv(xr - z * se_r)), c(ci[, 2], inv(xr + z * se_r)),
       wr, "Proportion meta-analysis plot [random effects]")

# The Miller inverse, the other choice of back-transform in StatsDirect: the exact
# inverse of the double arcsine at n = the harmonic mean of the study sizes
hm <- k / sum(1 / total)
ft <- function(r, n) asin(sqrt(r / (n + 1))) + asin(sqrt((r + 1) / (n + 1)))
miller <- function(t) {
  # beyond the range of the transform at n = hm the exact inverse folds back, so
  # StatsDirect returns 0 or 1 there
  if (t > ft(hm, hm)) return(1)
  if (t < ft(0, hm)) return(0)
  0.5 * (1 - sign(cos(t)) * sqrt(1 - (sin(t) + (sin(t) - 1 / sin(t)) / hm)^2))
}
cat("Method: Miller (exact inverse Freeman-Tukey double arcsine)\n")
cat("Fixed effects pooled proportion = ", six(miller(xf)), " (95% CI = ",
    six(miller(xf - z * se_f)), " to ", six(miller(xf + z * se_f)), ")\n", sep = "")
cat("Random effects pooled proportion = ", six(miller(xr)), " (95% CI = ",
    six(miller(xr - z * se_r)), " to ", six(miller(xr + z * se_r)), ")\n", sep = "")
# Harbord's score is taken from the Miller pooled proportion here, so the test moves
pf <- miller(xf)
score <- adherent - total * pf
vs <- total * pf * (1 - pf)
harbord <- lm(I(score / sqrt(vs)) ~ sqrt(vs))
cat("Harbord: bias = ", six(coef(harbord)[1]), " (90% CI = ",
    six(confint(harbord, level = 0.9)[1, 1]), " to ",
    six(confint(harbord, level = 0.9)[1, 2]), ")  ",
    pv(summary(harbord)$coefficients[1, 4]), "\n", sep = "")