RDA gawain
Does a survival prediction model rank the people who fail sooner? Are the risks it predicts the risks that occur? And does acting on it beat treating everyone, or no one? gawain answers all three — for single-event, competing-risks and multi-state outcomes, from any model that can produce a predicted risk.
Coming
December 2026
Not yet released gawain is in build for R and Stata.
What gawain does
gawain measures the three things a prediction model is for. Discrimination — Harrell’s C, Uno’s censoring-adjusted C, the time-dependent AUC, Gönen–Heller K, Somers’ D, and the Royston–Sauerbrei D with R²D. Calibration — the inverse-probability-of-censoring-weighted Brier score and its integrated form, the calibration slope, observed against expected events, and the integrated calibration index with E50 and E90. Clinical utility — decision-curve net benefit, against treat-all and treat-none. Twelve statistics in all, with bootstrap intervals, k-fold cross-validation, and Harrell’s optimism correction.
It takes predictions as data, not as a model object: an observed time, a status indicator, and a predicted risk or linear predictor. So anything that can produce a predicted risk can be evaluated — a merlin fit, stcox, stpm2, coxph, flexsurv, a model scored in another language, or a published risk score applied to your cohort. That independence is enforced rather than intended: nothing in the package loads merlin, and each implementation carries a test that fails if it ever starts to.
Under competing risks every measure switches to its competing-risks form — Wolbers’ concordance, the Aalen–Johansen cumulative incidence, and cause-specific calibration and net benefit. These are different estimators, not the same ones with a filter applied, and gawain treats a status carrying cause numbers without a stated cause as an error rather than a filter: collapsing the competing events to censoring estimates the wrong quantity and overstates the risk. For a multi-state model it evaluates any (from, to) transition at a landmark, absorbing or transient — and at landmark zero on an absorbing destination it reproduces the plain time-to-event analysis exactly, which is what certifies it.
All three questions, with the censoring handled
One command composes the measures and returns them together; each is also available on its own. Everything below is implemented in both R and Stata.
Six rank measures
Harrell’s C, Uno’s censoring-adjusted C, the cumulative/dynamic time-dependent AUC, Gönen–Heller K, Somers’ D, and the Royston–Sauerbrei D with R²D.
Slope, O:E and the ICI
The IPCW Brier score and its integrated form, the calibration slope, observed against expected events, and the integrated calibration index with E50 and E90.
Decision curves
Net benefit across the threshold range, against treat-all and treat-none — the question a clinician actually asks of a risk score, and the one most often skipped because nothing packages it.
Different estimators, not a filter
Wolbers’ concordance, the Aalen–Johansen cumulative incidence, and cause-specific calibration and net benefit. Collapsing competing events to censoring is refused, not silently allowed.
Any (from, to), at a landmark
Occupancy of any destination from any origin, absorbing or transient, with landmarking — and a matrix sweep over every transition. No summary across cells is offered: a scalar over transitions with different at-risk populations would report a model that does neither thing.
Bootstrap, cross-validation, optimism
Percentile intervals, out-of-fold evaluation and Harrell’s optimism correction — plus a temporal-holdout screen that refits on the data as it stood at each cutoff and asks whether the model extrapolates.
Every number it reports has been checked against something
A package that tells you whether to trust a model has to answer the same question about itself. gawain answers it twice, and both layers live in the test suites rather than in prose: agreement with the reference implementation of each measure, and truth recovery on data whose answer is known exactly, because the process that generated it determines the answer.
| Measure | Checked against | Value | Tolerance |
|---|---|---|---|
| Harrell’s C | survival::concordance(reverse = TRUE) | 0.6730769231 | 1e−8 |
| Uno’s C | Uno et al. (2011) eq. 7, implemented directly | 0.6774039882 | 1e−8 |
| Time-dependent AUC | riskRegression::Score(metrics = "auc", cens.model = "km") | 0.7296310898 | 1e−8 |
| Brier score | pec::pec | 0.2071678541 | 1e−8 |
| Royston–Sauerbrei D | survival::royston | 1.1022568052 | 1e−8 |
| Net benefit, threshold 0.30 | dcurves::dca | 0.235800639 | 1e−8 |
| Aalen–Johansen CIF, t = 5 | survival::survfit(Surv(time, factor(cause)) ~ 1) | 0.5250278717 | 1e−8 |
| Brier score, cause 1 | riskRegression::Score(cause = 1, cens.model = "km") | 0.1654486760 | 1e−9 |
| Wolbers’ concordance, IPCW | pec::cindex(cause = 1, eval.times = 2) | 0.7192009433 | 1e−8 |
| Censored | Uno’s C | AUC(t) | Brier(t) | O:E | Harrell drift |
|---|---|---|---|---|---|
| 65.6% | −1.58e−03 | −1.66e−03 | −7.18e−05 | −2.79e−03 | 1.29e−02 |
| 78.1% | 7.47e−04 | −4.71e−04 | 9.13e−04 | 3.44e−03 | 1.75e−02 |
| 86.1% | 3.67e−03 | 1.84e−03 | 2.10e−04 | 3.50e−03 | 2.13e−02 |
The first four columns are the corrections working. The last is Harrell’s C, the uncorrected estimator, drifting upward as theory says it must — at 86% censoring by 2.1e−02, while the corrected measures stay within 3.7e−03 of the value they were asked to recover. That is the correction shown to be doing work rather than asserted to be, and it is only possible because the family owns its own generator: the data come from avalon, so the true value is known and no target in the table was supplied to the estimator.
Two places where gawain does not match a published implementation are recorded with their reasons rather than tuned away. A conformance report that lists only agreements is marketing. Calibration is absent from the table above for a different reason: there is no external implementation of the slope, O:E or the ICI to pin a value against, so those are certified by behaviour instead — they have to move when the model is wrong, and the suite checks that they do.
Get started
gawain is in active development in R and Stata, and is not yet on CRAN or SSC.
Not yet released. Unlike the other packages still in build, the syntax below is not a plan: both implementations run today, the Stata certification suite passes across nineteen scripts, and the R port reproduces its pinned values on the same predictions. What is pending is distribution. Get in touch if you would like early access.
A first model
Unlike the other in-development family pages, nothing below is planned syntax: both implementations run today, and what is pending is distribution rather than the interface. The R block was executed to produce the figures it describes; the Stata block is the package’s own documented example.
library(gawain)
library(survival)
# a risk score from a model gawain knows nothing about
lung <- na.omit(lung[, c("time", "status", "age", "sex", "ph.ecog")])
fit <- coxph(Surv(time, status) ~ age + sex + ph.ecog, data = lung)
lung$eta <- predict(fit, type = "lp")
lung$p <- 1 - summary(survfit(fit, newdata = lung), times = 365)$surv[1, ]
# discrimination, calibration and the decision curve, at one year
gawain(time, status - 1, predict = p, eta = eta, data = lung,
statistic = "all", at = 365)* a risk score from a model gawain knows nothing about
webuse brcancer, clear
stset rectime, failure(censrec)
stcox hormon x1
predict double xb, xb
gawain, time(rectime) status(censrec) risk(xb) statistic(harrell)
* or run it after a fitted merlin model, and let it build the predictions
merlin (rectime hormon x1, family(weibull, failure(censrec)))
gawain, statistic(all)The fourth question the family asks
Worked examples and tutorials for the family are in our Resources.
Try it in your browser: the model chooser — work out which model your question needs, before you validate one.
Citing gawain
gawain does not have a methods paper yet — cite the software itself. The measures it computes are other people’s; each is attributed to its source in the documentation, and the conformance report names the implementation it was checked against.
@misc{gawain2026,
author = {Crowther, Michael J.},
title = {{gawain: validation of survival prediction models}},
year = {2026},
url = {https://reddooranalytics.se/software/gawain/},
note = {Red Door Analytics}
}