Kaplan-Meier survival under administrative censoring

The product-limit estimate multiplies survival before each distinct event time t_j by one minus the deaths at t_j divided by the number still at risk just before t_j. Chaining the step over all event times up to t gives the product of the factors, the Kaplan-Meier curve S(t). Patients censored at the cut-off leave the risk set at their censoring time, and because administrative censoring removes the latest recruits first, the number at risk falls steadily towards the end of follow-up.

Signature

S_j = S_prev * (1 - d_j / n_j)
Inputs
InputsDefinitionUnit
S_prevEstimated survival just before t_j, equal to S_j at the previous event time and 1 before the firstprobability
d_jNumber of patients with the event at t_jpatients
n_jNumber of patients still under observation and event-free just before t_j, excluding anyone already censoredpatients
Output
S_jEstimated probability of remaining event-free beyond event time t_jprobability

Function

Observed follow-up, Kaplan-Meier survival and restricted mean under administrative censoring

Maps each patient's entry date, the shared data cut-off and the event times seen by the cut-off to the observed follow-up and event indicator, then to the Kaplan-Meier survival curve, the restricted mean survival time up to the last observed follow-up and the share of mean survival that has to come from extrapolation beyond it. Staggered entry makes the censoring time differ between patients, so early recruits are observed for longer than late ones. The constant hazard estimated as events divided by person-time is the rate formula of the Adverse Event Rate page (HE-FM-AER-002), and mean survival with an exponential tail has the form of HE-FM-BTH-002 on the Bathtub Hazard page; neither is repeated here.

Computational function

  • Computational function: Kaplan-Meier curve, restricted mean and tail share from entry months, event times and a data cut-off

    Takes the data a trial arm usually holds, each patient's entry month, the event time where an event was seen by the cut-off, and the cut-off itself, and returns the censoring times, the observed records, the Kaplan-Meier curve, the restricted mean to the last observed follow-up and the share of mean survival from an exponential tail. It builds the risk sets n_j and deaths d_j of HE-FM-ADMC-002 from the observed records of HE-FM-ADMC-001, then applies HE-FM-ADMC-003 and HE-FM-ADMC-004. The inputs therefore differ from the Kaplan-Meier formula's variables: the formula takes the counts at one event time, while the function derives every count from patient-level data. When no tail hazard is supplied it uses events divided by person-time, HE-FM-AER-002.

    Inputs and outputs: entry: Entry month of each patient on the trial calendar; required. Unit: months.; event: Months from entry to the event, or Inf when no event was seen by the cut-off; required, one per patient. Unit: months.; cutoff: Calendar month of the data cut-off; required. Unit: months.; h: Constant hazard assumed after the last observed follow-up; optional, above zero, defaults to events divided by person-time. Unit: events per patient-month.; C: Censoring time of each patient. Unit: months.; Y: Observed time of each patient. Unit: months.; delta: Event indicator of each patient, 1 or 0. Unit: none.; t_j: Distinct event times. Unit: months.; S: Kaplan-Meier survival after each event time. Unit: probability.; RMST_tau: Restricted mean to the last observed follow-up tau. Unit: months.; A_tail: Area under the exponential tail after tau. Unit: months.; P_tail: Share of mean survival from the tail. Unit: proportion.

    Assumption: All censoring is administrative and unrelated to prognosis, the arm has at least one event, a patient censored at an event time is counted at risk for it, and the hazard after the last observed follow-up is constant. Results are undiscounted.

    Worked example (Article eight-patient arm with a 36-month cut-off): The function reproduces the article's records, the curve of 0.875, 0.75, 0.6 and 0.4, the restricted mean of 21.7 months and, at the trial hazard of 4 deaths in 136 patient-months, a tail share of about 39%. entry = (0, 2, 4, 8, 12, 16, 20, 24); event = (10, Inf, 20, 6, Inf, 14, Inf, Inf); cutoff = 36; C = (36, 34, 32, 28, 24, 20, 16, 12); Y = (10, 34, 20, 6, 24, 14, 16, 12); delta = (1, 0, 1, 1, 0, 1, 0, 0); t_j = (6, 10, 14, 20); S = (0.875, 0.75, 0.6, 0.4); RMST_tau = 21.7; h = 0.029412; A_tail = 13.6; P_tail = 0.3853

    Worked example (Complete follow-up leaves no tail): Two illustrative patients, not from the article, who both die before the cut-off give a curve that falls to 0, a restricted mean equal to the mean observed time of 6.5 months and no tail, a limiting case that checks the implementation. entry = (0, 6); event = (5, 8); cutoff = 36; C = (36, 30); Y = (5, 8); delta = (1, 1); t_j = (5, 8); S = (0.5, 0); RMST_tau = 6.5; h = 0.153846; A_tail = 0; P_tail = 0

    Excel: =CutOff-B2, =IF(C2="",D2,MIN(C2,D2)) and =IF(AND(C2<>"",C2<=D2),1,0) With one patient per row from row 2, entry month in column B and event time in column C (blank when no event was seen), these give the censoring time in column D, the observed time in column E and the event flag in column F. With column E named ObservedRange and column F named EventRange, for each distinct event time in column H, =COUNTIF(ObservedRange,">="&H2) and =COUNTIFS(ObservedRange,H2,EventRange,1) give the number at risk and the deaths, and the survival column is =1-J2/I2 in the first row and =K2*(1-J3/I3) copied down.

    R: admin_km <- function(entry, event, cutoff, h = NULL) { C <- cutoff-entry; Y <- pmin(event, C); delta <- as.numeric(event <= C); tj <- sort(unique(Y[delta == 1])); nj <- sapply(tj, function(t) sum(Y >= t)); dj <- sapply(tj, function(t) sum(Y == t & delta == 1)); S <- cumprod(1-dj/nj); tau <- max(Y); RMST <- sum(c(1, S) * diff(c(0, tj, tau))); if (is.null(h)) h <- sum(delta)/sum(Y); tail <- S[length(S)]/h; list(C = C, Y = Y, delta = delta, t = tj, S = S, RMST = RMST, h = h, tail = tail, share = tail/(RMST+tail)) } Event times for patients alive at the cut-off are entered as Inf; admin_km(c(0, 2, 4, 8, 12, 16, 20, 24), c(10, Inf, 20, 6, Inf, 14, Inf, Inf), 36)[["RMST"]] gives 21.7.

    Python: def admin_km(entry, event, cutoff, h=None): C = [cutoff-e for e in entry]; Y = [min(t, c) for t, c in zip(event, C)]; delta = [int(t <= c) for t, c in zip(event, C)]; tj = sorted({y for y, x in zip(Y, delta) if x}); S = list(itertools.accumulate([1-sum(x for y, x in zip(Y, delta) if y == t)/sum(y >= t for y in Y) for t in tj], operator.mul)); tau = max(Y); RMST = sum(s*(b-a) for s, a, b in zip([1]+S, [0]+tj, tj+[tau])); h = h if h is not None else sum(delta)/sum(Y); tail = S[-1]/h; return C, Y, delta, tj, S, RMST, h, tail, tail/(RMST+tail) Uses the math, itertools and operator modules, with math.inf for patients alive at the cut-off; the sixth value returned for the article's arm is 21.7.

    Test (Complete follow-up gives the mean observed time): With every patient dying before the cut-off, the restricted mean to the last death equals the average observed time. Expected result: TRUE. Excel check: =ABS((1*5+0.5*3)-AVERAGE(5,8))<1E-9

    Test (Article curve and restricted mean reproduced): Survival after month 20 rounds to 0.4 and the restricted mean to month 34 rounds to 21.7. Expected result: TRUE. Excel check: =AND(ROUND((1-1/8)*(1-1/7)*(1-1/5)*(1-1/3),4)=0.4,ROUND(SUMPRODUCT({1,0.875,0.75,0.6,0.4},{6,4,4,6,14}),4)=21.7)

    Common error (Censoring times entered as event times): Entering cut-off minus entry as an event time for the four patients alive at the cut-off turns them into deaths. In the article's arm the curve then falls to 0 at month 34, the restricted mean drops to the mean observed time of 17 months and no tail remains, figures computed here for illustration.

    Source: Clark TG, Bradburn MJ, Love SB, Altman DG. Survival analysis part I: basic concepts and first analyses. British Journal of Cancer. 2003;89(2):232-238. Section on the Kaplan-Meier survival estimate, which defines n_j as the number alive just before t_j and d_j as the number of events at t_j and lets each patient contribute for as long as they are known to be event-free.

    C_i = d - e_i; Y_i = min(T_i, C_i); delta_i = (T_i <= C_i); S_j = S_prev * (1 - d_j / n_j); RMST_tau = sum_(k=1)^K [S_k * L_k]; A_tail = S_tau / h; P_tail = A_tail / (RMST_tau + A_tail)

Try this function

Implementations

  • Excel

    Kaplan-Meier step from observed times and event flags

    With the observed times in ObservedRange, the event flags in EventRange and one distinct event time in EventTime, the first two formulas return the number at risk in AtRisk and the deaths in Deaths; the third, copied down the event times with SurvPrev pointing to the cell above (1 for the first row), returns the survival curve.

    =COUNTIF(ObservedRange,">="&EventTime); =COUNTIFS(ObservedRange,EventTime,EventRange,1); =SurvPrev*(1-Deaths/AtRisk)

Assumptions

  • Censoring at the cut-off unrelated to prognosis

    Patients censored at the cut-off are as likely to have a later event as those still observed. Because the censoring time is set by the entry date, this holds only if survival does not depend on when patients were recruited; changes in treatment or diagnosis during a long recruitment period break it.

  • Censored patients at risk at their own censoring time

    A patient censored at the same time as an event is counted in the risk set for that event and removed afterwards, so n_j counts everyone whose observed time is t_j or longer.

Worked examples

  • Kaplan-Meier step at month 6 with eight at risk

    In the article's illustrative arm all eight patients are at risk at the first death, at month 6, so survival falls to 0.875.

    S_prev = 1; d_j = 1; n_j = 8; S_j = 0.875
  • Kaplan-Meier step at month 10 with seven at risk

    Seven patients remain at risk at the second death, at month 10, and survival falls from 0.875 to 0.75.

    S_prev = 0.875; d_j = 1; n_j = 7; S_j = 0.75
  • Kaplan-Meier step at month 14 after the last recruit is censored

    Patient 8, the last recruit, was censored at month 12, so with the two earlier deaths also removed five patients are at risk at month 14, and survival falls from 0.75 to 0.6.

    S_prev = 0.75; d_j = 1; n_j = 5; S_j = 0.6
  • Kaplan-Meier step at month 20 with three at risk

    Patient 7 was censored at month 16, so only three patients remain at risk at month 20, and survival falls from 0.6 to 0.4. The curve then stays at 0.40 to month 34, the last observed follow-up, and rests on one patient after month 24.

    S_prev = 0.6; d_j = 1; n_j = 3; S_j = 0.4

Common errors

  • Censored patients kept in the Kaplan-Meier risk set

    Removing only the deaths from the risk set treats censored patients as if they were still observed. In the article's arm the risk sets at months 14 and 20 become 6 and 5 instead of 5 and 3, and survival ends at 0.50 rather than 0.40, the same answer as counting every censored patient as a survivor. The 0.50 is computed here for illustration.

  • Censored patients dropped from the analysis

    Excluding the four censored patients leaves four known outcomes, all deaths, which implies that no one survives. The Kaplan-Meier estimate of 0.40 instead uses each patient for as long as they were observed.

Sources

  • Kaplan-Meier product-limit estimate and its assumptions

    Clark TG, Bradburn MJ, Love SB, Altman DG. Survival analysis part I: basic concepts and first analyses. British Journal of Cancer. 2003;89(2):232-238. Section on the Kaplan-Meier survival estimate, which gives survival at t_j as survival at the previous event time multiplied by one minus d_j divided by n_j, notes that without censoring it reduces to the proportion event-free, and states that it assumes the same survival for patients recruited early and late.

    View source →

  • Product-limit estimator in a survival analysis textbook

    Kalbfleisch JD, Prentice RL. The Statistical Analysis of Failure Time Data. 2nd ed. Hoboken, NJ: Wiley; 2002. Standard derivation of the Kaplan-Meier product-limit estimator for right-censored data.

    View source →

Canonical Identity

Stable URI · Machine-readable · Resolvable · CC BY 4.0