Skip to content

Coming from R

metafopy is built so that metafor code translates line by line. This page lists the rules of the translation. Where metafopy does not behave like metafor, see Differences from metafor, which is kept up to date with every known deviation.

The same analysis in both languages

R:

library(metafor)
dat <- escalc(measure="RR", ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg)
res <- rma(yi, vi, mods = ~ ablat, data=dat)
print(res)
predict(res, newmods=c(10, 30, 50), transf=exp)
confint(res)
forest(res, atransf=exp)

Python:

import numpy

from metafopy import confint, datasets, escalc, forest, predict, rma

dat = escalc(measure='RR', ai='tpos', bi='tneg', ci='cpos', di='cneg', data=datasets.load('dat.bcg'))
res = rma('yi', 'vi', mods='~ ablat', data=dat)
print(res)
print(predict(res, newmods=[10, 30, 50], transf=numpy.exp))
print(confint(res))
forest(res, atransf=numpy.exp)
Mixed-Effects Model (k = 13; tau^2 estimator: REML)

tau^2 (estimated amount of residual heterogeneity):     0.0764 (SE = 0.0591)
tau (square root of estimated tau^2 value):             0.2763
I^2 (residual heterogeneity / unaccounted variability): 68.39%
H^2 (unaccounted variability / sampling variability):   3.16
R^2 (amount of heterogeneity accounted for):            75.62%

Test for Residual Heterogeneity:
QE(df = 11) = 30.7331, p-val = 0.0012

Test of Moderators (coefficient 2):
QM(df = 1) = 16.3571, p-val < .0001

Model Results:

         estimate      se     zval    pval    ci.lb    ci.ub
intrcpt    0.2515  0.2491   1.0095  0.3127  -0.2368   0.7397
ablat     -0.0291  0.0072  -4.0444  <.0001  -0.0432  -0.0150  ***

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

     pred   ci.lb   ci.ub   pi.lb   pi.ub
0  0.9612  0.6668  1.3857  0.5000  1.8478
1  0.5371  0.4355  0.6623  0.3005  0.9600
2  0.3001  0.2144  0.4201  0.1586  0.5678
        estimate    ci.lb    ci.ub
tau^2     0.0764   0.0167   0.7849
tau       0.2763   0.1292   0.8859
I^2(%)   68.3931  32.1080  95.6976
H^2       3.1639   1.4729  23.2428

The printed output is the same as metafor's.

Rules

In R In metafopy
rma.uni, rma.mv, leave1out rma_uni, rma_mv, leave1out: . becomes _
ci.lb, tau2, QE ci_lb, tau2, QE: fields of the result, . becomes _
res$beta, res$se, coef(res) res.beta, res.se
dat.bcg (lazy-loaded) datasets.load('dat.bcg')
tpos, tneg (unquoted columns, data=dat) 'tpos', 'tneg' (strings naming columns of data=) or arrays
mods = ~ ablat + year mods='~ ablat + year' (a string; formulaic syntax)
random = ~ 1 \| study/esid random='~ 1 \| study/esid'
random = list(~ 1 \| a, ~ 1 \| b) random=['~ 1 \| a', '~ 1 \| b']
btt = 2:3 (1-based) btt=[1, 2] (0-based)
subset = year > 1950 subset=dat['year'] > 1950 (a boolean array)
transf = exp transf=numpy.exp
TRUE / FALSE, NULL, NA True / False, None, numpy.nan
control = list(tau2.max = 10) control={'tau2_max': 10}, or a Control / MVControl instance
set.seed(1234) set_seed(1234) (R's generator, so permutation tests reproduce R)
summary(res) res.summary(): print(res) plus the fit-statistics table (str(res) is print(res))
plot(res) family, forest(res) functions on matplotlib axes: forest, funnel, plot_infl...

Names that metafor writes with . in the middle of a word also lose it in prefixed functions: plot.gosh is plot_gosh, plot.infl.rma.uni is plot_infl, plot.profile.rma is plot_profile, plot.selmodel is plot_selmodel, and transf.ilogit is transf_ilogit. The transformations are also a module: transf.ilogit is metafopy.transf.ilogit (the same function as metafopy.transf_ilogit), so from metafopy import transf keeps metafor's spelling.

Classes and generic functions

R's S3 classes (rma.uni, rma.mv, escalc...) become frozen dataclasses (RMAResult, RMAMVResult...) and escalc returns a plain pandas.DataFrame whose attrs carry the attributes metafor stores on the data frame. R's generic functions (predict, confint, anova, profile, influence...) are single-dispatch functions that choose the implementation from the class of the result. predict(res, ...) works as in R. The implementations for each class are documented in the reference.

Numbers

metafopy is validated against metafor 5.2-1. The test suite compares the results of the models with R fixtures: closed-form quantities agree to rounding error, and quantities found by numerical optimisation agree to the optimiser's tolerance. The exact tolerances and the cases that differ more are in Differences from metafor.

What is not ported

reporter() is not ported. emmprep and emmeans' reference grid, marginal means and contrasts are ported natively; see the guide. See Differences from metafor for details and for the places where a metafor feature behaves differently.