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).
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:
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:
| Concept | Example SAS variable | Meaning |
|---|---|---|
| Subject | USUBJID | Unique patient identifier |
| Time | AVAL | Observed follow-up time |
| Event indicator | EVENT | 1 = event, 0 = censored |
| Treatment | TRT01P | Treatment 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.
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:
| EVENT | Meaning |
|---|---|
| 1 | Death / event occurred |
| 0 | Censored |
Then:
time aval*event(0);
is appropriate.
If instead the dataset uses:
| EVENT | Meaning |
|---|---|
| 0 | Death / event occurred |
| 1 | Censored |
then the censoring value in the TIME statement must be changed accordingly.
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.
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:
| Patient | Time | Status |
|---|---|---|
| 001 | 3 | Event |
| 002 | 5 | Censored |
| 003 | 7 | Event |
| 004 | 9 | Event |
| 005 | 12 | Censored |
At Month 3, five patients are initially at risk and one event occurs:
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:
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.
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.
| Group | 0 | 6 | 12 | 18 | 24 | 30 | 36 |
|---|
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 feature | Interpretation |
|---|---|
| Vertical drop | One or more events occurred at that time. |
| Flat segment | No events occurred during that interval. |
| Censoring tick | A subject left the risk set without experiencing the event. |
| Higher curve | Higher estimated probability of remaining event-free at that time. |
| Crossing curves | The 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.
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
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.
Median Survival
The median survival is the time \(t\) at which the survival function reaches approximately 0.50:
If the Kaplan–Meier curve never falls to 50%, the median survival is not estimable within the observed follow-up.
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.
| Situation | Appropriate reporting |
|---|---|
| Curve crosses 0.50 | Report estimated median and confidence interval as specified. |
| Curve remains above 0.50 | Report median as not reached / not estimable according to the reporting convention. |
| Very sparse tail | Interpret 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:
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;
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.
| Approach | Typical purpose |
|---|---|
| STRATA | Estimate and compare survival curves across groups within one analysis. |
| BY | Run 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.
PROC LIFETEST Versus PROC PHREG
| Question | PROC LIFETEST | PROC PHREG |
|---|---|---|
| Kaplan–Meier curve | Yes | No, not as its primary purpose |
| Nonparametric survival estimation | Yes | No |
| Median survival | Yes | Not the primary use |
| Log-rank comparison | Yes | Not the primary use |
| Cox proportional hazards model | No | Yes |
| Hazard ratios | No | Yes |
| Covariate-adjusted hazard analysis | Limited | Yes |
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.
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:
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.
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.
| Scale | Typical use |
|---|---|
| Days | Precise derivation and analysis dataset |
| Weeks | Some disease areas and shorter follow-up |
| Months | Readable clinical display and summary |
| Years | Long-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
| Specification | Example |
|---|---|
| Endpoint | Overall survival |
| Population | Intent-to-treat population |
| Time origin | Date of randomization |
| Event | Death from any cause |
| Censoring | Per SAP-defined OS censoring rules |
| Estimator | Kaplan–Meier |
| Comparison | Log-rank test |
| Confidence limits | 95% pointwise limits, if specified |
| Risk table | 0, 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
| Request | Purpose |
|---|---|
PLOTS=SURVIVAL | Kaplan–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.
| Quantity | What it describes |
|---|---|
| Pointwise survival CI | Uncertainty around \(S(t)\) at a particular time. |
| Median CI | Uncertainty around the time at which survival reaches 50%. |
| Confidence band | Simultaneous 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.
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
Building a Survival Summary Table
A typical survival table may contain:
| Statistic | Drug A | Drug B |
|---|---|---|
| N | 120 | 118 |
| Number of events | 62 | 71 |
| Median survival | 18.4 months | 14.2 months |
| 95% CI | 15.8–22.7 | 11.9–17.1 |
| Log-rank p-value | 0.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.
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 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
| Output | Question answered |
|---|---|
| Survival curve | What is the estimated probability of remaining event-free over time? |
| At-risk numbers | How many subjects remain in the risk set at selected times? |
| Median | When does estimated survival reach 50%, if it does? |
| Confidence interval | How uncertain is the estimate? |
| Log-rank test | Is there evidence that the survival distributions differ? |
| ProductLimitEstimates | What 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:
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:
| Time | Drug A | Drug B |
|---|---|---|
| 12 months | 86% | 78% |
| 24 months | 69% | 55% |
| 36 months | 57% | 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:
The actual wording must match the study's endpoint definition and SAP.
Production Checklist
Quick Reference: Core Syntax
| Task | Core syntax |
|---|---|
| Overall KM | proc lifetest; time aval*cnsr(1); run; |
| By treatment | strata trt01p; |
| Log-rank | strata trt01p / test=logrank; |
| Risk table | plots=survival(atrisk=...) |
| Confidence limits | plots=survival(cl) |
| Product-limit method | method=pl |
| Save survival estimates | outsurv=km_curve |
| Capture KM estimates | ods output ProductLimitEstimates=... |
| Capture quartiles | ods output Quartiles=... |
| Capture group test | ods 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:
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.