Skip to content

Binary and count data

For 2x2 tables (events and non-events in a treatment and a control group) and for event counts with person-time, the data can be analysed in several ways. All of them take the raw counts, so you do not call escalc yourself.

Function Method Measures
rma_uni Inverse-variance, on escalc effect sizes any
rma_mh Mantel-Haenszel OR, RR, RD, IRR, IRD
rma_peto Peto's one-step method OR
rma_glmm Generalized linear mixed-effects models OR, IRR, PLO, IRLN and the experimental measures

The arguments are the same throughout: ai, bi, ci, di for the cells of the table (events and non-events in the treatment and control group), or ai, n1i, ci, n2i with the group sizes, and data=.

Mantel-Haenszel

Mantel-Haenszel pooling (Mantel and Haenszel, 1959, https://doi.org/10.1093/jnci/22.4.719) behaves well with sparse data, and needs no continuity correction for studies with a zero in a single cell. It is an equal-effects method.

from metafopy import datasets, rma_mh

bcg = datasets.load('dat.bcg')
print(rma_mh(ai='tpos', bi='tneg', ci='cpos', di='cneg', data=bcg, measure='RR'))
Equal-Effects Model (k = 13)

I^2 (total heterogeneity / total variability):  92.13%
H^2 (total variability / sampling variability): 12.71

Test for Heterogeneity:
Q(df = 12) = 152.5676, p-val < .0001

Model Results (log scale):

estimate      se      zval    pval    ci.lb    ci.ub
 -0.4537  0.0393  -11.5338  <.0001  -0.5308  -0.3766

Model Results (RR scale):

estimate   ci.lb   ci.ub
  0.6353  0.5881  0.6862

Peto's method

Peto's method (Yusuf et al., 1985, https://doi.org/10.1016/S0033-0620(85)80003-7) works on the observed minus expected number of events and is accurate for rare events and balanced groups:

from metafopy import rma_peto

print(rma_peto(ai='tpos', bi='tneg', ci='cpos', di='cneg', data=bcg))
Equal-Effects Model (k = 13)

I^2 (total heterogeneity / total variability):  92.85%
H^2 (total variability / sampling variability): 13.98

Test for Heterogeneity:
Q(df = 12) = 167.7302, p-val < .0001

Model Results (log scale):

estimate      se      zval    pval    ci.lb    ci.ub
 -0.4744  0.0407  -11.6689  <.0001  -0.5541  -0.3948

Model Results (OR scale):

estimate   ci.lb   ci.ub
  0.6222  0.5746  0.6738

Generalized linear mixed-effects models

rma_glmm fits the exact binomial or Poisson likelihood with random effects, which avoids the normal approximation and the continuity corrections of the inverse-variance method. This is the best choice for sparse data, and it is slower. Choose the model with model: 'UM.FS' and 'UM.RS' are unconditional models with fixed or random study effects, 'CM.AL' and 'CM.EL' are conditional models (approximate and exact likelihood). See Stijnen et al. (2010), https://doi.org/10.1002/sim.4040.

from metafopy import rma_glmm

print(rma_glmm(ai='tpos', bi='tneg', ci='cpos', di='cneg', data=bcg, measure='OR', model='UM.FS'))
Random-Effects Model (k = 13; tau^2 estimator: ML)
Model Type: Unconditional Model with Fixed Study Effects

tau^2 (estimated amount of total heterogeneity): 0.2949
tau (square root of estimated tau^2 value):      0.5430
I^2 (total heterogeneity / total variability):   91.02%
H^2 (total variability / sampling variability):  11.14

Tests for Heterogeneity:
Wld(df = 12) = 163.1649, p-val < .0001
LRT(df = 12) = 176.9544, p-val < .0001

Model Results:

estimate      se     zval    pval    ci.lb    ci.ub
 -0.7450  0.1756  -4.2436  <.0001  -1.0891  -0.4009  ***

---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

rma_glmm accepts moderators (mods='~ ablat'). predict, blup and ranef work on its result. Mixed-model fits can differ slightly from R, because lme4 stops at a looser optimiser tolerance; see Differences from metafor.

As in metafor, control={'package': 'GLMMadaptive'} fits the mixed models with adaptive Gauss-Hermite quadrature (Pinheiro and Bates, 1995; GLMMadaptive) and control={'package': 'glmmTMB'} with the Laplace approximation (Brooks et al., 2017); nAGQ is ignored by glmmTMB.

For the conditional model CM.EL with method='FE', control={'optimizer': 'clogit'} or 'clogistic' fit it with the partial likelihood of survival::clogit or Epi::clogistic. link= and family= change the link function or the family of the unconditional models.

The other optimisers of rma.glmm are available for CM.EL too (control={'optimizer': 'BFGS'}, 'Nelder-Mead', or 'optim' with optmethod=, optCtrl={'maxit': ...}, and 'CG', 'L-BFGS-B', 'nlm', 'bobyqa', ...). optim's BFGS and Nelder-Mead are exact ports of R's routines; the rest use the closest SciPy method. control={'hesspack': 'pracma'} or 'calculus' (default 'numDeriv') and control={'hessianCtrl': {...}} choose how the Hessian of CM.EL is computed. control={'dnchgcalc': 'dnoncenhypergeom'} or 'dFNCHypergeo' and control={'dnchgprec': 1e-10} choose the density of the non-central hypergeometric distribution; naming 'dFNCHypergeo' or a precision uses a port of BiasedUrn's algorithm, including the truncation of its tails. See differences from metafor for what can differ.

Rates

For incidence rates, pass the event counts x1i, x2i and the person-time t1i, t2i, with measure='IRR':

from metafopy import escalc

print(escalc(measure='IRR', x1i=[3, 5], t1i=[100, 120], x2i=[7, 4], t2i=[110, 90])[['yi', 'vi']])
         yi       vi
0 -0.751988  0.47619
1 -0.064539  0.45000

Zero cells

Studies with a zero cell need a continuity correction for the inverse-variance method. add, to and drop00 control it and have the same meaning in escalc, rma_uni, rma_mh, rma_peto and rma_glmm. Studies with no events in both groups carry no information about the relative effect and are dropped by rma_mh and rma_peto (drop00=True). Sweeting et al. (2004), https://doi.org/10.1002/sim.1761, discuss the alternatives.