Restricted mean survival time (RMST)
RMST is the area under the Kaplan-Meier curve between 0 and τ — on average, how long people lived during the first τ of follow-up. This page covers how to read that area, why τ must be fixed in advance, how far the conclusion moves when τ changes, why the difference and the ratio both have to be reported, and how to turn it into one sentence you can say to a patient.
Why this method gets its own page
The main line this site teaches for survival data is the Kaplan-Meier curve plus the Cox proportional hazards model, and the effect measure that comes out is a hazard ratio. A hazard ratio charges two things, and clinical readers pay them every day:
- It requires proportional hazards. The ratio between the two groups has to hold constant across the whole of follow-up. When it does not, that single number is a weighted average of two different effects and matches the true hazard ratio at no time point at all. How to check it, and what each of the four repairs costs, is on the proportional hazards assumption and Schoenfeld residuals.
- Its unit does not translate. HR 0.78 does not answer so what? To tell a patient how much longer this treatment lets people live on average, a hazard ratio cannot be converted directly — it is a ratio of instantaneous risks, not a length of time.
Restricted mean survival time (RMST) owes neither. It is an area under a curve, so it needs no proportionality of any kind, and its unit is time — days or months — which the reader does not have to translate.
That is why it is no longer only repair number four for a failed assumption. Recent oncology and heart-failure trials routinely put an RMST difference in the secondary analyses or the appendix, for exactly the two reasons above: when curves cross or an effect arrives late, the hazard ratio is hard to interpret, and RMST still computes and still says something out loud. This page is the site’s only full account of it — the PH page now carries a short pointer here instead of publishing a second set of RMST numbers of its own.
The definition: the area under the Kaplan-Meier curve
is the survival curve estimated by Kaplan-Meier. Integrate it from 0 to and the dimension of the answer is time: during the first of follow-up, how long the average person lived.
A KM curve is a step function, so the integral needs no numerical method at all — it is a sum of rectangles, each step’s height times the number of days it lasts. That is also why RMST assumes no distributional shape and no proportionality: it uses nothing except the KM curve itself.
The example here is survival::lung, the NCCTG advanced lung cancer cohort, 228
patients in all. After a complete-case filter on the six columns
time, status, age, sex_f, ph.karno, wt.loss, 214 patients enter the
analysis with 152 deaths and 62 censored observations. The grouping
variable is ph.karno, the Karnofsky performance score: Karnofsky >= 80
(n = 160, events = 105) against Karnofsky <= 70 (n = 54, events = 47).
is set to 365 days, one year.
figures/scripts/B3-07-rmst.RHow to compute it
The survival package does it unaided, with nothing to install: summary(fit, rmean = tau) reports
the area under the curve on [0, τ] for every stratum, together with its standard error.
library(survival)
data(cancer, package = "survival")
lung$sex_f <- factor(lung$sex, levels = c(1, 2), labels = c("Male", "Female"))
# The complete-case filter keeps exactly the six columns this analysis uses
ld <- lung[complete.cases(lung[, c("time", "status", "age", "sex_f",
"ph.karno", "wt.loss")]), ]
# State the levels. Left to itself R sorts them alphabetically, "Karnofsky <= 70"
# lands in row one, and every m[1] below is silently the other group.
ld$karno_grp <- factor(
ifelse(ld$ph.karno >= 80, "Karnofsky >= 80", "Karnofsky <= 70"),
levels = c("Karnofsky >= 80", "Karnofsky <= 70")
)
fit <- survfit(Surv(time, status) ~ karno_grp, data = ld)
# That is the whole thing: rmean = tau makes summary() report the area under
# the curve on [0, tau]. The column names changed between survival versions:
# older ones lead with a star (*rmean), 3.8 onwards does not. Accept both --
# hard-coding one of them breaks silently on the next upgrade.
tb <- summary(fit, rmean = 365)$table
mcol <- intersect(c("rmean", "*rmean"), colnames(tb))
scol <- intersect(c("se(rmean)", "*se(rmean)"), colnames(tb))
m <- tb[, mcol]
se <- tb[, scol]
# Difference: two independent means subtract, their variances add
d <- m[1] - m[2]
se_d <- sqrt(se[1]^2 + se[2]^2)
c(diff = d, lcl = d - 1.96 * se_d, ucl = d + 1.96 * se_d,
p = 2 * (1 - pnorm(abs(d / se_d))))
# Ratio: built on the log scale and transformed back (why: the section below)
r <- m[1] / m[2]
se_lr <- sqrt((se[1] / m[1])^2 + (se[2] / m[2])^2)
c(ratio = r, lcl = exp(log(r) - 1.96 * se_lr), ucl = exp(log(r) + 1.96 * se_lr))
# Sensitivity to tau: the same code over a series of taus is figure 2
sapply(c(180, 270, 365, 450, 550, 650), function(tau) {
x <- summary(fit, rmean = tau)$table
xc <- intersect(c("rmean", "*rmean"), colnames(x))
x[1, xc] - x[2, xc]
})Verified with R 4.6.0 and survival 3.8.6. summary(fit, rmean = tau) ships with survival itself; nothing extra to install.
import numpy as np
import statsmodels.api as sm
from lifelines import KaplanMeierFitter
from lifelines.utils import restricted_mean_survival_time
lung = sm.datasets.get_rdataset("cancer", "survival").data
d = lung[["time", "status", "age", "sex", "ph.karno", "wt.loss"]].dropna().copy()
d["event"] = (d["status"] == 2).astype(int)
d["grp"] = np.where(d["ph.karno"] >= 80, "high", "low")
def rmst_and_se(T, E, tau):
kmf = KaplanMeierFitter().fit(T, E)
# Pass kmf (the model), not kmf.survival_function_ (a DataFrame): the
# latter integrates by the trapezoid rule and lands below R's step sum.
point = restricted_mean_survival_time(kmf, t=tau)
# The standard error has to be built by hand. Each event time contributes
# (area remaining from that time to tau)^2 times d / (n * (n - d)). This
# reproduces R's se(rmean) to every digit R prints.
tb = kmf.event_table
tb = tb[tb.index <= tau]
S = kmf.survival_function_.loc[tb.index].values.ravel()
times = np.append(tb.index.values, tau)
rest = np.array([np.sum(np.diff(times[i:]) * S[i:]) for i in range(len(S))])
n_i, d_i = tb["at_risk"].values, tb["observed"].values
term = np.where(n_i - d_i > 0, d_i / (n_i * (n_i - d_i)), 0.0)
return point, np.sqrt(np.sum(rest**2 * term))
hi = rmst_and_se(d.loc[d.grp == "high", "time"], d.loc[d.grp == "high", "event"], 365)
lo = rmst_and_se(d.loc[d.grp == "low", "time"], d.loc[d.grp == "low", "event"], 365)
diff = hi[0] - lo[0]
se_d = np.hypot(hi[1], lo[1])
print(diff, diff - 1.96 * se_d, diff + 1.96 * se_d)lifelines' restricted_mean_survival_time(kmf, t=tau) reproduces the R point estimate exactly — pass the fitted model, not kmf.survival_function_, because the DataFrame form uses a trapezoid rule and comes out slightly smaller. Its return_variance=True is NOT the variance of the estimate: it is the variance of the restricted survival time distribution itself, and a confidence interval built from it is wide enough to cross zero. The standard error has to be computed by hand, which is what the block below does. statsmodels has no RMST. Every number on this page comes from the R.
τ has to be fixed in advance
RMST means nothing without a τ attached — an RMST with no τ is not a number. And τ is chosen, which is the one genuinely soft spot this method has.
figures/scripts/B3-07-rmst.RSame data, same patients, same model — only τ moves:
| τ (days) | Karnofsky >= 80 | Karnofsky <= 70 | Difference (days) | 95% CI | p |
|---|---|---|---|---|---|
| 180 | 165.1 | 144.5 | 20.6 | 4.8 – 36.5 | 0.011 |
| 270 | 229.9 | 188.4 | 41.5 | 15.3 – 67.8 | 0.002 |
| 365 | 284.9 | 221.6 | 63.3 | 26.1 – 100.6 | < 0.001 |
| 450 | 323.2 | 243.3 | 79.9 | 33.3 – 126.5 | < 0.001 |
| 550 | 356.5 | 265.8 | 90.7 | 33.1 – 148.2 | 0.002 |
| 650 | 382.3 | 280.1 | 102.3 | 35.9 – 168.6 | 0.003 |
Move τ from 180 to 650 days and the difference goes from 20.6 to 102.3 days, a factor of 5.0. These are not two different conclusions. They are two cuts of the same one — but if the paper reports only the second, and τ was settled after looking at the curves, the reader cannot tell a clinical reason from a chosen one.
The direction is worth noticing too. In this dataset the difference grows almost monotonically in τ, reaching 114.9 days at τ = 900 before flattening and easing back to 114.7 days in the last step. Figure 1 explains why: the two curves do not cross for almost all of follow-up, blue-grey stays above red, and every extra day of integration adds a little more area — until the tail, where the curves meet and cross and the difference stops accumulating. Data whose curves cross in the middle does not look like this; there the difference grows, then shrinks back visibly or even changes sign, and the choice of τ matters more still.
How far τ can go
RMST subtracts one curve’s area from another’s, so τ cannot run past the last observation in either group.
| Group | Last observation (days) |
|---|---|
| Karnofsky >= 80 | 1010 |
| Karnofsky <= 70 | 1022 |
The bound is set by the group with the shorter follow-up — Karnofsky >= 80 at 1010 days, not the other group’s 1022. So the longest usable τ on this page is 1010 days, the red dashed line on figure 2.
The reason is how a step function behaves once the last person leaves: the KM curve simply stops descending. It stops not because the risk ended but because nobody is left to have the event. Push τ past that point and the extra area is a rectangle extruded sideways from the final step — extrapolation, not estimation. Worse, the two groups get extruded by different lengths, so the difference is pushed around by an artefact.
Report both the difference and the ratio
| Quantity | Estimate | 95% CI | Reads as |
|---|---|---|---|
| RMST difference | 63.3 days | 26.1 – 100.6 days | Days of extra life on average within the first 365 days |
| RMST ratio | 1.29 | 1.09 – 1.51 | How many times the mean survival time within the first 365 days |
The difference says how many days longer, and is the quantity that can go straight onto a patient handout. The ratio says how many times longer, and travels better between studies because it carries no unit. The practical reason to report both is that they respond to τ differently: over the same move from τ = 180 to 650 days the difference grows by a factor of 5.0 (the table above), while the ratio of the two RMSTs travels only from 1.14 to 1.37, because numerator and denominator grow together. Give only one and the reader has nothing to check it against.
The difference excludes 0 and the ratio excludes 1; both point the same way. The p < 0.001 quoted here is the test on the difference — the ratio is tested on the log scale, and its p value is not the same number.
One sentence you can say to a patient
This is where RMST earns its keep: it needs no translation.
During the first year after diagnosis (τ = 365 days, or 11.99 months), patients in the Karnofsky >= 80 group lived 9.36 months on average, and those in the Karnofsky <= 70 group lived 7.28 months, a difference of 2.08 months (95% CI 0.86 to 3.30 months).
Put plainly: the group with the better performance status lived about 2 months longer, on average, during that first year. Saying that needs no prior explanation of instantaneous risk, and none of what proportional means.
RMST and median survival are also two different things that clinical discussion routinely conflates. The median answers how far half the patients got; RMST answers how long the average patient lived during a stated window. The median cannot be estimated at all until the curve has dropped below 0.5, which needs long enough follow-up; RMST is computable regardless, and that is part of why early reports like it.
How to read it in a paper
RMST usually appears as a KM figure plus a row or a small table giving each group’s RMST(τ), the difference, the ratio and their intervals. Three things to check:
- What τ is, and how it was chosen. The Methods should be able to say. Taking τ as the largest follow-up time in the shorter-followed arm is an acceptable pre-specified rule; no account at all of where τ came from leaves the difference impossible to evaluate.
- Whether the difference and the ratio both appear, with intervals. An RMST reported as a bare point estimate is as unusable as a bare hazard ratio.
- Whether there is a sensitivity analysis over τ. In modern trials the appendix often holds exactly the curve in figure 2 above. A single τ that happens to sit where the gap is widest sends you back to point 1.
One more thing that gets skipped: RMST replaces the effect measure, not the censoring assumption. The KM curve underneath still requires non-informative censoring, and RMST inherits that requirement whole — see censoring and truncation.
Common misuse
| Misuse | Why it is wrong |
|---|---|
| Choosing τ after seeing the curves | The difference is a function of τ (here 20.6 days to 102.3 days), so choosing τ chooses the size of the answer |
| Computing a row of τ values and reporting the best one | Selective reporting. Either pre-specify one, or put the whole curve in the appendix |
| Letting τ exceed the last observation in the shorter-followed arm | The extra area is the final step extruded sideways — extrapolation, not estimation |
| Setting τ out at the tail | That stretch of curve rests on a handful of people; the interval widens until there is no conclusion left |
| Reporting the difference or the ratio but not both | They respond to τ differently, so one alone cannot be checked against anything |
| Building the ratio’s CI additively on the ratio scale | A ratio is right-skewed and bounded below by 0; work on the log scale and transform back |
| Calling RMST a mean life expectancy | It covers [0, τ] only, and says nothing beyond it |
| Comparing an RMST difference against a hazard ratio by size | Different units, different questions — one is time, the other a ratio of risks |
Switching to RMST because cox.zph() came out significant, without saying so | Replacing the effect measure is a methodological decision; whether it was made before or after must be in the Methods |
| Treating RMST as a reason to skip the censoring check | Non-informative censoring is a KM requirement, and RMST is built on KM |
Where this page sits
- It is built on KM — see the Kaplan-Meier curve and the log-rank test. If the KM estimate is wrong, RMST is wrong; the number-at-risk table and the handling of censoring all follow that page’s rules.
- The hazard ratio it is compared against — see the Cox proportional hazards model. They are not substitutes: most papers report both, the HR carrying the primary claim and RMST the clinical reading.
- Repair four when proportional hazards fails — see the proportional hazards assumption and Schoenfeld residuals. The first three repairs (stratify, split the time axis, a time-varying coefficient) all still mend the Cox model; this one replaces the effect measure.
- The other route out of proportional hazards — see weighted log-rank tests and milestone survival. The division of labour: a weighted log-rank test answers whether the two curves differ, RMST answers by how much and in days. In a delayed-effect setting such as immunotherapy the two usually appear together.
- The censoring assumption underneath — see censoring and truncation.
Rerun every number on this page
/opt/homebrew/bin/Rscript figures/scripts/B3-07-rmst.RRead the figure
The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.
At a tau of 365 days the RMST analysis prints several numbers. Which one can be told to a patient directly as "on average this much longer alive"?
Show the answer and why
Correct answer: 63.3 days - the difference in restricted mean survival time between the arms
63.3 days is the difference in RMST, and its most useful property is its unit: days. It can be stated as "about two months longer alive, on average, over this year", which a hazard ratio cannot - a hazard ratio is a ratio, carries no unit of time, and cannot answer a patient asking how much longer. 19.0 is the standard error of that difference, describing precision rather than size; 26.1 is its lower 95% bound, and using an interval endpoint as the effect size reports a different quantity rather than a cautious version of the same one.
Three numbers in the output are measured in days. Which one cannot possibly be either arm's RMST?
Show the answer and why
Correct answer: 365.0 days is impossible - it equals tau, and RMST is the area under the curve from zero to tau
RMST is the area under the survival curve from zero to tau, so its ceiling is everyone surviving the whole window, which is tau itself. 365.0 can therefore only be tau and never an arm's RMST - a quick self-check: an "RMST" at or above tau means the wrong column was read. 284.9 and 221.6 are the two arms, and both are legitimate; a large gap between them does not make either impossible, since that gap is the quantity the analysis exists to measure.
Same data, same comparison: moving tau from 365 days to 90 shrinks the RMST difference sharply. What does that show?
Show the answer and why
Correct answer: The difference becomes 5.2 days - tau is part of the estimand, so it has to be fixed in advance
At 90 days the difference is 5.2 days; over a year it is 63.3. Neither is wrong - they answer two different questions, "how much longer alive over three months" and "over a year". Tau is therefore not a technical setting but part of the estimand, and it has to be fixed before the data are seen; choosing the tau that looks best afterwards is choosing the endpoint afterwards. 11.2 is the upper bound on the 90-day difference, not a point estimate.
Chapters that use this method
Sources and licences
This page is original writing