Competing Risk Cumulative Incidence

Authors

[Editor] Shixiang Wang;

[Contributors] ZCode (GLM) โ€” AI-generated, independently AI-reviewed.

Modified

2026-10-31

๐Ÿค– AI Skill โ€” Download the Bizard unified skill for your AI assistant โฌ‡๏ธ Download Skill ZIP
๐Ÿ”Œ MCP Server โ€” Let AI agents (Claude Code, Cursor, โ€ฆ) query Bizard live: claude mcp add bizard -- npx @openbiox/bizard-mcp โ€” or the free hosted instance (no install, faster from mainland China): claude mcp add --transport http bizard http://biotree.top:38123/bizard-mcp/mcp ๐Ÿ“– MCP Docs
๐Ÿ“– Cite Bizard โ€” if Bizard helps your research, please cite: Li, K., Zheng, H., Huang, K., et al. (2026). Bizard: A Community-Driven Platform for Accelerating and Enhancing Biomedical Data Visualization. iMetaMed, e70038. ๐Ÿ”— DOI / BibTeX

When patients can fail from more than one cause โ€” progression or death, relapse or transplant mortality โ€” standard Kaplanโ€“Meier analysis is wrong for the event of interest: censoring patients at their competing event pretends they were still at risk of progressing, and the naive 1 โˆ’ KM estimator overestimates the incidence, dramatically so when the competing event is common [1]. The correct descriptive tool is the cumulative incidence function (CIF, Aalenโ€“Johansen estimator), which treats competing events as competing: a subject who dies can no longer progress, and the CIFs of all causes sum to 1.

Group comparison uses Grayโ€™s test (a K-sample test on the CIFs), and regression uses the Fineโ€“Gray subdistribution hazard model [2]. This tutorial walks through all three with tidycmprsk [3] and ggsurvfit [4], on the classic mgus2 cohort [5]: 1,384 patients with monoclonal gammopathy of undetermined significance, where progression to plasma cell malignancy competes with death.

This tutorial covers four workflows:

  1. CIFs of both competing outcomes with confidence intervals and risk table;
  2. CIFs by a covariate with Grayโ€™s test;
  3. Fineโ€“Gray subdistribution hazard regression;
  4. Why 1 โˆ’ KM overestimates incidence โ€” the comparison every reviewer asks for.

Example

CompetingRiskPlot DEMO

Setup

  • System Requirements: Cross-platform (Linux/MacOS/Windows)

  • Programming language: R

  • Dependent packages: survival; tidycmprsk; ggsurvfit; ggplot2; dplyr

# Installing necessary packages
if (!requireNamespace("tidycmprsk", quietly = TRUE)) {
  install.packages("tidycmprsk")
}
if (!requireNamespace("ggsurvfit", quietly = TRUE)) {
  install.packages("ggsurvfit")
}

# Load packages
library(survival)
library(tidycmprsk)
library(ggsurvfit)
library(ggplot2)
library(dplyr)
sessioninfo::session_info("attached")
โ”€ Session info โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 setting  value
 version  R version 4.6.2 (2026-10-29)
 os       Ubuntu 24.04.5 LTS
 system   x86_64, linux-gnu
 ui       X11
 language (EN)
 collate  C.UTF-8
 ctype    C.UTF-8
 tz       UTC
 date     2026-10-31
 pandoc   3.1.3 @ /usr/bin/ (via rmarkdown)
 quarto   1.10.20 @ /usr/local/bin/quarto

โ”€ Packages โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 ! package    * version    date (UTC) lib source
 P dplyr      * 1.2.1      2026-04-03 [?] RSPM
 P ggplot2    * 4.0.3.9000 2026-10-30 [?] Github (tidyverse/ggplot2@b638d65)
   ggsurvfit  * 1.2.1      2026-07-24 [1] RSPM
 P survival   * 3.8-6      2026-01-16 [?] RSPM
   tidycmprsk * 1.1.2      2026-04-09 [1] RSPM

 [1] /home/runner/.cache/R/renv/library/Bizard-5140bdc6/linux-ubuntu-noble/R-4.6/x86_64-pc-linux-gnu
 [2] /home/runner/work/_temp/Library
 [3] /opt/R/4.6.2/lib/R/library

 * โ”€โ”€ Packages attached to the search path.
 P โ”€โ”€ Loaded and on-disk path mismatch.

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

Data Preparation

mgus2 ships with the survival package [5]: 1,384 MGUS patients followed from diagnosis for progression to a plasma cell malignancy (PCM) or death. Follow-up time is the earlier of progression (ptime) and last contact (futime); the competing-risks event code is 0 = censored, 1 = PCM (the event of interest), 2 = death (the competing event).

data(mgus2)

mgus2$etime <- with(mgus2, ifelse(pstat == 1, ptime, futime))
mgus2$event <- with(mgus2, ifelse(pstat == 1, 1, ifelse(death == 1, 2, 0)))
mgus2$event_f <- factor(mgus2$event, levels = 0:2,
                        labels = c("censored", "pcm", "death"))

cat("Patients:", nrow(mgus2),
    "| progression:", sum(mgus2$event == 1),
    "| death (competing):", sum(mgus2$event == 2), "\n")
Patients: 1384 | progression: 115 | death (competing): 860 

Visualization

1. Cumulative Incidence of Both Outcomes

ci1 <- cuminc(Surv(etime, event_f) ~ 1, data = mgus2)

ggcuminc(ci1, outcome = c("pcm", "death")) +
  add_confidence_interval() +
  add_risktable(size = 3) +
  scale_color_manual(values = c(pcm = "#B2182B", death = "#2166AC"), name = NULL) +
  scale_fill_manual(values = c(pcm = "#B2182B", death = "#2166AC"), guide = "none") +
  xlab("Months since diagnosis") +
  ylab("Cumulative incidence") +
  theme_bw(base_size = 11)
Figureย 1: Aalen-Johansen cumulative incidence of progression and of death (the competing event), with 95% confidence bands and a risk table; the two CIFs are estimated jointly and sum to the all-cause incidence.

Death dominates: by 20 years roughly 78% have died versus about 16% who have progressed โ€” which is exactly the setting where naive Kaplanโ€“Meier analysis of progression goes wrong (Section 4).

2. Comparing Groups with Grayโ€™s Test

ci2 <- cuminc(Surv(etime, event_f) ~ sex, data = mgus2)
gt <- glance(ci2)
cat(sprintf("Gray's test, progression: chi-square = %.2f, df = %d, p = %.3f\n",
            gt$statistic_1, gt$df_1, gt$p.value_1))
Gray's test, progression: chi-square = 1.19, df = 1, p = 0.274
cat(sprintf("Gray's test, death:       chi-square = %.2f, df = %d, p = %.3f\n",
            gt$statistic_2, gt$df_2, gt$p.value_2))
Gray's test, death:       chi-square = 11.65, df = 1, p = 0.001
ggcuminc(ci2, outcome = "pcm") +
  add_confidence_interval() +
  scale_color_manual(values = c(F = "#1B9E77", M = "#7570B3"), name = "Sex") +
  scale_fill_manual(values = c(F = "#1B9E77", M = "#7570B3"), guide = "none") +
  xlab("Months since diagnosis") +
  ylab("Cumulative incidence of progression") +
  theme_bw(base_size = 11)
Figureย 2: Cumulative incidence of progression by sex with 95% confidence intervals; the caption reports Grayโ€™s test.

Men progress slightly faster than women, but Grayโ€™s test does not reach significance at the 0.05 level โ€” with the effect quantified properly by the regression below.

3. Fine-Gray Regression

fg <- crr(Surv(etime, event_f) ~ sex + age, data = mgus2, failcode = "pcm")
fgdf <- tidy(fg, exponentiate = TRUE, conf.int = TRUE) |>
  mutate(term_lbl = recode(term, sexM = "Sex: M vs F", age = "Age (per year)"))

ggplot(fgdf, aes(x = estimate, y = term_lbl)) +
  geom_errorbar(aes(xmin = conf.low, xmax = conf.high), orientation = "y",
                width = 0.12, color = "#B2182B") +
  geom_point(size = 3, color = "#B2182B") +
  geom_vline(xintercept = 1, linetype = "dashed", color = "grey40") +
  scale_x_log10() +
  labs(x = "Subdistribution hazard ratio (log scale)", y = NULL,
       title = "Fine-Gray regression: progression to malignancy") +
  theme_bw(base_size = 11)
Figureย 3: Fine-Gray subdistribution hazard ratios for progression (log scale): male sex is non-significant, older age is protective (fewer remaining years in which to progress).

The subdistribution HR answers the clinically relevant question โ€” how the covariate shifts the absolute incidence of progression in the presence of the competing risk. For the etiologic (cause-specific) question, fit survival::coxph instead and say which one you report.

4. Why 1 โˆ’ KM Overestimates: The Comparison Figure

kmfit <- survfit(Surv(etime, event == 1) ~ 1, data = mgus2)  # deaths censored
kmdf <- data.frame(time = kmfit$time, est = 1 - kmfit$surv)
cidf <- tidy(ci1) |>
  filter(outcome == "pcm") |>
  select(time, cif = estimate)
cidf <- rbind(data.frame(time = 0, cif = 0), cidf)

ggplot() +
  geom_step(data = kmdf, aes(time, est, color = "1 โˆ’ KM (naive)"),
            linewidth = 1, direction = "hv") +
  geom_step(data = cidf, aes(time, cif, color = "True CIF (Aalen-Johansen)"),
            linewidth = 1, direction = "hv") +
  geom_hline(yintercept = tail(cidf$cif, 1), linetype = "dotted", color = "grey40") +
  annotate("text", x = 250, y = tail(cidf$cif, 1) + 0.025, size = 3.4, color = "#B2182B",
           label = sprintf("True CIF = %.3f", tail(cidf$cif, 1))) +
  annotate("text", x = 250, y = max(kmdf$est) - 0.03, size = 3.4, color = "#7570B3",
           label = sprintf("1 โˆ’ KM = %.3f", max(kmdf$est))) +
  scale_color_manual(values = c("1 โˆ’ KM (naive)" = "#7570B3",
                                "True CIF (Aalen-Johansen)" = "#B2182B"), name = NULL) +
  coord_cartesian(xlim = c(0, 420), ylim = c(0, 0.65)) +
  labs(x = "Months since diagnosis", y = "Incidence of progression",
       title = "1 โˆ’ KM overestimates incidence when deaths compete") +
  theme_bw(base_size = 11) + theme(legend.position = "top")
Figureย 4: Naive 1 - KM (deaths censored) reaches 0.62 while the true cumulative incidence of progression is 0.16: treating deaths as censoring pretends those patients were still at risk.

The naive curve rises almost four times above the truth by 20 years. Whenever a competing event is more than a rarity, report Aalenโ€“Johansen CIFs โ€” a Kaplanโ€“Meier curve of the event of interest alone is a common and consequential reviewer catch.

TipPractice tips
  • Encode outcomes as a factor with the event of interest first, competing event second, censoring last; tidycmprsk::cuminc() requires the two-level Surv(time, factor) syntax.
  • Report CIFs with confidence intervals and the risk table โ€” readers judge the follow-up, not just the curve.
  • Grayโ€™s test compares incidence; the log-rank test on cause-specific survival answers a different question. Pick per the estimand.
  • In Fineโ€“Gray models, covariate effects on the subdistribution hazard can have counterintuitive signs (older age appears โ€œprotectiveโ€ against progression because death removes patients first) โ€” interpret against the CIF, not the hazard.

Application

Competing-risk curves are standard in transplantation (relapse vs non-relapse mortality), geriatric oncology (progression vs other-cause death), and device/cardiology studies (arrhythmia vs all-cause death). The panel below mirrors a typical publication layout: (A) CIFs of both outcomes with risk table and (B) the naive 1 โˆ’ KM versus true CIF comparison.

CompetingRiskPlot Application

Reference

[1] Austin PC, Fine JP. Practical recommendations for reporting Fine-Gray model analyses for competing risk data. Stat Med. 2017;36(4):5391-5400. doi:10.1002/sim.7501

[2] Fine JP, Gray RJ. A proportional hazards model for the subdistribution of a competing risk. J Am Stat Assoc. 1999;94(446):496-509. doi:10.1080/01621459.1999.10474144

[3] Sjoberg DD, Fei T. tidycmprsk: competing risks estimation. R package version 1.1.2. 2026. doi:10.32614/CRAN.package.tidycmprsk

[4] Sjoberg DD, Whiting K, Curry M, Lavery JA, Larmarange J. Reproducible summary tables with the gtsummary package. R J. 2021;13:570-580. doi:10.32614/RJ-2021-053 (ggsurvfit builds on gtsummary)

[5] Kyle RA, Therneau TM, Rajkumar SV, et al.ย A long-term study of prognosis in monoclonal gammopathy of undetermined significance. N Engl J Med. 2002;346(8):564-569. doi:10.1056/NEJMoa011332