--- title: "Responder analysis from a fitted meta-analysis" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Responder analysis from a fitted meta-analysis} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(respondeR) ``` You often already have a continuous meta-analysis fitted and saved in an R object. respondeR can read that object directly and express it as responder risks, so you do not have to rebuild the arm-level data frame by hand. It reads the saved object with base R, so the package that produced it (for example *meta* or *metafor*) does not even need to be attached. There are two situations, handled automatically: * the object **carries the per-arm summaries** (a `metacont` from *meta*): it is converted to the data-frame form and analyzed with the full method menu; * the object **carries only the pooled relative effect** (a *metafor* `rma` fit): it is converted with `responder_from_effect()`, and you supply a baseline control responder risk (by name: `baseline = `). ## From a `meta` (metacont) object A `metacont` object stores both arms, so respondeR can run the complete analysis. You would normally create it like this: ```{r, eval = FALSE} library(meta) fit <- metacont( n.e = n_e, mean.e = change_e, sd.e = sd_e, n.c = n_c, mean.c = change_c, sd.c = sd_c, studlab = study, data = sample_responder_data ) responder_analysis(fit, mid = 1) ``` A `metacont` object is, in the end, a list with the per-arm fields respondeR reads (`mean.e`, `sd.e`, `n.e`, `mean.c`, `sd.c`, `n.c`, `studlab`). To keep this vignette runnable without *meta* installed, here is the same object built by hand: ```{r} d <- sample_responder_data fit_meta <- structure( list( studlab = d$study, n.e = d$n_e, mean.e = d$change_e, sd.e = d$sd_e, n.c = d$n_c, mean.c = d$change_c, sd.c = d$sd_c, sm = "MD" ), class = c("metacont", "meta") ) responder_analysis(fit_meta, mid = 1)[, c("method", "p_e", "p_c", "rd", "rr", "or")] ``` That is identical to calling `responder_analysis()` on the data frame; all the usual arguments (`direction`, `method`, `pooling`, `control`, ...) pass straight through. The fitted object's own choices carry over unless you override them: studies excluded from the fit (its `exclude` argument) are dropped, a random-effects fit (`common = FALSE, random = TRUE`) sets `pooling = "random"`, its `method.tau` (DL or REML) sets `tau_method`, and a Hartung-Knapp fit sets `ci_method = "hksj"`. Repeated study labels (the comparisons of a multi-arm trial) become a `trial` column, so a shared control arm is split rather than double counted. If you only want the extracted data frame, use `as_responder_data()`. ## From a `metafor` `rma` object An `rma` fit keeps the pooled relative effect, not the arms. respondeR reads the estimate, its standard error, its confidence interval (so a Knapp-Hartung `t` interval and the fit's confidence level are kept) and the effect measure, then converts. Because the arms are gone, you must tell it the **baseline** control responder risk (as a probability, or as a control mean and SD), by name. Meta-regressions, models without an intercept and raw-mean measures are rejected. ```{r, eval = requireNamespace("metafor", quietly = TRUE)} library(metafor) es <- escalc( measure = "SMD", m1i = change_e, sd1i = sd_e, n1i = n_e, m2i = change_c, sd2i = sd_c, n2i = n_c, data = d ) fit_rma <- rma(yi, vi, data = es) # A standardized mean difference, against a 22% control responder rate: responder_analysis(fit_rma, baseline = 0.22)[, c("method", "p_e", "p_c", "rd", "or")] ``` The effect is read as experimental minus control and oriented by `direction`. For pain, where a reduction is the response, a negative SMD is a benefit: ```{r, eval = requireNamespace("metafor", quietly = TRUE)} es_vas <- escalc( measure = "SMD", m1i = change_e, sd1i = sd_e, n1i = n_e, m2i = change_c, sd2i = sd_c, n2i = n_c, data = vas_pain ) fit_vas <- rma(yi, vi, data = es_vas, test = "knha") responder_analysis(fit_vas, baseline = 0.4, direction = "lower") ``` For a mean-difference model you also pass a reference within-arm SD (`sd_ref`), the scale on which the threshold lives, and you can give the baseline as a control mean and SD: ```{r, eval = requireNamespace("metafor", quietly = TRUE)} es_md <- escalc( measure = "MD", m1i = change_e, sd1i = sd_e, n1i = n_e, m2i = change_c, sd2i = sd_c, n2i = n_c, data = d ) fit_md <- rma(yi, vi, data = es_md) responder_analysis(fit_md, baseline = list(mean = 0, sd = 1.3), mid = 1, sd_ref = 1.3)[, c("method", "p_e", "p_c", "rd")] ``` ## From a bare estimate If all you have is a number from a paper (a pooled SMD or MD with its SE), call the engine directly: ```{r} # Pooled SMD of 0.5 (SE 0.1) vs a 25% control responder rate: responder_from_effect(0.5, se = 0.1, measure = "SMD", baseline = 0.25)[, c("method", "p_e", "p_c", "rd", "or")] ``` ## How the conversion works, and what it assumes For a **standardized mean difference** `g`, respondeR maps it to an odds ratio through the logistic distribution, `lnOR = (pi / sqrt(3)) g` (Hasselblad and Hedges, 1995; Chinn, 2000; Anzures-Cabrera, Sarpatwari & Higgins, 2011), then combines that odds ratio with the control responder proportion `p_c` to recover the experimental proportion and the risk difference, risk ratio, odds ratio and NNT. For a **mean difference** `MD`, respondeR shifts the control responder probability along the Normal cut-point: `p_e = Phi(Phi^-1(p_c) + MD / sigma)`, where `sigma` is the reference within-arm SD (`sd_ref`). This conversion assumes Normal change scores. Both risks depend on the same baseline, so when the baseline is estimated (a mean, SD and `n`) its uncertainty is propagated jointly with that of the effect. Two assumptions matter. First, the **baseline** is yours to choose: a defensible control responder rate, taken from a representative control arm or an external source, much as a GRADE summary-of-findings table fixes one baseline risk. A fixed baseline probability gives intervals conditional on it. Second, the **mean-difference path needs a reference SD**; pick the typical within-arm SD on the outcome scale, and report it. ## Coming next Support for network meta-analysis objects (`netmeta`) and Bayesian network meta-analysis / multilevel network meta-regression (`multinma`) is planned for a later release: each comparison or posterior draw will be converted to responder risks against a chosen baseline. ## References Thorlund, K., Walter, S. D., Johnston, B. C., Furukawa, T. A., & Guyatt, G. H. (2011). Pooling health-related quality of life outcomes in meta-analysis. *Research Synthesis Methods*, 2(3), 188 to 203. doi:10.1002/jrsm.46 Anzures-Cabrera, J., Sarpatwari, A., & Higgins, J. P. T. (2011). Expressing findings from meta-analyses of continuous outcomes in terms of risks. *Statistics in Medicine*, 30(25), 2967 to 2985. doi:10.1002/sim.4298 Chinn, S. (2000). A simple method for converting an odds ratio to effect size for use in meta-analysis. *Statistics in Medicine*, 19(22), 3127 to 3131. Hasselblad, V., & Hedges, L. V. (1995). Meta-analysis of screening and diagnostic tests. *Psychological Bulletin*, 117(1), 167 to 178.