---
title: "Getting started with respondeR"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting started with respondeR}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

```{r setup}
library(respondeR)
```

## The idea

Trials of continuous outcomes usually report a **mean change** and **standard
deviation** in each arm. Those are hard to communicate: a standardized mean
difference of 0.3 means little to a patient. A **responder analysis** translates
the continuous result into something concrete: the proportion of patients who
improve by at least a **minimal important difference (MID)**. It contrasts the
arms on familiar scales: risk difference, risk ratio, odds ratio, number needed
to treat.

respondeR does this from summary statistics alone, using the cut-point approach
of Anzures-Cabrera, Sarpatwari & Higgins (2011). It never needs individual
patient data.

## Data format

One row per study (or per comparison). The experimental arm columns end in `_e`,
the control arm in `_c`:

```{r}
sample_responder_data
```

| Column | Meaning |
|--------|---------|
| `study` | Study (comparison) label |
| `change_e`, `change_c` | Mean change per arm |
| `sd_e`, `sd_c` | SD of change per arm |
| `n_e`, `n_c` | Sample size per arm |
| `trial` (optional) | Trial label, shared by the comparisons of one multi-arm trial |

If a trial reports baseline and final SDs instead of the SD of the change,
reconstruct it with `impute_change_sd()` (and vary the assumed correlation as a
sensitivity analysis):

```{r}
impute_change_sd("prepost", sd_baseline = 2.1, sd_final = 2.4, r = 0.5)
```

## A first analysis

Suppose a change above `1` is clinically meaningful. With the default settings,
`responder_analysis()` returns one row per pooling method, printed as a compact
table with the number needed to treat:

```{r}
res <- responder_analysis(sample_responder_data, mid = 1)
res
```

* **PE** and **PC** are the experimental and control responder proportions.
* **RD**, **RR** and **OR** are the between-arm contrasts with confidence
  intervals; **NNT** is the number needed to treat for one more responder
  (NNTB), or for one fewer (NNTH).
* The `individual` method pools per-study contrasts, so it has no single pair
  of pooled proportions (shown as "-").

The result is still a data frame, so columns are available directly, and
`as.data.frame()` gives every column, including the heterogeneity statistics:

```{r}
res$rd
head(as.data.frame(res), 2)
```

`summary(res)` adds the settings and the per-study weights.

## Which way is "better"?

By default a *higher* change is a response. For outcomes where *lower* is better
(pain, symptom scores), set `direction = "lower"` and give the MID as the
required change (for example `mid = -1.5` for a 1.5-point reduction).

## Per-study results and a forest plot

`responder_rd_individual()` returns the per-study risk differences, and
`plot()` draws them with the pooled estimates:

```{r}
responder_rd_individual(sample_responder_data, mid = 1)
```

```{r, fig.width = 6.5, fig.height = 3.4, fig.alt = "Forest plot of per-study responder risk differences with pooled estimates"}
plot(res)
```

## Random effects and heterogeneity

When studies disagree, use random effects. With few studies, prefer the
Hartung-Knapp-Sidik-Jonkman interval with its ad hoc floor
(`ci_method = "hksj_adhoc"`), which is never narrower than the Wald interval:

```{r}
responder_analysis(sample_responder_data, mid = 1, method = "individual",
                   pooling = "random", ci_method = "hksj_adhoc")
```

## How much does the MID matter?

`responder_curve()` repeats the analysis across thresholds. Report the curve,
not just one value; open circles mark thresholds where a single study would hold
most of the weight.

```{r, fig.width = 6, fig.height = 3.6, fig.alt = "Pooled risk difference against the MID threshold with pointwise confidence bands"}
curve <- responder_curve(sample_responder_data, mids = seq(0, 2, by = 0.25))
plot(curve, at = 1)
```

## Summary-of-findings rows

`responder_sof()` turns the pooled relative effect into absolute effects per
1000 patients at an assumed control risk, by default the median control-arm
responder risk, in GRADE wording. Give several control risks for low, moderate
and high baseline risk:

```{r}
ind <- responder_analysis(sample_responder_data, mid = 1, method = "individual")
responder_sof(ind)
responder_sof(ind, control_risk = c(0.1, 0.4))
```

## A threshold-free alternative

Choosing a MID is sometimes contentious. The common-language effect size sidesteps
it: the probability that a randomly chosen treated patient has a better change
than a randomly chosen control.

```{r}
cles <- responder_cles(sample_responder_data)
sprintf("CLES = %.1f%% (%.1f%% to %.1f%%)",
        100 * cles$cles, 100 * cles$cles_lb, 100 * cles$cles_ub)
```

## A real example: VAS pain after exercise therapy

The package bundles a real dataset, `vas_pain`: the 20 exercise-versus-control
comparisons pooled for the visual analogue scale (VAS) pain outcome by Li, Bao,
Wang and Zhao (2025). Change scores are post minus baseline VAS on a 0 to 10 cm
scale, so a more negative value is a larger pain reduction. Two of the trials had
three arms and share one control group between two comparisons; the `trial`
column marks them and respondeR splits each shared control arm so it is not
counted twice. Using a 1.5 cm reduction as the MID:

```{r}
vas <- responder_analysis(vas_pain, mid = -1.5, direction = "lower",
                          pooling = "random", ci_method = "hksj_adhoc")
vas
```

```{r, include = FALSE}
v <- as.data.frame(vas)
ind_rd <- round(100 * v$rd[v$method == "individual"])
```

Pooling the per-study estimates (the `individual` method, which keeps every
comparison within its randomized trial), about `r ind_rd` more exercise patients
per 100 reach a 1.5 cm pain reduction than controls. The descriptive
`unweighted` and `median` summaries are larger and more dispersed; that spread
reflects the heterogeneity across trials (I-squared above 50 percent), and they
carry no interval. In summary-of-findings form:

```{r}
responder_sof(vas[vas$method == "individual", ])
```

and without any threshold:

```{r}
cles <- responder_cles(vas_pain, direction = "lower", pooling = "random")
sprintf("A treated patient has less pain than a control %.0f%% of the time (%.0f%% to %.0f%%)",
        100 * cles$cles, 100 * cles$cles_lb, 100 * cles$cles_ub)
```

(Data from Li et al. (2025), Frontiers in Sports and Active Living,
doi:10.3389/fspor.2025.1614906, Figure 3, reproduced under CC BY 4.0.)

## Fitted meta-analyses

If you already have a `meta::metacont()` or `metafor::rma()` fit, pass it to
`responder_analysis()` directly; see `vignette("meta-analysis-objects")`.

## The Shiny application

Everything above is available in a point-and-click app:

```{r, eval = FALSE}
launch_responder_analysis()
```

The same tool runs in the browser, with no installation, at
<https://choxos.github.io/respondeR/app/>.

## Where next

See `vignette("methodology")` for the full statistical detail: each method's
estimator and variance, the relative measures, the SMD bridge, the interval
options, assumptions and a method-choice guide.
