Tutorials › Biostatistics › SAS PROC LIFETEST for Survival Analysis

Survival Analysis

SAS PROC LIFETEST for Survival Analysis

A practical guide to Kaplan–Meier estimation in SAS, including time-to-event data structures, censoring, survival curves, median survival, confidence intervals, log-rank tests, stratified analyses, ODS output, clinical-trial reporting, and common programming mistakes.

Intermediate 22 min read

What You'll Learn

  • How PROC LIFETEST handles time-to-event data and censoring
  • How the Kaplan–Meier estimator works conceptually
  • How to specify TIME and censoring correctly in SAS
  • How to compare treatment groups with the log-rank test
  • How to obtain medians, quartiles, estimates, and output data sets
  • How PROC LIFETEST fits into clinical-trial TLF production and QC

Introduction

Survival analysis is used whenever the outcome of interest is a time-to-event endpoint. In clinical trials, the event might be death, disease progression, relapse, treatment failure, or another protocol-defined event.

The defining feature is that not every patient necessarily experiences the event during the observation period. Some patients are still event-free when follow-up ends, some withdraw, and some are lost to follow-up. Their exact event time is therefore unknown, but their available follow-up still contains information.

This is why ordinary means, standard deviations, and t-tests are usually inadequate for primary analysis of endpoints such as overall survival (OS) and progression-free survival (PFS).

Key idea: PROC LIFETEST is SAS/STAT's nonparametric procedure for estimating survival distributions and related quantities. Its most familiar use in clinical trials is the Kaplan–Meier product-limit estimator, together with survival plots, median survival estimates, confidence intervals, and group-comparison tests.

What Is a Time-to-Event Endpoint?

For each subject, define a time \(T\) from a clearly specified origin to the event of interest. The survival function is:

$$ S(t)=P(T>t) $$

It is the probability that the event has not occurred by time \(t\), under the usual definition of the survival function.

Examples in oncology include:

  • Overall survival: time from a defined origin to death from any cause.
  • Progression-free survival: time from a defined origin to progression or death, according to the protocol-defined endpoint.
  • Duration of response: time from first qualifying response to progression or death among responders, according to the prespecified definition.
  • Disease-free survival: time from a defined landmark to recurrence, death, or another protocol-defined event.

The statistical procedure does not determine the clinical definition of the endpoint. That definition comes from the protocol, statistical analysis plan, and endpoint derivation rules.

The Three Pieces of a Basic Survival Dataset

A simple right-censored survival dataset generally needs three concepts:

ConceptExample SAS variableMeaning
SubjectUSUBJIDUnique patient identifier
TimeAVALObserved follow-up time
Event indicatorEVENT1 = event, 0 = censored
TreatmentTRT01PTreatment group used for comparison

The crucial point is that the time variable contains both event times and censoring times. The event indicator tells PROC LIFETEST how to interpret each observation.

Understanding Censoring

Suppose a patient is followed for 18 months and dies at Month 18. That is an event at 18 months.

Another patient is followed for 18 months, remains alive, and then the study ends. We do not know when that patient would eventually die. We only know that the death time is greater than 18 months. This is right censoring at 18 months.

A third patient might withdraw at Month 10 while alive. If the analysis rules treat that observation as censored at Month 10, PROC LIFETEST uses the information that the patient remained event-free through that point.

Censoring is not the same as failure. If a patient is censored at 18 months, the analysis does not assume the event happened at 18 months. It records that the patient was known to be event-free through the censoring time.

The TIME Statement

The central PROC LIFETEST syntax is:

proc lifetest data=analysis;
    time aval*event(0);
run;

The expression:

time aval*event(0);

means that AVAL is the time variable and that the value 0 of EVENT identifies censored observations. Therefore, a value of 1 represents the event of interest in this example.

This is one of the most important lines in the entire program. A reversed or incorrect event coding can completely change the analysis.

Event Coding: The Mistake to Avoid

Suppose the data are coded:

EVENTMeaning
1Death / event occurred
0Censored

Then:

time aval*event(0);

is appropriate.

If instead the dataset uses:

EVENTMeaning
0Death / event occurred
1Censored

then the censoring value in the TIME statement must be changed accordingly.

Programming rule: Never copy event(0) automatically. First verify the actual derivation of the event indicator in the analysis dataset.

The Kaplan–Meier Estimator

The Kaplan–Meier estimator is a product-limit estimator. At each distinct event time \(t_j\), it multiplies the estimated probability of surviving that event time given survival immediately beforehand.

$$ \widehat S(t) = \prod_{t_j\le t} \left( 1-\frac{d_j}{n_j} \right) $$

where:

  • \(d_j\) = number of events at event time \(t_j\)
  • \(n_j\) = number of subjects at risk immediately before \(t_j\)

The curve therefore changes at event times. Censoring observations do not cause the Kaplan–Meier curve itself to step downward, although censoring changes the risk set for subsequent event times.

A Small Hand Calculation

Imagine five patients with event/censoring information:

PatientTimeStatus
0013Event
0025Censored
0037Event
0049Event
00512Censored

At Month 3, five patients are initially at risk and one event occurs:

$$ \widehat S(3) = 1\times\frac{5-1}{5} = 0.80 $$

The censoring at Month 5 does not directly reduce the curve. It removes that patient from the risk set for later event times.

At Month 7, four patients are at risk immediately before the event, so:

$$ \widehat S(7) = 0.80\times\frac{4-1}{4} = 0.60 $$

This stepwise logic is what PROC LIFETEST automates.

An Interactive Kaplan–Meier Example

The following simulated example illustrates two treatment groups. Hover over the curves to inspect approximate survival values at selected times. Censoring marks are shown on the curves.

Figure 1. Simulated Kaplan–Meier Survival Curves
Illustrative time-to-event data. The curves, censoring marks, and risk table are simulated for teaching purposes and are not from an actual clinical trial.
Treatment A
Treatment B
50% survival reference
Censoring
Teaching example
n = 80
Primary display
KM + risk table

The visual illustrates the same concepts that PROC LIFETEST produces with PLOTS=SURVIVAL(ATRISK=...). Exact values from a real study must come from the analysis dataset and PROC LIFETEST output.

Group061218243036

Reading a Kaplan–Meier Curve

The y-axis represents the estimated probability of remaining event-free. The x-axis represents time from the analysis origin.

Visual featureInterpretation
Vertical dropOne or more events occurred at that time.
Flat segmentNo events occurred during that interval.
Censoring tickA subject left the risk set without experiencing the event.
Higher curveHigher estimated probability of remaining event-free at that time.
Crossing curvesThe relative treatment pattern changes over time; proportional-hazards assumptions should not be inferred from the picture alone.

PROC LIFETEST: The Minimal Clinical-Trial Program

For a single overall survival curve:

ods graphics on;

proc lifetest data=adtte
              plots=survival(atrisk);
    time aval*cnsr(1);
run;

Here the example assumes CNSR=1 means censored. That coding is common in CDISC-oriented time-to-event analysis datasets, but the actual study derivation must be verified before programming.

Important CDISC distinction: A variable named CNSR often uses 1 = censored and 0 = event, whereas a generic variable named EVENT often uses 1 = event and 0 = censored. The variable name does not determine its meaning; the analysis specification does.

Adding Treatment Groups With STRATA

To estimate separate Kaplan–Meier curves by treatment:

ods graphics on;

proc lifetest data=adtte
              plots=survival(atrisk);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

The STRATA statement creates separate survival estimates for the levels of TRT01P. The TEST=LOGRANK option requests the log-rank comparison of the survival distributions.

Why the Log-Rank Test Is Separate From the Kaplan–Meier Curve

The Kaplan–Meier estimator is descriptive: it estimates survival over time. The log-rank test is inferential: it tests whether survival distributions differ between groups under its assumptions and weighting structure.

A typical output package therefore contains both:

  • Kaplan–Meier estimates and curves
  • Number at risk
  • Median survival and confidence interval, when estimable
  • Log-rank test statistic and p-value
Do not interpret a visual separation as a statistically significant difference. Conversely, a statistically significant log-rank result does not tell you by itself how large or clinically important the treatment effect is.

Confidence Intervals for the Survival Curve

PROC LIFETEST can display pointwise confidence limits around the Kaplan–Meier survival estimate.

ods graphics on;

proc lifetest data=adtte
              plots=survival(cl atrisk);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

The confidence interval is an uncertainty interval around the estimated survival function. It is not a prediction interval for an individual patient's future survival time.

Confidence-Limit Transformations

Survival probabilities are constrained between 0 and 1, while a simple normal approximation on the raw survival scale can produce awkward behavior near the boundaries. Kaplan–Meier confidence intervals are therefore commonly constructed using a transformation of the survival estimate.

When producing a regulated clinical-trial figure, the confidence-limit method should be consistent with the statistical analysis specification and the programming standard.

Adding an At-Risk Table

The number at risk is one of the most important pieces of information on a Kaplan–Meier figure.

proc lifetest data=adtte
              plots=survival(atrisk=0 to 36 by 6);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

The syntax requests the number of subjects at risk at specified time points. The at-risk table prevents readers from interpreting a long tail of a curve as equally reliable when very few subjects remain under observation.

Reporting principle: A Kaplan–Meier curve without an at-risk table can be substantially harder to interpret, particularly when follow-up becomes sparse.

Median Survival

The median survival is the time \(t\) at which the survival function reaches approximately 0.50:

$$ \widehat S(t)=0.50 $$

If the Kaplan–Meier curve never falls to 50%, the median survival is not estimable within the observed follow-up.

Do not force a median. If fewer than half of subjects experience the event, the median may be not reached. This is a valid result, not a programming failure.

Requesting Median and Quartile Estimates

PROC LIFETEST can produce quartile estimates for survival time. The default Kaplan–Meier method is the product-limit method.

proc lifetest data=adtte
              method=pl;
    time aval*cnsr(1);
    strata trt01p;
run;

The output includes the quartile table when the requested survival quantiles are estimable. In clinical reporting, the median is often the most prominently reported quantile.

Interpreting "Not Reached"

Suppose a treatment arm has an estimated survival of 62% at the end of follow-up. The survival curve never reaches 50%.

Then the median OS is not estimable from the available follow-up.

It would be incorrect to replace this with a numerical value merely because a downstream table expects a number.

SituationAppropriate reporting
Curve crosses 0.50Report estimated median and confidence interval as specified.
Curve remains above 0.50Report median as not reached / not estimable according to the reporting convention.
Very sparse tailInterpret late survival estimates cautiously and show numbers at risk.

Extracting Results With ODS OUTPUT

One of the most useful skills for a clinical programmer is moving PROC LIFETEST results into SAS datasets for automated TLF production.

For example:

ods output
    ProductLimitEstimates=km_est
    Quartiles=km_quartiles
    HomTests=logrank_test;

proc lifetest data=adtte
              method=pl
              plots=survival(atrisk);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

ods output close;

The SAS documentation identifies ProductLimitEstimates as the ODS table containing product-limit survival estimates, Quartiles as the table for survival-time quartiles, and HomTests as the table containing results of k-sample tests from the STRATA analysis.

Why ODS OUTPUT Matters in Clinical Programming

Printing a PROC LIFETEST table to the Results Viewer is useful for exploration. A production clinical-programming workflow usually needs more:

1
Run PROC LIFETEST using the finalized analysis dataset.
2
Capture required ODS output tables into SAS datasets.
3
Derive report-ready values and formats.
4
Generate tables, listings, and figures from controlled datasets.
5
Perform independent or double-programming validation.

OUTSURV: Saving the Survival Curve

PROC LIFETEST also provides an OUTSURV= option for creating a dataset containing survival estimates.

proc lifetest data=adtte
              outsurv=km_curve;
    time aval*cnsr(1);
    strata trt01p;
run;

The correct option name is OUTSURV=:

proc lifetest data=adtte
              outsurv=km_curve;
    time aval*cnsr(1);
    strata trt01p;
run;

More precisely, the production syntax should be:

proc lifetest data=adtte
              outsurv=km_curve;
    time aval*cnsr(1);
    strata trt01p;
run;
Programming note: The PROC option is spelled OUTSURV=. The examples above intentionally show the spelling issue because it is an easy typo to make when writing code from memory. Use OUTSURV= in production.

What Is in the OUTSURV Dataset?

For the product-limit method, the output contains the analysis time and survival estimate, along with relevant stratum information and additional variables depending on the requested options and analysis.

This makes OUTSURV= particularly useful when you need to build a customized survival figure rather than using the default ODS Graphics plot.

A Clean Production Pattern

%let alpha = 0.05;

ods graphics on;

ods output
    ProductLimitEstimates = work.km_est
    Quartiles              = work.km_quartiles
    HomTests               = work.logrank;

proc lifetest data=adam.adtte
              method=pl
              alpha=&alpha
              plots=survival(cl atrisk=0 to 36 by 6);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

ods graphics off;

This pattern is useful because it makes the analysis inputs and captured outputs explicit. In a real project, the exact dataset, treatment variable, time origin, censoring rules, and plot options should come from the SAP and programming specification.

Using the ID Statement

The ID statement can be useful when patient-level identifiers need to be carried into certain output tables.

proc lifetest data=adtte
              method=pl;
    time aval*cnsr(1);
    id usubjid;
run;

Whether an ID variable is useful depends on the output being requested. It should not be added automatically just because a subject identifier exists.

BY-Group Versus STRATA Analysis

A common programming decision is whether to use BY or STRATA.

ApproachTypical purpose
STRATAEstimate and compare survival curves across groups within one analysis.
BYRun separate PROC LIFETEST analyses for independent BY groups.

For a treatment comparison, STRATA is usually the natural starting point because it produces the group-specific curves and supports k-sample comparison tests.

Stratified Log-Rank Analysis

Clinical trials sometimes require stratification by a baseline factor used in randomization or specified in the analysis plan.

PROC LIFETEST supports stratified k-sample tests through the STRATA statement's options. The exact implementation should match the statistical analysis plan.

Do not confuse strata used for estimation with adjustment in a multivariable model. PROC LIFETEST is primarily a nonparametric survival-analysis procedure. If the primary analysis requires a Cox proportional hazards model with covariate adjustment, PROC PHREG is generally the relevant SAS procedure.

PROC LIFETEST Versus PROC PHREG

QuestionPROC LIFETESTPROC PHREG
Kaplan–Meier curveYesNo, not as its primary purpose
Nonparametric survival estimationYesNo
Median survivalYesNot the primary use
Log-rank comparisonYesNot the primary use
Cox proportional hazards modelNoYes
Hazard ratiosNoYes
Covariate-adjusted hazard analysisLimitedYes

In many clinical-trial programs, both procedures appear in the same analysis workflow: LIFETEST for descriptive Kaplan–Meier outputs and PHREG for the prespecified Cox-model analysis.

Hazard Ratio Is Not the Same as a Kaplan–Meier Difference

The Kaplan–Meier curve describes survival probabilities over time. A hazard ratio is a model-based relative measure of the instantaneous event rate under the specified model.

Therefore, a figure showing two curves should not be labeled as a hazard-ratio plot, and a hazard ratio should not be interpreted as the vertical difference between two Kaplan–Meier curves.

Checking the Risk Set

The number at risk at time \(t\) represents subjects who remain under observation and eligible to contribute to the risk set immediately before that time, subject to the analysis rules.

It is not simply the number of subjects whose plotted line has not ended visually. The exact risk-set definition follows the survival-analysis data and censoring rules.

Why Censoring Changes the Denominator

Suppose ten patients are initially at risk. Two experience events at Month 6, and one is censored before Month 9.

The censored subject does not contribute an event, but also does not remain in the risk set after the censoring time.

This matters because later event probabilities use the number remaining at risk at each event time.

Ties: Multiple Events at the Same Time

Clinical trial data may contain multiple events at the same recorded time. The Kaplan–Meier estimator handles multiple events at a common event time using the number at risk immediately before the time and the number of events at that time.

This is another reason that hand-built survival calculations can become error-prone when the dataset is larger than a teaching example.

Delayed Entry and Left Truncation

Some studies do not observe subjects from time zero. A subject may enter the risk set after the origin because the analysis begins at a landmark or because eligibility requires survival to a particular time.

This is a different situation from ordinary right censoring and should not be handled by simply changing the event indicator.

If delayed entry or left truncation is part of the analysis, use the appropriate PROC LIFETEST entry-time functionality and follow the prespecified statistical method.

Clinical-trial warning: Do not invent an entry-time rule during programming. Delayed entry changes the risk set and therefore changes the survival estimate.

Competing Risks

Standard Kaplan–Meier analysis treats competing events according to the specified censoring/event framework. When the scientific question is a cumulative incidence function in the presence of competing risks, the analysis is different.

PROC LIFETEST supports competing-risks analyses through the EVENTCODE= option and cumulative-incidence functionality.

proc lifetest data=analysis
              plots=cif(test);
    time aval*cnsr(1) / eventcode=1;
    strata trt01p;
run;

The exact event and censoring coding must be aligned with the competing-risks definition. Do not treat a competing event as ordinary censoring unless that is the intended estimand.

Restricted Mean Survival Time

When proportional hazards are questionable or when a fixed-time summary is more clinically interpretable, restricted mean survival time (RMST) can be useful.

Conceptually, RMST through a restriction time \(\tau\) is the area under the survival curve:

$$ RMST(\tau)=\int_0^\tau S(t)\,dt $$

PROC LIFETEST includes RMST functionality in current SAS/STAT releases. Whether RMST is a primary, secondary, or sensitivity analysis is a statistical-analysis decision rather than a default plotting choice.

Choosing the Time Origin

A survival endpoint is meaningless without a defined time origin.

Common origins include:

  • Date of randomization
  • Date of first dose
  • Date of surgery
  • Date of response
  • Date of diagnosis

The origin must be defined consistently with the endpoint definition. For example, PFS in a randomized oncology trial is commonly measured from randomization or another prespecified origin, while duration of response begins after response criteria are met.

Programming principle: PROC LIFETEST does not know what your clinical time origin should be. It only analyzes the time variable you give it.

Deriving Analysis Time

A typical ADaM time-to-event dataset might contain:

USUBJID    TRT01P       PARAMCD   STARTDT     ADT         AVAL    CNSR
01-001     Drug A       OS        2025-01-10  2026-02-14  400     0
01-002     Drug A       OS        2025-01-10  2026-03-05  419     1
01-003     Placebo      OS        2025-01-12  2026-01-20  373     0

The analysis-time variable AVAL is the quantity passed to PROC LIFETEST. The exact derivation depends on the unit and endpoint definition.

Days, Months, or Weeks?

The procedure itself can analyze any appropriate numeric time scale. Clinical reporting often uses days for the underlying analysis and months for display.

If time is reported in months, define the conversion rule explicitly. A month is not universally equal to 30 days in every analysis convention.

ScaleTypical use
DaysPrecise derivation and analysis dataset
WeeksSome disease areas and shorter follow-up
MonthsReadable clinical display and summary
YearsLong-term survival reporting

Common SAS Format Pattern

Treatment labels should be formatted consistently across tables and figures.

proc format;
    value $trtfmt
        "A" = "Drug A"
        "B" = "Drug B";
run;

proc lifetest data=adtte
              plots=survival(atrisk=0 to 36 by 6);
    time aval*cnsr(1);
    strata trt01p;
    format trt01p $trtfmt.;
run;

In production work, treatment labels are often controlled centrally rather than recreated independently inside each program.

Filtering the Analysis Population

Do not rely on PROC LIFETEST to infer the analysis population. Create or receive a dataset that already implements the SAP-defined population rules.

data adtte_anl;
    set adam.adtte;
    where saffl = "Y"
      and paramcd = "OS";
run;

proc lifetest data=adtte_anl
              plots=survival(atrisk);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

The exact population flag and endpoint variable names will vary by study.

Handling Missing Analysis Time

Observations with missing values needed by the procedure cannot contribute normally to the survival analysis. Missingness should therefore be investigated before running the final program.

A useful pre-analysis QC step is:

proc freq data=adtte;
    tables paramcd*aval / missing;
run;

proc means data=adtte n nmiss min median max;
    var aval;
run;

The precise QC program will depend on the dataset structure, but the principle is simple: know how many records are actually entering the analysis.

Duplicate Subject-Endpoint Records

A standard single-endpoint survival analysis generally expects one analysis record per subject for that endpoint.

If the dataset contains multiple records per subject and endpoint, determine whether they represent:

  • Different analysis parameters
  • Different competing events
  • Multiple analysis strategies
  • Duplicate records

Do not simply remove duplicates without understanding their origin.

PROC SORT and Analysis Order

PROC LIFETEST handles the survival calculation internally, so sorting the input dataset by time is not generally required for the statistical calculation.

Nevertheless, sorting by subject and time can make upstream QC and output inspection easier:

proc sort data=adtte_anl;
    by trt01p usubjid aval;
run;

Generating a Kaplan–Meier Figure for a CSR

A production figure commonly includes:

  • Survival probability on the y-axis
  • Analysis time on the x-axis
  • One curve per treatment group
  • Censoring marks
  • 95% confidence limits when specified
  • Number at risk beneath the plot
  • A legend with controlled treatment labels
  • A figure footnote describing the endpoint and censoring

The exact style should be controlled by the organization's TLF shell and statistical programming standards.

Example Figure Specification

SpecificationExample
EndpointOverall survival
PopulationIntent-to-treat population
Time originDate of randomization
EventDeath from any cause
CensoringPer SAP-defined OS censoring rules
EstimatorKaplan–Meier
ComparisonLog-rank test
Confidence limits95% pointwise limits, if specified
Risk table0, 6, 12, 18, 24, 30, 36 months

ODS Graphics

PROC LIFETEST integrates with SAS ODS Graphics for survival plots and related visualizations.

ods graphics on;

proc lifetest data=adtte
              plots=survival(atrisk=0 to 36 by 6);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

ods graphics off;

The PLOTS= option controls the requested graphical output. SAS documentation lists survival plots, survival plots with at-risk numbers, confidence limits, and test displays among the available LIFETEST graphics.

Common PLOTS= Variations

RequestPurpose
PLOTS=SURVIVALKaplan–Meier survival curve
PLOTS=SURVIVAL(ATRISK)Curve with numbers at risk
PLOTS=SURVIVAL(CL)Curve with pointwise confidence limits
PLOTS=SURVIVAL(TEST)Survival plot with homogeneity test information
PLOTS=SURVIVAL(ATRISK CL)Curve, risk table, and confidence limits

Exact plot syntax and supported options can vary with SAS/STAT release, so production programmers should verify the version-specific documentation used by their environment.

Adding Censoring Marks

Censoring marks are important because they distinguish a flat survival segment from an absence of follow-up.

A curve can remain flat for two very different reasons:

  • No events occurred among subjects at risk.
  • Subjects were censored, leaving fewer patients at risk for subsequent times.

The marks make this distinction visible.

Survival Curve Crossing

Suppose Treatment A has higher survival early but Treatment B catches up later. The curves may cross.

Curve crossing can make a single summary measure such as a hazard ratio less straightforward to interpret and can challenge proportional-hazards assumptions.

The appropriate response is not to hide the crossing. Instead, investigate the estimand, time-specific effects, RMST, or other prespecified analyses as appropriate.

The Log-Rank Test and Its Assumptions

The log-rank test compares survival distributions using event-time information. It is especially sensitive to differences that persist over follow-up rather than to every possible pattern of time-varying treatment effect.

A non-significant log-rank test does not prove that treatment effects are identical. It means the specified test did not provide sufficient evidence against the null under the analysis assumptions and sample size.

Multiple Treatment Groups

PROC LIFETEST can handle more than two strata.

proc lifetest data=adtte
              plots=survival(atrisk);
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

For three treatment groups, the overall test asks whether the survival distributions are homogeneous across the groups. If pairwise comparisons are needed, multiplicity control should follow the statistical analysis plan.

Multiplicity Adjustments

When multiple pairwise survival comparisons are performed, an unadjusted collection of p-values can inflate the family-wise type I error rate.

PROC LIFETEST provides adjustment options for certain multiple-comparison analyses. The choice of adjustment should be driven by the SAP rather than selected after looking at the observed p-values.

Confidence Intervals for Median Survival

The median estimate should be accompanied by a confidence interval when estimable and when required by the reporting specification.

The confidence interval for a median is not the same thing as the confidence band around the entire Kaplan–Meier curve.

QuantityWhat it describes
Pointwise survival CIUncertainty around \(S(t)\) at a particular time.
Median CIUncertainty around the time at which survival reaches 50%.
Confidence bandSimultaneous or band-type uncertainty over a range of times.

Why the Median Can Be Unstable

If the curve crosses 50% only near the end of follow-up, the median may be sensitive to a small number of events.

This is another reason to examine:

  • Number of events
  • Number at risk
  • Confidence intervals
  • Length of follow-up
  • Shape of the survival curve

A median should never be interpreted in isolation.

Restricted Follow-Up and Administrative Censoring

Many trials specify a data cutoff date. Patients who have not experienced the event by the cutoff are censored according to the endpoint-specific rules.

The resulting survival estimate is therefore conditional on the information available by that cutoff.

Data cutoff matters. Two analyses of the same trial can produce different Kaplan–Meier estimates if they use different data cutoff dates.

Post-Cutoff Data Must Not Leak Into the Analysis

A common programming failure is allowing events recorded after the analysis cutoff to enter the endpoint dataset.

The derivation of ADTTE should already implement the cutoff rules before PROC LIFETEST is called.

The survival procedure should analyze the finalized analysis dataset rather than silently redefining the endpoint.

Example ADTTE-Oriented Workflow

1
Derive the analysis start date according to the endpoint definition.
2
Determine the event date and event type.
3
Apply the SAP-defined censoring rules.
4
Calculate analysis time and event/censoring indicator.
5
Validate one analysis record per subject and endpoint.
6
Run PROC LIFETEST for descriptive survival estimates and comparisons.
7
Capture ODS output for downstream TLF production.
8
Generate the final table and figure.
9
Perform independent QC against the specification and source data.

Building a Survival Summary Table

A typical survival table may contain:

StatisticDrug ADrug B
N120118
Number of events6271
Median survival18.4 months14.2 months
95% CI15.8–22.711.9–17.1
Log-rank p-value0.032

The numbers above are illustrative. In production, each value should be generated from the validated analysis dataset and the exact statistical specification.

Programming the Table From ODS Output

A common strategy is to capture the ODS tables and then transform them into the organization's standard shell.

ods output
    Quartiles=work.quartiles
    HomTests=work.homtests;

proc lifetest data=adtte
              method=pl;
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

ods output close;

proc print data=work.quartiles;
run;

proc print data=work.homtests;
run;

The exact variable names in the ODS datasets should be inspected in the specific SAS release and analysis configuration rather than assumed.

Inspecting ODS Dataset Structures

Before writing downstream code, inspect the captured dataset:

proc contents data=work.quartiles varnum;
run;

proc print data=work.quartiles(obs=20);
run;

This is a simple but important habit. ODS output structures can contain labels, numeric codes, character representations, and variables whose presence depends on the requested options.

Validation of the Kaplan–Meier Estimate

A good QC strategy does more than compare the final PDF visually.

At minimum, validate:

  • Analysis population counts
  • Event counts
  • Censoring counts
  • Minimum and maximum analysis time
  • Survival estimates at key time points
  • Median survival
  • Confidence intervals
  • Log-rank statistic and p-value
  • Numbers at risk
  • Final plotted treatment labels

Independent Validation Example

For a simple endpoint, an independent validation program might recreate event and censoring counts from the subject-level dataset:

proc freq data=adtte;
    tables trt01p*cnsr / missing;
run;

proc means data=adtte n min median max;
    class trt01p;
    var aval;
run;

The goal is not necessarily to reproduce every internal computational detail in a second program. It is to create an independent check that would detect a major programming error.

Common Mistake: Treating Censoring as an Event

This is perhaps the most dangerous basic error.

If the data use 1 = event and 0 = censoring, then:

time aval*event(0);

is appropriate.

If you accidentally write:

time aval*event(1);

you have told PROC LIFETEST that the 1s are censored. The resulting survival analysis will be fundamentally different.

QC check: Always reconcile the number of events reported by PROC LIFETEST with an independent event count from the analysis dataset.

Common Mistake: Using the Wrong Analysis Population

A Kaplan–Meier curve can be statistically correct for the wrong population.

For example, using all randomized subjects for a time-to-event endpoint that is specified for a treated population, or using an incorrect subgroup flag, can produce a polished but invalid TLF.

Common Mistake: Wrong Time Origin

If one program calculates PFS from randomization while another calculates it from first dose, the curves can differ even when the event and censoring dates are identical.

The start date must therefore be part of the endpoint specification, not an implementation detail left to the programmer.

Common Mistake: Censoring at the Wrong Date

For a patient without an event, the censoring date might depend on:

  • Last adequate assessment
  • Last known alive date
  • Last tumor assessment
  • Study cutoff date
  • Protocol-specific follow-up rules

These are not interchangeable. The correct rule is endpoint-specific.

Common Mistake: Reporting a Median When It Is Not Reached

If the survival curve does not cross 50%, reporting a numerical median from an inappropriate extrapolation would misrepresent the observed data.

Report not reached/not estimable according to the study's controlled terminology and shell conventions.

Common Mistake: Ignoring the At-Risk Table

A survival curve can look impressive at 36 months even if only a handful of patients remain at risk.

Always examine the denominator before drawing conclusions from the far right tail.

Common Mistake: Comparing Curves by Eye

Visual separation is useful descriptive information, but formal treatment comparisons should use the prespecified statistical test or model.

Common Mistake: Assuming Proportional Hazards

The Kaplan–Meier procedure itself does not establish the proportional-hazards assumption.

If a Cox model is planned, evaluate whether the model assumptions are reasonable and use appropriate sensitivity or alternative summaries when necessary.

When PROC LIFETEST Is the Right Tool

  • Kaplan–Meier survival estimation
  • Nonparametric survival summaries
  • Median survival estimation
  • Survival curves by treatment or subgroup
  • Log-rank comparisons
  • Risk tables and survival graphics
  • Competing-risk cumulative-incidence analyses supported by the procedure
  • RMST analyses supported by the procedure

When PROC LIFETEST Is Not Enough

  • Multivariable Cox proportional hazards modeling
  • Adjusted hazard ratios
  • Time-dependent covariates in a Cox model
  • Complex recurrent-event models
  • Frailty/random-effects survival models
  • Specialized multi-state models

Those analyses may require PROC PHREG or other procedures and specialized methods.

Survival Analysis in the Clinical-TLF Ecosystem

A survival-analysis programming workflow often connects several layers:

A
ADaM derivation: create the validated time-to-event analysis records.
B
PROC LIFETEST: estimate Kaplan–Meier curves, medians, confidence intervals, and nonparametric comparisons.
C
PROC PHREG: produce the prespecified Cox-model results when applicable.
D
TLF formatting: transform statistical output into controlled tables and figures.
E
QC: reconcile counts, estimates, labels, shells, and source data.

A Practical End-to-End Example

Assume a two-arm randomized oncology trial with overall survival. The ADTTE dataset contains:

USUBJID   TRT01P   PARAMCD   AVAL   CNSR
1001      Drug A   OS        420    0
1002      Drug A   OS        395    1
1003      Drug A   OS        520    1
1004      Drug B   OS        310    0
1005      Drug B   OS        280    0
1006      Drug B   OS        610    1

If CNSR=0 means death/event and CNSR=1 means censored, then the core analysis is:

ods graphics on;

ods output
    ProductLimitEstimates = work.os_km
    Quartiles              = work.os_quartiles
    HomTests               = work.os_logrank;

proc lifetest data=adam.adtte
              method=pl
              plots=survival(cl atrisk=0 to 36 by 6);
    where paramcd = "OS";
    time aval*cnsr(1);
    strata trt01p / test=logrank;
run;

ods output close;

ods graphics off;

This single procedure call can provide the foundation for both the survival figure and the numerical survival summary, provided the endpoint dataset and analysis specification are correct.

Reading the Output Conceptually

OutputQuestion answered
Survival curveWhat is the estimated probability of remaining event-free over time?
At-risk numbersHow many subjects remain in the risk set at selected times?
MedianWhen does estimated survival reach 50%, if it does?
Confidence intervalHow uncertain is the estimate?
Log-rank testIs there evidence that the survival distributions differ?
ProductLimitEstimatesWhat are the event-time-specific KM estimates?

Survival Probability at a Fixed Time

Often the clinical question is not the median but survival at a prespecified time, such as 12 or 24 months.

For example:

$$ \widehat S(24)=0.68 $$

would be interpreted as an estimated 68% probability of remaining event-free beyond 24 months under the defined endpoint and analysis population.

Fixed-time estimates can be particularly useful when the median is not reached.

Why Fixed-Time Survival Can Be More Informative Than the Median

Suppose the median OS is not reached in either arm, but:

TimeDrug ADrug B
12 months86%78%
24 months69%55%
36 months57%42%

The median alone would not communicate these observed differences.

If fixed-time survival probabilities are clinically important, prespecify them rather than selecting time points after seeing the curves.

Interpreting Long Tails

Kaplan–Meier curves can extend long after most events have occurred.

A visually smooth tail does not mean the estimate is precise. The number at risk may be very small.

This is one reason the risk table is not decorative: it provides the denominator context needed to interpret the curve.

Survival Curves and Clinical Interpretation

A survival curve describes the observed statistical pattern. Clinical interpretation requires context from:

  • Event definition
  • Follow-up duration
  • Baseline prognosis
  • Treatment exposure
  • Subsequent therapy
  • Safety and tolerability
  • Other efficacy endpoints

A Kaplan–Meier curve is therefore one component of an efficacy analysis, not the entire clinical conclusion.

Clinical Study Report Language

A typical figure footnote might read:

Example: Kaplan–Meier estimates of overall survival by treatment group. Tick marks indicate censored observations. Numbers at risk are shown at selected time points. Overall survival is defined as time from randomization to death from any cause; patients without an event at the analysis cutoff are censored according to the prespecified censoring rules.

The actual wording must match the study's endpoint definition and SAP.

Production Checklist

1
Confirm the endpoint definition.
2
Confirm the time origin.
3
Confirm the event date and event definition.
4
Confirm the censoring rules.
5
Verify event/censor coding.
6
Verify the analysis population.
7
Run PROC LIFETEST with the prespecified method.
8
Capture required ODS output.
9
Reconcile event and censor counts.
10
Validate medians, confidence intervals, and p-values.
11
Validate the at-risk table.
12
Review the final figure against the TLF shell.

Quick Reference: Core Syntax

TaskCore syntax
Overall KMproc lifetest; time aval*cnsr(1); run;
By treatmentstrata trt01p;
Log-rankstrata trt01p / test=logrank;
Risk tableplots=survival(atrisk=...)
Confidence limitsplots=survival(cl)
Product-limit methodmethod=pl
Save survival estimatesoutsurv=km_curve
Capture KM estimatesods output ProductLimitEstimates=...
Capture quartilesods output Quartiles=...
Capture group testods output HomTests=...

The Most Important Concept

PROC LIFETEST is not merely a command that draws a Kaplan–Meier curve. It is a statistical procedure sitting downstream of the endpoint derivation.

If the time origin, event date, censoring rule, or analysis population is wrong, the procedure can produce a perfectly formatted but clinically incorrect result.

The strongest clinical programmers therefore treat PROC LIFETEST as the final statistical engine in a controlled chain:

$$ \text{Protocol/SAP} \rightarrow \text{Endpoint Derivation} \rightarrow \text{ADTTE} \rightarrow \text{PROC LIFETEST} \rightarrow \text{ODS Output} \rightarrow \text{TLF} \rightarrow \text{QC} $$
Bottom line: PROC LIFETEST is one of the core SAS procedures for clinical-trial survival analysis. Master the TIME statement first, especially the event/censoring coding. Then learn STRATA and the log-rank test, median and quartile output, PLOTS= options, ODS OUTPUT, and OUTSURV=. Finally, place the procedure inside a validated ADTTE-to-TLF workflow. That is the difference between knowing the syntax and being able to produce a defensible clinical-trial survival analysis.

References

SAS Institute Inc. The LIFETEST Procedure. SAS/STAT User's Guide. See the current SAS documentation for syntax, ODS tables, survival plots, confidence limits, competing risks, RMST, and version-specific options.

Klein, J.P. and Moeschberger, M.L. Survival Analysis: Techniques for Censored and Truncated Data. Springer.

Kaplan, E.L. and Meier, P. (1958). Nonparametric estimation from incomplete observations. Journal of the American Statistical Association, 53, 457–481.

SAS documentation: PROC LIFETEST User's Guide.