Skip to main content
v2026.11,858 entries · CC-BY 4.0

Survival Analysis in R: survival Package Guide

Run Kaplan-Meier, log-rank and Cox analyses in R with the survival package, read the output, and avoid event-coding and ties mistakes.

Written and maintained by CASRAI Editorial Board

Last updated

Survival analysis in R is done with the survival package: Surv() builds the time-to-event outcome, survfit() estimates Kaplan-Meier curves, survdiff() compares curves with the log-rank test, coxph() fits a Cox model, and cox.zph() tests its proportional-hazards assumption. This guide walks through that sequence with commands checked against the package’s CRAN reference manual (checked 2026-10-29), then covers the traps that most often produce wrong answers rather than error messages: event coding, tied event times, and an undefined median.

What survival analysis in R is used for in research

Survival (time-to-event) methods model how long it takes for an event to happen when some participants are still event-free at the end of follow-up. The CRAN page describes the package as “core survival analysis routines, including Surv objects, Kaplan-Meier and Aalen-Johansen (multi-state) curves, Cox models, and parametric accelerated failure time models.” Typical research uses are time to death, relapse, device failure or publication, in clinical trials, cohort studies and registry work.

This page is the software companion to the conceptual guides. For what the estimators mean, read survival analysis: Kaplan-Meier, Cox and parametric models; for the model’s assumptions, the Cox proportional hazards model explained.

Install or access the survival package (CRAN)

The official source is the CRAN package page, cran.r-project.org/web/packages/survival. On 2026-10-29 it listed:

  • version 3.8-12, published 2026-09-09, maintained by Terry M. Therneau (Thomas Lumley did the original port from S to R);
  • a dependency of R (>= 4.1.0);
  • package priority “recommended”, licence LGPL-2 | LGPL-2.1 | LGPL-3, project home github.com/therneau/survival;
  • vignettes including “The survival package”, “Adjusted Survival Curves”, “Multi-state models and competing risks”, “Concordance”, “Splines, plots, and interactions”, “Roundoff error and tied times” and “Population contrasts”.
install.packages("survival")   # from CRAN, if it is not already installed
library(survival)
packageVersion("survival")      # confirm which version you are running

For publication-style plots, the survminer package provides ggsurvplot(). Its author’s documentation gives install.packages("survminer") for the CRAN release and devtools::install_github("kassambara/survminer", build_vignettes = FALSE) for the development version.

Step-by-step: Surv, survfit, survdiff, coxph and cox.zph

The steps below use the lung data set that ships with the package, with the columns time, status and sex used in the survminer documentation and age used in the reference manual’s model examples. Check ?lung in your own session for the codebook before interpreting any coefficient.

  1. Code the event correctly. Surv() accepts status as 0/1, TRUE/FALSE, or 1/2 with 2 meaning death. The manual notes that many older data sets, “e.g., the lung data set”, still use the 1/2 convention. Recode once so the meaning is explicit:
    library(survival)
    lung$event <- as.numeric(lung$status == 2)   # 1 = died, 0 = censored
  2. Build the outcome. The full signature is Surv(time, time2, event, type = c('right','left','interval','counting','interval2'), origin = 0). For ordinary right-censored follow-up the two-argument form is enough:
    Surv(lung$time, lung$event)
  3. Estimate Kaplan-Meier curves. The Task View for survival analysis states that survfit “computes the Kaplan-Meier estimator for truncated and/or censored data.”
    fit <- survfit(Surv(time, event) ~ sex, data = lung)
    print(fit)
    summary(fit, times = c(180, 360))

    summary() with times returns the curve at the time points you choose; for print(), scale rescales the printed times, for example days to years.

  4. Plot it. Base R: plot(fit). With survminer: ggsurvplot(fit, data = lung), which can add the number-at-risk table.
  5. Compare the curves. survdiff(formula, data, subset, na.action, rho = 0, timefix = TRUE) runs the G-rho family of tests; rho = 0 is the log-rank test.
    survdiff(Surv(time, event) ~ sex, data = lung)
  6. Fit a Cox model. coxph() takes the same formula style, with covariates on the right:
    cox <- coxph(Surv(time, event) ~ sex + age, data = lung)
    summary(cox)
  7. Test proportional hazards. cox.zph(fit, transform = "km", terms = TRUE, singledf = FALSE, global = TRUE):
    zph <- cox.zph(cox)
    zph
    plot(zph)

Output and how to read it

print(survfit): events and median

Printing a survfit object gives, for each curve, the number of observations, the number of events, the restricted mean survival with its standard error, and the median survival with confidence limits. The manual defines the median by drawing a horizontal line at 0.5 across the curve and its confidence band: where the line meets the curve is the median, and where it meets the lower and upper bands gives the interval. If the curve never falls to 0.5 the median cannot be estimated. That reflects the data (heavy censoring or short follow-up), not a coding error. The restricted mean, which print() can also report, is an alternative summary; the manual notes it is undefined when the last observation is not a death unless an upper limit is chosen through the rmean option.

survdiff: observed, expected and p-value

The returned object holds the number of subjects per group (n), weighted observed events (obs), weighted expected events (exp), the chi-square statistic and its p-value. A group whose observed events exceed its expected events is doing worse than the pooled curve implies. For the test’s variants and weighting choices, see the log-rank test and its variants.

coxph: coefficients and hazard ratios

In summary(cox) the coef column is a log hazard ratio and exp(coef) is the hazard ratio for a one-unit increase in that covariate (or for the non-reference level of a factor). The Cox guide linked above explains how to interpret a hazard ratio.

cox.zph: the proportional-hazards check

The table component of a cox.zph result holds a formal score test for zero slope of the time-dependent coefficient, per term and, with global = TRUE, for the model as a whole. The plot estimates the time-dependent coefficient, which should be a horizontal line if proportional hazards holds. A small p-value or a visibly sloping curve is evidence against proportional hazards for that term.

One cross-check worth knowing

The survdiff documentation states that the ordinary log-rank test is equivalent to the score test from a Cox model using the Breslow approximation for ties, and recommends the Cox model form for more complex models, for example time-dependent covariates. Because coxph defaults to the Efron approximation, the two p-values can differ slightly unless you fit with ties = "breslow".

Troubleshooting survival analysis in R

Results look inverted or implausible

Check the event coding first. Passing a 1/2 variable is valid only if 2 means the event; the manual lists 0/1, TRUE/FALSE and 1/2 (2 = death) as accepted codings. Tabulate status against known deaths before fitting anything.

The median is missing or not estimable

The survival curve did not reach 0.5 within follow-up. Report survival at fixed times with summary(fit, times = ...), or use the restricted mean (set an upper limit with the rmean option).

Tied event times

coxph accepts ties = c("efron", "breslow", "exact") and uses Efron by default, which the manual describes as more accurate with tied death times and as efficient computationally. The “exact” partial likelihood is equivalent to a conditional logistic model and is appropriate when times take a small set of discrete values. If there are no tied death times all methods agree. The package vignette “Roundoff error and tied times” covers the floating-point side, and survdiff has a timefix argument for the same issue.

A Cox model that will not converge

Iteration limits and convergence tolerances are set through coxph.control(), passed as control = in the coxph call.

Predicted curves inside a function fail

The manual notes that if fit <- coxph(...); survfit(fit) is used inside another function, the coxph call needs model = TRUE.

Non-proportional hazards

When cox.zph flags a covariate, the single hazard ratio from coxph should be read with that in mind. The package also fits parametric accelerated failure time models.

Alternatives and companion packages

Each row below is taken from the CRAN Task View for survival analysis (cran.r-project.org/web/views/Survival.html, checked 2026-10-29) or the package’s own CRAN page.

Package What it adds Source statement
survival Surv objects, Kaplan-Meier and Aalen-Johansen curves, Cox models, parametric AFT models CRAN package page
survminer ggsurvplot() for survival curves with a number-at-risk table; visual checks of Cox assumptions Task View
flexsurv Parametric time-to-event models with any parametric distribution, where any parameter can depend on covariates Task View
cmprsk Cumulative incidence functions for competing risks, compared across samples; the Fine and Gray subdistribution hazard model Task View

For competing events, see competing risks, cumulative incidence and the Fine-Gray model. For R more generally, see what R is used for in research.

FAQ

Which R package do I need for survival analysis?

The survival package covers the standard workflow: Kaplan-Meier curves, log-rank tests, Cox models and parametric AFT models. Add survminer for number-at-risk plots, flexsurv for flexible parametric models and cmprsk for competing risks.

Does status = 2 mean death in the lung data?

Yes, under the convention the manual describes: Surv accepts 1/2 coding where 2 is death, and the manual names the lung data as one that still uses it. Recode to 0/1 so the meaning is explicit.

Is the log-rank test the same as a Cox model?

The log-rank test is equivalent to the score test from a Cox model with Breslow ties, per the survdiff documentation. The Cox model additionally gives an effect size (hazard ratio) and handles several covariates at once.

How do I get a Kaplan-Meier plot with a number-at-risk table?

Fit with survfit() and pass the object to ggsurvplot() from survminer. To read the plot, see how to read a Kaplan-Meier curve.

Sources

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about Survival Analysis in R: survival Package Guide

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Ask CASRAI · Regulatory Radar

Research-admin question? Get an answer that links its sources.

An AI assistant specialized in research administration. Every answer links its sources to check before you act. 2 questions free, no account. $29/month after.

  • Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.
  • Every answer numbers its sources and links each one, so you can check the source yourself.