NICE DSU cross-reference
Reviewers navigate an appraisal by TSD number. This maps the three that govern survival extrapolation onto what the merlin family actually does, with the command for each in both languages.
Nothing here reproduces the guidance. Each entry is our own description of what the document is for, next to the command that answers it — the citation travels, the published text stays where it was published.
merlin 3.0.0’s HTA layer is a survival front end: it fits the candidate families, projects them past follow-up, anchors the tail to background mortality, and hands the parameter draws to pendragon for the value layer or morgana for Bayesian posteriors. One of us co-authored TSD 21.
Extrapolating survival from patient-level trial data
What it asks of an analysis
Fit the candidate parametric families to the same data, compare them on fit and on what each implies beyond the observed follow-up, and justify the one carried into the model rather than reporting a single curve.
What the merlin family does
In merlin 3.0.0 for Stata, merlin grid fits the whole candidate set in one call: exponential, Weibull, Gompertz, generalised gamma, log-normal and log-logistic, sweeping the degrees of freedom of Royston–Parmar and M-spline fits. merlin for R v2, in build, adds merlin_extrap_grid(), which returns one row per fit — log-likelihood, df, AIC, ΔAIC, BIC, landmark survival, RMST at the horizon, and whether it converged. The comparison becomes a table you can attach rather than a paragraph.
merlin_extrap_grid(
Surv(time, status) ~ trt, data = d,
families = c("exponential", "weibull", "gompertz",
"lognormal", "loglogistic", "ggamma", "rp"),
df = list(rp = c(3, 5, 7)),
landmarks = c(1, 5, 10), horizon = 50)
stset time, failure(status)
merlin grid trt, families(exponential weibull gompertz lognormal loglogistic ggamma rp) ///
df(3 5 7) landmarks(1 5 10) horizon(50)
* the grid refits the best fit and leaves it in memory; project it
range tgrid 0 50 101
merlin extrap, generate(x) timevar(tgrid)
Flexible methods, when the standard families will not fit
What it asks of an analysis
Where the standard set cannot follow the shape of the hazard — a turning point, a plateau, a cured fraction — use a model flexible enough that it can, and be explicit about what the flexibility does at the horizon.
What the merlin family does
Royston–Parmar splines are a family like any other here, so moving from Weibull to a spline is one argument rather than a different package. M-splines are the safer choice when the extrapolation is what matters: the constant-hazard tail gives a flat hazard past the last knot, where Weibull and Gompertz can explode or vanish. Mixture and non-mixture cure forms use the same syntax.
merlin(Surv(time, status) ~ trt,
family = "rp", df = 3, data = d)
# flat-hazard tail, for a long horizon
merlin(Surv(time, status) ~ trt,
family = "mspline", df = 4, data = d)
stset time, failure(status) merlin (_t trt, family(rp, df(3) failure(_d))) * flat-hazard tail, for a long horizon merlin (_t trt, family(mspline, df(4) failure(_d)))
Partitioned survival as a decision structure
What it asks of an analysis
The dominant oncology structure: progression-free and overall survival are modelled separately and the health states are read off as areas between the curves — which means the curves can cross and produce a negative state occupancy unless something stops them.
What the merlin family does
The explorer shows the structure and the curve-crossing failure directly, which is the quickest way to see why the assumption matters. For the analysis, fit the two curves in merlin and take occupancy, costs and the ICER through pendragon. A state-transition model fitted as a multi-state model avoids the crossing problem rather than checking for it.
# the two curves, then out to the value layer merlin(Surv(pfs, prog) ~ trt, family = "rp", df = 3, data = d) merlin(Surv(os, died) ~ trt, family = "rp", df = 3, data = d)
stset pfs, failure(prog) stmerlin trt, distribution(rp) df(3) // progression-free estimates store pfs stset os, failure(died) stmerlin trt, distribution(rp) df(3) // overall survival estimates store os
What a reviewer asks for next
Background mortality. An extrapolated hazard that falls below the general population’s is a curve to reject. In merlin 3.0.0 for Stata, merlin extrap anchors the tail to a lifetable — across the whole time axis, or only past an attained age — and re-derives survival and RMST from the anchored hazard. merlin for R v2, in build, adds merlin_extrap() for the same.
Parameter uncertainty. merlin psa (Stata, from 3.0.0) and merlin_extrap_psa() (R v2, in build) draw from the fitted parameter vector and replay each draw through the prediction, giving bands on survival, hazard and RMST. That same draw matrix is the hand-off to pendragon, so uncertainty in the survival model becomes uncertainty in the ICER rather than a separate assumption.
Reproducibility. What the checks cover, and what they do not, is set out on the test suite page; qualified builds for regulated use are on Validated.