---
title: "Comparing ML-UMR, STC, and Naive Methods"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Comparing ML-UMR, STC, and Naive Methods}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

## Why compare methods?

Unanchored indirect treatment comparisons (ITCs) rely on strong assumptions
that cannot be fully verified from data alone. Running multiple methods and
comparing their results is an important part of any ITC analysis:
a sensitivity check that reveals how conclusions depend on modeling choices.

mlumr provides three methods in a single package with a unified data
interface, making side-by-side comparison straightforward.

| Method | Adjustment | Framework | Key assumption |
|--------|-----------|-----------|----------------|
| Naive | None | Frequentist | Populations are exchangeable |
| STC | Outcome regression | Frequentist | Correct outcome model specification |
| ML-UMR SPFA | Joint Bayesian model | Bayesian | Shared prognostic effects (SPFA) |
| ML-UMR Relaxed | Joint Bayesian model | Bayesian | Correct specification and enough information/prior support for treatment-specific effects |

## Setup: shared data preparation

All three methods start from the same `mlumr_data` object. STC and ML-UMR
benefit from integration points; the naive method ignores them.

```{r, eval = TRUE, purl = FALSE}
library(mlumr)
set.seed(2026)

# --- Simulate IPD (index treatment) ---
n_A <- 500
age_A <- rbinom(n_A, 1, 0.40)
sex_A <- rbinom(n_A, 1, 0.55)

# True DGP: logit(p) = -0.5 + 0.8*age - 0.3*sex
logit_p_A <- -0.5 + 0.8 * age_A - 0.3 * sex_A
y_A <- rbinom(n_A, 1, plogis(logit_p_A))

ipd_df <- data.frame(
  trt = "Drug_A", outcome = y_A,
  age_group = age_A, sex = sex_A
)

# --- Simulate AgD (comparator) ---
# Same covariate effects, different intercept and covariate distribution
n_B <- 400
r_B <- 148  # pre-computed from true model with different covariates

agd_df <- data.frame(
  trt = "Drug_B", n_total = n_B, n_events = r_B,
  age_group_mean = 0.35, sex_mean = 0.50
)

# --- Prepare data ---
ipd <- set_ipd(ipd_df, treatment = "trt", outcome = "outcome",
               covariates = c("age_group", "sex"))
agd <- set_agd(agd_df, treatment = "trt",
               outcome_n = "n_total", outcome_r = "n_events",
               cov_means = c("age_group_mean", "sex_mean"),
               cov_types = c("binary", "binary"))

dat <- combine_data(ipd, agd)

# Add integration points (used by STC and ML-UMR)
dat <- add_integration(
  dat, n_int = 64,
  age_group = distr(qbern, prob = age_group_mean),
  sex = distr(qbern, prob = sex_mean)
)
```

## Running all three methods

### Naive estimate

```{r, eval = TRUE, purl = FALSE}
res_naive <- naive(dat)
print(res_naive)
```

The naive method ignores covariate differences between populations. It
serves as a reference: if naive and adjusted estimates agree, covariate
imbalance has little practical impact.

### STC estimate

```{r, eval = TRUE, purl = FALSE}
res_stc <- stc(dat)
print(res_stc)
```

STC fits a logistic regression on IPD and predicts counterfactual outcomes
for the comparator population via G-computation. The delta method provides
frequentist standard errors. STC is fast (sub-second) and a good default
when covariate adjustment is needed but a full Bayesian model is not
warranted.

### ML-UMR SPFA

```{r, eval = TRUE, purl = FALSE}
fit_spfa <- mlumr(
  dat, model = "spfa",
  prior_intercept = prior_normal(0, 10),
  prior_beta = prior_normal(0, 2.5),
  chains = 2, iter = 500, warmup = 250,
  seed = 42, refresh = 0, verbose = FALSE
)
summary(fit_spfa)
```

The SPFA model assumes shared covariate effects across treatments. It
jointly models both data sources and produces posterior distributions
for all parameters.

### ML-UMR Relaxed

```{r, eval = TRUE, purl = FALSE}
fit_relaxed <- mlumr(
  dat, model = "relaxed",
  prior_intercept = prior_normal(0, 10),
  prior_beta = prior_normal(0, 2.5),
  chains = 2, iter = 500, warmup = 250,
  seed = 43, refresh = 0, verbose = FALSE
)
summary(fit_relaxed)
```

The Relaxed model allows treatment-specific covariate coefficients,
capturing potential effect modification. Compare it with SPFA to assess
whether assuming shared effects is reasonable. With sparse AgD, relaxed-model
comparator coefficients can be prior-sensitive, so inspect `delta_beta` and
run prior-sensitivity checks when the relaxed model is central to the
interpretation.

## Building a comparison table

```{r, eval = TRUE, purl = FALSE}
# Extract ML-UMR marginal effects (LOR in comparator population)
me_spfa <- marginal_effects(fit_spfa, effect = "lor")
me_relaxed <- marginal_effects(fit_relaxed, effect = "lor")

# Comparator-population LORs from ML-UMR
lor_spfa <- me_spfa[me_spfa$population == "Comparator", ]
lor_relaxed <- me_relaxed[me_relaxed$population == "Comparator", ]

# Assemble results
comparison <- data.frame(
  Method = c("Naive", "STC", "ML-UMR SPFA", "ML-UMR Relaxed"),
  LOR = c(res_naive$link_effect, res_stc$link_effect, lor_spfa$mean, lor_relaxed$mean),
  SE = c(res_naive$se, res_stc$se, lor_spfa$sd, lor_relaxed$sd),
  CI_lower = c(res_naive$ci_lower, res_stc$ci_lower,
               lor_spfa$q2.5, lor_relaxed$q2.5),
  CI_upper = c(res_naive$ci_upper, res_stc$ci_upper,
               lor_spfa$q97.5, lor_relaxed$q97.5),
  stringsAsFactors = FALSE
)

# Add odds ratios for clinical interpretation
comparison$OR <- exp(comparison$LOR)
comparison$OR_lower <- exp(comparison$CI_lower)
comparison$OR_upper <- exp(comparison$CI_upper)

print(comparison, digits = 3)
```

## Interpreting differences between methods

### Naive vs STC

A large gap between naive and STC estimates indicates that covariate
imbalance is influencing the unadjusted comparison. The direction of the
shift reveals which population's covariates favor the outcome.

```{r, eval = TRUE, purl = FALSE}
bias_naive <- res_naive$link_effect - res_stc$link_effect
cat(sprintf("Apparent bias from covariate imbalance: %.3f (log OR scale)\n",
            bias_naive))
```

### STC vs ML-UMR SPFA

Under the shared prognostic factor assumption, STC and ML-UMR SPFA should
give similar point estimates because both adjust for the same covariates.
Differences arise because:

1. **STC** uses maximum likelihood; **ML-UMR** uses Bayesian inference with
   priors. With large samples, this difference is small.
2. **ML-UMR** jointly models both data sources; **STC** only uses AgD for
   prediction targets, not as a likelihood contribution.
3. ML-UMR uncertainty intervals tend to be wider because they account for
   more sources of uncertainty (prior, integration, joint modeling).

### SPFA vs Relaxed

```{r, eval = TRUE, purl = FALSE}
dic_comparison <- compare_models(fit_spfa, fit_relaxed)
print(dic_comparison)
```

If the Relaxed model gives markedly different LORs or substantially better
DIC, this *may* suggest effect modification -- covariate effects differ by
treatment. However, DIC is a rough metric with known limitations: it should
not be the sole basis for claiming effect modification. Always inspect
`delta_beta` credible intervals, prior sensitivity, and clinical plausibility.
If SPFA and Relaxed agree, the simpler SPFA model is preferred.

```{r, eval = TRUE, purl = FALSE}
# Directly compare delta_beta from the Relaxed model
# Non-zero delta_beta indicates effect modification
relaxed_summary <- fit_relaxed$summary
delta_rows <- grepl("^delta_beta", relaxed_summary$variable)
if (any(delta_rows)) {
  cat("Effect modification parameters (delta_beta):\n")
  print(relaxed_summary[delta_rows, c("variable", "mean", "2.5%", "97.5%")],
        row.names = FALSE)
}
```

```{r, eval = FALSE, purl = FALSE}
prior_sensitivity(fit_relaxed, prior_beta_scales = c(1, 2.5, 5, 10))
```

## Decision guide: which method to report?

The choice of primary analysis depends on the clinical and regulatory
context. This flowchart summarizes the main considerations:

1. **Are covariate distributions similar across trials?**
   - Yes: Naive estimate may suffice as primary, with STC as sensitivity.
   - No: Adjustment is needed. Proceed to step 2.

2. **Is the SPFA assumption plausible?**
   - Yes: ML-UMR SPFA is the recommended primary analysis. Report STC and
     Naive as sensitivity analyses.
   - Uncertain: Run both SPFA and Relaxed. If they agree, report SPFA.
     If they disagree, report Relaxed as primary and discuss the evidence
     for effect modification.
   - No (known effect modification): ML-UMR Relaxed as primary.

3. **Is Bayesian analysis acceptable to the audience?**
   - No: Report STC as primary with ML-UMR as sensitivity.
   - Yes: Report ML-UMR as primary with STC as sensitivity.

In all cases, report the naive estimate as a benchmark to quantify the
impact of covariate adjustment.

## Presenting results

For a complete ITC report, present:

1. **A summary table** (as above) with LOR, SE, and CI for each method
2. **Model diagnostics** for ML-UMR (divergences, Rhat, ESS)
3. **DIC comparison** between SPFA and Relaxed (if both were fit)
4. **A narrative** explaining which method is primary and why, with
   sensitivity analyses supporting the conclusions

```{r, eval = TRUE, purl = FALSE}
# Example narrative output
cat("Primary analysis: ML-UMR SPFA\n")
cat(sprintf("  LOR = %.3f (95%% CrI: %.3f to %.3f)\n",
            lor_spfa$mean, lor_spfa$q2.5, lor_spfa$q97.5))
cat(sprintf("  OR  = %.3f (95%% CrI: %.3f to %.3f)\n\n",
            exp(lor_spfa$mean), exp(lor_spfa$q2.5), exp(lor_spfa$q97.5)))

cat("Sensitivity analyses:\n")
cat(sprintf("  STC:    LOR = %.3f (95%% CI: %.3f to %.3f)\n",
            res_stc$link_effect, res_stc$ci_lower, res_stc$ci_upper))
cat(sprintf("  Naive:  LOR = %.3f (95%% CI: %.3f to %.3f)\n",
            res_naive$link_effect, res_naive$ci_lower, res_naive$ci_upper))
cat(sprintf("  Relaxed: LOR = %.3f (95%% CrI: %.3f to %.3f)\n",
            lor_relaxed$mean, lor_relaxed$q2.5, lor_relaxed$q97.5))
```

## Summary

Running all three methods and comparing their results strengthens any
unanchored ITC analysis. mlumr's unified data interface makes this
comparison straightforward -- the same `mlumr_data` object feeds all
methods, ensuring consistency in the inputs.

Key takeaways:

- **Always report the naive estimate** as a baseline to show the impact
  of adjustment.
- **STC is a fast, frequentist alternative** that adjusts for measured
  covariates via outcome regression.
- **ML-UMR SPFA** is the recommended primary analysis under the shared
  prognostic factor assumption, offering fully Bayesian uncertainty
  quantification.
- **ML-UMR Relaxed** is a useful sensitivity analysis when effect
  modification is plausible.
- **Compare SPFA and Relaxed via DIC** as a rough sensitivity check.
  DIC is a legacy metric with known limitations; treat large differences
  as suggestive rather than definitive evidence for effect modification.
