bio-clinical-biostatistics-trial-reporting
SkillAI & modelsPrepares statistical reports for clinical trials following CONSORT 2025, SPIRIT 2025, ICH E9(R1) estimands, and FDA 2023 covariate adjustment guidance. Covers Table 1 generation, analysis populations (ITT/FAS/PP/Safety), the 5 ICH E9(R1) intercurrent-event strategies, MMRM under MAR (mmrm), reference-based MI (rbmi J2R/CR/CIR), Permutt tipping-point sensitivity, and Rubin's-rules vs frequentist variance debate. Use when preparing regulatory submissions, defining estimands, or implementing missing-data sensitivity analyses.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the bio-clinical-biostatistics-trial-reporting skill
What this skill tells your AI
The instructions your AI receives, as published by pku-yuangroup/openai4s in skills/bioskills/bio-clinical-biostatistics-trial-reporting/SKILL.md and read by ahel’s review.
Version Compatibility
Reference examples tested with: tableone 0.9+, statsmodels 0.14+, scikit-learn 1.4+, pandas 2.1+, numpy 1.26+. R packages cited (essential for current regulatory work): mmrm 0.3+ (Roche/openpharma), rbmi 1.5+ (Roche/Bayer via insightsengineering), gMCP, RBesT.
Before using code patterns, verify installed versions match. If versions differ:
- Python:
pip show <package>thenhelp(module.function)to check signatures - R:
packageVersion('<pkg>')then?function_name
If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.
Trial Reporting Under CONSORT 2025 + ICH E9(R1)
"Prepare a clinical trial statistical report" -> Define the estimand explicitly per ICH E9(R1); execute a covariate-adjusted primary analysis targeting the right summary measure; pre-specify the missing-data strategy and run regulatory-grade sensitivity analyses; structure the output per CONSORT 2025 and the new SPIRIT 2025 alignment.
The Single Most Important Methodological Shift -- The Estimand Comes First
Kahan, Cro, Li, Harhay 2023 Am J Epidemiol 192:987 ("Eliminating Ambiguous Treatment Effects Using Estimands"): 98% of published trial reports do not describe what the reported treatment effect represents. 54% of trials: impossible to deduce the estimand from reported methods. In 74% of trials submitted for regulatory approval 1996-2017, "what-if" hypothetical effects were used but only 2 trials explained this.
The framework: ICH E9(R1) Addendum (November 2019, EMA effective 30 July 2020, FDA May 2021) defines an estimand as the precise specification of what is being estimated, via five attributes:
- Treatment condition -- what is being compared
- Population -- which patients
- Endpoint -- which variable
- Population-level summary measure -- mean diff, OR, HR, RD
- Intercurrent-event (ICE) handling strategy -- one of five
The order is non-negotiable: specify the estimand BEFORE choosing the statistical method. Choosing MMRM and retrofitting the estimand to match is the canonical error.
The Five Intercurrent-Event Strategies
| Strategy | What it does | Typical implementation | Identification cost | Regulatory pattern |
|---|---|---|---|---|
| Treatment policy | Include all data regardless of ICE | ANCOVA on observed value (retrieved-dropout data); ITT-like | Trivially identified; needs full follow-up regardless of ICE | FDA-preferred default for cardio/HF/CV-safety; Fleming 2025 endorsement |
| Hypothetical | What would have been observed had ICE not occurred | MMRM under MAR; g-computation; IPCW; reference-based MI under MAR | Sequential ignorability (causal); MAR (missing-data shorthand) | Heavy use in CNS, diabetes, respiratory; EMA more accepting than FDA |
| Composite | Incorporate ICE into endpoint | Death = non-responder; PFS = composite of progression OR death; MACE | Identified from observed data; embeds a ranking choice | Standard in oncology PFS; acceptable when ICE has clinical signal |
| While-on-treatment | Use only pre-ICE values | Censor at discontinuation (for TTE); analyse last pre-ICE value (for repeated measures) | Estimates conditional quantity | Safety endpoints (AE rate per time on drug); FDA cautious for efficacy |
| Principal stratum | Confine to latent stratum (e.g. tolerators) | Bayesian estimation under monotonicity/principal ignorability | Latent membership; unverifiable assumptions | Rare as primary; some oncology/vaccine acceptance |
Postdoc reading list:
- Bornkamp, Rufibach, Lin, Liu, Mehrotra, Roychoudhury, Schmidli, Shentu, Wolbers 2021 Pharm Stat 20:737 — principal stratum critique
- Olarte Parra, Daniel, Bartlett 2022 Stat Biopharm Res — proves MMRM-MAR IS a hypothetical estimator under specific causal assumptions
- Permutt 2016 Stat Med 35:2876; 2020 Stat Biopharm Res 12:45 — FDA Missing Data Working Group taxonomy; "do covariates change the estimand?"
- Fleming, Carroll, Wittes et al 2025 Stat Med — argue treatment policy is the only strategy preserving randomisation; critique hypothetical
- Morris 2026 Stat Med — causal-perspective comment on Fleming
- Lipkovich, Ratitch, Mallinckrodt 2020 Stat Biopharm Res — Rubin causal model connection
Decision Tree for Estimand Selection
| Trial scenario | Recommended estimand strategy | Why |
|---|---|---|
| Continuous endpoint, monotone missingness, MAR plausible | Hypothetical via MMRM (mmrm + KR) | Standard FDA-favoured MAR analysis; cite Mallinckrodt 2008/2014 |
| Continuous endpoint, ICE = treatment discontinuation, sponsor wants effectiveness | Treatment policy via retrieved-dropout MI | If post-ICE data available; ITT-respecting |
| Continuous endpoint, treatment-policy primary with ICE-related missingness | Hybrid: J2R for discontinuation ICEs, MMRM-MAR for other missingness | Aprocitentan precedent; de facto FDA standard 2024-2025 |
| Binary endpoint, RCT, FDA 2023-compliant | Marginal RD via g-computation; conditional OR supportive | See clinical-biostatistics/logistic-regression for g-computation |
| Oncology OS with crossover | Treatment policy as primary; hypothetical (RPSFT/IPCW) as sensitivity | Sotorasib CodeBreaK 200 precedent |
| Oncology PFS | Treatment policy for subsequent-therapy ICE (composite may incorporate death) | Sun 2021 framework; Fleming 2025 |
| Weight management / chronic disease | Retrieved-dropout MI (Wegovy STEP precedent); J2R supportive | FDA 2025 obesity draft guidance explicitly endorses |
| Long-term safety endpoint | While-on-treatment for rate; treatment policy for cumulative incidence | Standard ICH E2A practice |
| AlloSCT in hematologic oncology | Composite "event-free survival" treating alloSCT as event | Sun 2021 (alloSCT as intercurrent event); "no alloSCT" hypothetical is clinically meaningless |
| Symptomatic palliative endpoint with high dropout | Composite with worst-rank for dropouts (Permutt trimmed means) | Permutt 2017 Pharm Stat 16:20 |
MMRM -- The FDA-Favoured MAR Analysis
Mallinckrodt 2008/2014, codified in DIA Scientific Working Group "three pillars" doctrine: for continuous longitudinal endpoints under monotone (or near-monotone) MAR, an MMRM with treatment + visit + treatment-by-visit + baseline + baseline-by-visit, unstructured (UN) within-subject covariance, REML, contrast at the primary timepoint -- is the consistent and FDA-preferred analysis. LOCF is biased even under MCAR because it discards imputation uncertainty and assumes a flat post-withdrawal trajectory.
The mmrm R package (Roche / openpharma)
library(mmrm)
fit <- mmrm(
formula = change_from_baseline ~ baseline + arm * visit + us(visit | subject),
data = trial_data,
method = "Kenward-Roger", # or "Satterthwaite", "Kenward-Roger-Linear"
reml = TRUE
)
summary(fit) # treatment-by-visit contrast at primary timepoint
The Kenward-Roger flavour question: method = "Kenward-Roger" uses full second-order Kenward-Roger (Kenward-Roger 1997 Biometrics 53:983), which inflates SE for fixed-effect contrasts using an adjusted covariance estimator with second-order Taylor terms. method = "Kenward-Roger-Linear" drops the second-order Cholesky-derivative term to match SAS PROC MIXED bit-for-bit. Most submissions use Kenward-Roger-Linear to maintain SAS-R reproducibility.
Convergence-vs-correctness trade-off
Unstructured (UN) covariance has p(p+1)/2 parameters for p visits. With ~30-50 patients per arm by week 12 and 6+ visits, UN can fail to converge. The industry-standard fallback hierarchy per pre-specified SAP:
- UN with KR (preferred)
- UN with Satterthwaite (if KR fails)
- Heterogeneous Toeplitz (k+1 parameters)
- AR(1) with heterogeneous variances
- CS with heterogeneous variances (last resort)
Each step down imposes more structure and the structure can be wrong — biasing both SEs and point estimates. CS imposes equal correlation across time which is rarely true for treatment-ramp-up endpoints (HbA1c, BP). Pre-specify the fallback in the SAP, not at analysis time.
MMRM = hypothetical estimator (Olarte Parra unification)
Olarte Parra, Daniel, Bartlett 2022 Stat Biopharm Res: under specific identifying assumptions, MMRM under MAR IS a causal hypothetical estimand via g-formula equivalence. The "issue" is articulation, not statistical machinery — MMRM-MAR implicitly answers a hypothetical estimand whose hypothetical scenario must be made explicit in the SAP (e.g., "what would the mean response at week 24 be had all patients continued randomised treatment and remained observable?").
Reference-Based Multiple Imputation -- The rbmi Framework
Carpenter, Roger, Kenward 2013 J Biopharm Stat 23:1352 — the canonical paper. Reference-based MI operationalises MNAR sensitivity not as a numeric delta but as a clinical narrative:
- Jump-to-reference (J2R): "after withdrawal the patient instantly resembles the placebo arm"
- Copy-reference (CR): "the entire post-baseline trajectory copied from placebo, with subject's baseline deviation preserved"
- Copy-increments-in-reference (CIR): "the patient retains the on-treatment increment but trends with the placebo arm thereafter, anchored at last observed value"
- Last-mean-carried-forward (LMCF): "patient stays at last on-treatment mean"
rbmi R package (Wolbers et al 2022 Pharm Stat 21(6):1246-1257; CRAN; insightsengineering):
library(rbmi)
# Draws -> Impute -> Analyse -> Pool pipeline
draws <- draws(data = trial_data, vars = vars,
method = method_bayes(n_samples = 100))
imputed <- impute(draws, references = c('Active' = 'Placebo', 'Placebo' = 'Placebo'))
analyses <- analyse(imputed, fun = ancova,
vars = list(outcome = 'change', visit = 'avisit',
group = 'arm', covariates = c('baseline')))
result <- pool(analyses) # Rubin's rules pooling
Four inference engines:
- Bayesian MI + Rubin's rules (historical default) — information-anchored variance
- Approximate Bayesian via REML + bootstrap — frequentist variance from bootstrap
- Conditional mean imputation + jackknife (Wolbers 2022 contribution) — single deterministic imputation per ANCOVA-linearity theorem, jackknife for SE; FDA-friendly because deterministic + frequentist
- BMLMI (bootstrapped MI of Lipkovich/Ratitch) — within/between variance decomposition
The Variance Debate -- Cro/Carpenter vs Bartlett/Wolbers
The single most active methodological argument in current biostatistics.
Cro/Carpenter/Kenward 2019 JRSS-A 182:623 ("Information-Anchored Sensitivity Analysis"): proved that Rubin's-rules variance applied to J2R/CR/CIR is approximately information-anchored — the relative loss of information from missingness in the sensitivity analysis matches the relative loss in the MAR primary analysis. True repeated-sampling variance is "information positive" because reference-based imputation borrows from the reference arm and reduces the marginal variance of the active arm BELOW what an MAR analysis with the same missingness would give.
Philosophical position: a sensitivity analysis should not import information the primary analysis did not have; if borrowing from placebo makes the active-arm CI narrower, the analysis is no longer "anchored" to the same information state.
Bartlett 2021 Stat Biopharm Res 15(1):178 + Wolbers 2022 Pharm Stat counter: if J2R is the actual sampling model under which inference is made, then the correct frequentist variance is the one that delivers nominal Type-I error and CI coverage under that model -- the jackknife/bootstrap variance, NOT Rubin's. Simulations in rbmi vignettes: Bayesian MI with Rubin's gives Type-I error 0.9-2.5% (over-conservative); CMI+jackknife gives 4.84-4.96% (nominal) under J2R; Bayesian MI loses real power.
Regulatory practice 2024-2025 is bifurcating: EMA tolerates either; FDA reviewers increasingly flag Rubin's-rules variance under reference-based MI as needing a frequentist sensitivity analysis in addition. What postdocs argue about: whether Type-I inflation under bootstrap is the price of correct inference, or evidence J2R was never coherent as a true sampling model.
Permutt Tipping-Point Analysis -- The Analyst as Adversary
Permutt 2016 Stat Med 35:2876 (Permutt was head of FDA Division of Biometrics IV): the regulator's question is not "what is a reasonable MNAR adjustment?" but "how bad would the missing data have to be in the active arm to overturn the significant primary result?"
Delta-adjustment patterns:
- One-arm shift (FDA preferred): add delta to imputed values in active arm only; vary delta from 0 to the value that nullifies the effect
- Symmetric shift: both arms worsened by delta (probes systematic optimism)
- Reverse shift: placebo improved by delta (more aggressive, rarely needed)
# rbmi with delta adjustment
delta <- delta_template(imputed, delta = c(0, 5, 10, 15, 20), dlag = c(1, 1, 1, 1))
adjusted <- analyse(imputed, delta = delta, ...)
# Report: minimum delta that flips p-value below 0.05
The regulator then judges whether the tipping delta is clinically plausible — larger than the active-arm treatment effect itself? Larger than the MCID? FDA-preferred report: tipping delta in units of residual SD (for cross-trial comparison), not raw outcome units.
Decisive Regulatory Cases -- The 2020-2025 Casebook
Aducanumab (Biogen BLA 761178, 2021): EMERGE and ENGAGE studies both stopped early for futility; EMERGE high-dose positive, ENGAGE negative. MMRM-MAR primary. FDA Office of Biostatistics (Tristan Massie review) argued futility-stop-induced missingness was not MAR (differential ARIA-driven unblinding); the Nov 2020 AdCom voted overwhelmingly against approval. Textbook case showing MAR-based primary in trial with high differential missingness is regulator-divisive.
Aprocitentan (Idorsia PRECISION trial, FDA approval 2024): documented in Sassi-Sayadi et al 2025 Ther Innov Regul Sci (PMC12753554). FDA pushed back on sponsor's MMRM-MAR primary; MAR was not credible for treatment-discontinuers. Accepted compromise: stratified imputation — J2R for treatment-discontinuation ICEs, MAR-MMRM for other missingness. This hybrid is now de facto FDA standard for treatment-policy estimand.
Wegovy/Ozempic STEP trials (Wilding 2021 NEJM; NDA 215256): retrieved-dropout MI as primary for treatment-policy. Missing body weight at week 68 imputed by sampling from observed week-68 measurements among "retrieved dropouts" (patients who discontinued semaglutide but remained in follow-up). J2R-MI as supportive. RD-MI now standard for chronic weight management. FDA 2025 obesity guidance explicitly endorses MI as primary.
Table 1 -- Baseline Characteristics
CONSORT 2010 discouraged baseline significance tests because randomisation is a known mechanism, not a hypothesis. Many journals still require them.
from tableone import TableOne
columns = ['age', 'sex', 'race', 'bmi', 'baseline_score', 'disease_stage']
categorical = ['sex', 'race', 'disease_stage']
table1 = TableOne(df, columns=columns, categorical=categorical,
groupby='ARM', pval=True, smd=True,
missing=True, overall=True)
print(table1.tabulate(tablefmt='github'))
table1.to_excel('table1.xlsx')
Use standardised mean differences (SMD) rather than p-values: SMD > 0.1 suggests meaningful imbalance regardless of statistical significance.
Senn's "balance testing is incoherent" (1994 Stat Med 13:1715; Altman 1985): balancing via randomisation, testing balance, then adjusting only when the test fails is a selection rule that destroys nominal Type-I error. Pre-specify covariates in the SAP; do not condition adjustment on observed imbalance.
Analysis Populations -- ITT vs FAS vs PP vs Safety
| Population | Definition | Bias direction | Primary use |
|---|---|---|---|
| ITT | All randomised, as randomised | Conservative (toward null) | Primary efficacy per ICH E9 |
| FAS (Full Analysis Set) | ITT excluding eligibility failures + subjects with no post-baseline data | Middle ground; close to ITT | Common practical primary; ICH E9 "as complete as possible while remaining unbiased" |
| Per-Protocol | Completed treatment per protocol without major violations | Anti-conservative (inflates effect) | Sensitivity analysis only |
| Safety | All received at least one dose | n/a | AE analysis |
| mITT | Sponsor-defined modified ITT | Variable | Pre-specify and justify |
FAS vs ITT distinction is critical for regulatory submissions — FAS may exclude post-randomisation subjects (ineligibility, no post-baseline efficacy); ITT cannot. Sponsors often equate them on the SAP only to discover at submission that FDA expected stricter ITT. Pre-specification in protocol is essential.
itt = dm.copy()
pp = dm[dm['USUBJID'].isin(completers) & ~dm['USUBJID'].isin(protocol_violators)]
dosed = ex[ex['EXDOSE'] > 0]['USUBJID'].unique()
safety = dm[dm['USUBJID'].isin(dosed)]
Missing Data Mechanisms -- The Practical Framework
| Mechanism | Definition | Testable? | Valid method |
|---|---|---|---|
| MCAR | Independent of all data | Partially (Little's test) | Complete-case unbiased but loses power |
| MAR | Depends on observed data only | NO (assumption) | MMRM under MAR; MI under MAR |
| MNAR | Depends on unobserved values | NO | Requires sensitivity analysis (J2R, CR, CIR, tipping point) |
MAR vs MNAR cannot be distinguished from observed data alone — this is a fundamental limitation. Pre-specify the assumed mechanism in the SAP; pre-specify the sensitivity analysis under MNAR (NRC 2010 Recommendation 15: "examining sensitivity to assumptions about the missing-data mechanism should be a mandatory component of reporting").
Clinical reasoning beyond the abstraction: examine the DS (Disposition) domain to tabulate reasons for discontinuation by treatment arm. If discontinuation rates or reasons differ between arms, missing data is likely informative and MNAR sensitivity analyses are mandatory.
Standard MMRM-MAR Primary Analysis Code
Goal: Execute the FDA-preferred primary analysis for a continuous longitudinal endpoint under MAR with valid Type-I in small/moderate trials.
Approach: Fit MMRM with unstructured covariance + Kenward-Roger via the Roche/openpharma mmrm R package; in Python, use statsmodels.mixedlm as exploratory-only (lacks KR).
# Python is weak for MMRM — current state of the art is R `mmrm`
# For Python users, statsmodels.mixedlm is the closest alternative but lacks
# Kenward-Roger; consider rpy2 to call R from Python for confirmatory work.
import statsmodels.formula.api as smf
import pandas as pd
# Random intercept LMM (suboptimal vs MMRM but Python-native)
model = smf.mixedlm(
'change ~ baseline + C(ARM) * C(VISIT)',
data=df_long,
groups=df_long['USUBJID']
).fit(reml=True)
# WARNING: this is NOT FDA-equivalent to MMRM with UN+KR
# For confirmatory work, use R `mmrm` package via rpy2 or fit in R directly
Multiple Imputation in Python (sklearn)
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
import statsmodels.formula.api as smf
import numpy as np
n_imputations = 20 # rule: m >= 100 * FMI (fraction of missing info)
imputer = IterativeImputer(max_iter=10, random_state=0, sample_posterior=True)
results = []
for i in range(n_imputations):
imputer.set_params(random_state=i)
imputed = pd.DataFrame(imputer.fit_transform(df[numeric_cols]), columns=numeric_cols)
for col in ['ARM', 'sex']:
imputed[col] = df[col].values
model = smf.logit(
'outcome ~ C(ARM, Treatment(reference="Placebo")) + age', data=imputed
).fit(disp=0)
results.append({'coef': model.params.iloc[1], 'se': model.bse.iloc[1]})
# Rubin's rules
pooled_coef = np.mean([r['coef'] for r in results])
within_var = np.mean([r['se']**2 for r in results])
between_var = np.var([r['coef'] for r in results], ddof=1)
total_var = within_var + (1 + 1/n_imputations) * between_var
pooled_se = np.sqrt(total_var)
pooled_or = np.exp(pooled_coef)
Critical sklearn caveats:
sample_posterior=Trueis essential — without it all m imputations are nearly identicalsample_posterior=Trueonly works withBayesianRidge(the default estimator). If estimator is changed (e.g.,RandomForestRegressor), parameter is silently ignored and MI degenerates to single imputation- IterativeImputer treats binary covariates as continuous; consider
miceforestfor mixed types or move to Rmice/rbmi - Only impute covariates and post-baseline outcomes, NOT treatment assignment (fully determined by randomisation)
- Include outcome in imputation model as predictor but exclude from imputed variables to avoid circular dependency
- IterativeImputer is experimental in sklearn — API may change without standard deprecation
Congeniality (Meng 1994): imputation model must be at least as flexible as analysis model. If analysis includes treatment-by-covariate interactions, imputation model should include them. Uncongenial imputation biases estimates and invalidates variance pooling.
Co-Primary Endpoints and Multiplicity
| Method | Approach | Conservatism |
|---|---|---|
| Bonferroni | alpha / m | Most conservative |
| Hierarchical (gatekeeping) | Pre-specified order; proceed only if previous rejects | Moderate; full alpha for first |
| Graphical procedure (Bretz-Maurer) | Directed graph; alpha propagates on rejection | Flexible; standard in modern SAPs |
| Hochberg / Hommel step-up | Ordered p-values vs alpha/(m-k+1) | Less conservative than Bonferroni; requires PRDS |
See clinical-biostatistics/multiplicity-graphical for the full Bretz-Maurer-Hommel treatment with gMCP.
Reconciliation: When Methods Disagree
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 404
- Forks
- 48
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
bio-clinical-biostatistics-trial-reporting- Source
- github.com/pku-yuangroup/openai4s