Overall, Cause Specific, and Competing Survival - Comprehensive Guide
ClinicoPath Development Team
2026-03-22
Source:vignettes/jsurvival-competingsurvival-comprehensive.Rmd
jsurvival-competingsurvival-comprehensive.RmdNote:
competingsurvival()is designed primarily for the jamovi GUI. The R syntax shown here is for reference and advanced scripting.
Competing Risks Survival Analysis
Overview
In clinical research, patients are often at risk of dying from multiple causes. Standard Kaplan-Meier analysis treats competing events (e.g., death from other causes) as censored observations, which overestimates the actual probability of the event of interest. Competing risks methods address this bias.
Key concepts:
- Kaplan-Meier / Overall Survival: All deaths are events. Simple and familiar, but does not distinguish cause.
- Cause-Specific Survival: Only deaths from the disease of interest are events; competing deaths are censored. Estimates the cause-specific hazard but can overestimate cumulative incidence.
- Cumulative Incidence Function (CIF): The proper probability of experiencing the event of interest in the presence of competing risks. Always <= 1 minus KM estimate.
- Gray’s Test: The competing-risks analog of the log-rank test. Compares CIF curves between groups.
- Fine-Gray Model: Subdistribution hazard regression. Unlike cause-specific Cox, it directly models the CIF, making hazard ratios interpretable in terms of cumulative incidence.
Datasets
This vignette uses two bundled datasets:
| Dataset | N | Outcome Levels | Key Grouping Variables |
|---|---|---|---|
competing_survival_data |
300 | Dead_of_Disease (115), Dead_of_Other (41), Alive_w_Disease (57), Alive_wo_Disease (87) | Treatment (Experimental_Therapy / Standard_Care), Tumor_Stage (I-IV), Sex |
survival_competing |
180 | Dead of Disease (53), Dead of Other (37), Alive w Disease (35), Alive w/o Disease (55) | treatment (Experimental / Standard), stage (I-IV), molecular_subtype (Type A/B/C) |
data("competing_survival_data")
data("survival_competing")
cat("--- competing_survival_data ---\n")
#> --- competing_survival_data ---
cat("Dimensions:", nrow(competing_survival_data), "x", ncol(competing_survival_data), "\n")
#> Dimensions: 300 x 10
cat("Outcome distribution:\n")
#> Outcome distribution:
print(table(competing_survival_data$Outcome))
#>
#> Dead_of_Disease Dead_of_Other Alive_w_Disease Alive_wo_Disease
#> 115 41 57 87
cat("\n--- survival_competing ---\n")
#>
#> --- survival_competing ---
cat("Dimensions:", nrow(survival_competing), "x", ncol(survival_competing), "\n")
#> Dimensions: 180 x 8
cat("Outcome distribution:\n")
#> Outcome distribution:
print(table(survival_competing$outcome))
#>
#> Alive w/o Disease Alive w Disease Dead of Disease Dead of Other
#> 55 35 53 371. Overall Survival
Overall survival treats all deaths (disease + other causes) as events. Alive patients are censored. This is the broadest survival measure.
result_os <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "overall",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease"
)With 156 total deaths out of 300 patients, this gives a straightforward hazard ratio for Treatment comparing all-cause mortality.
Overall Survival Without a Group Variable
When no explanatory variable is provided, the function reports median survival for the entire cohort.
result_os_nogroup <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
analysistype = "overall",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease"
)2. Cause-Specific Survival
Cause-specific survival focuses on disease-related deaths only. Deaths from other causes are treated as censored. This estimates the cause-specific hazard but can overestimate the probability of disease death when competing risks are substantial.
result_css <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "cause",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease"
)Only 115 disease deaths are counted as events here. The 41 deaths from other causes are censored, which means cause-specific survival is always >= overall survival.
3. Competing Risks (CIF)
The cumulative incidence function properly accounts for competing events. Unlike 1-KM, CIF never overestimates the probability of disease death.
result_cr <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease"
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:The cuminc table shows the cumulative incidence of
disease death and competing death at the default timepoints (12, 24, 36,
60 months). The comprisksPlot displays the CIF curves.
Competing Risks with the Second Dataset
The survival_competing dataset uses different naming
conventions for outcome levels, demonstrating that the function handles
various label formats.
result_cr2 <- competingsurvival(
data = survival_competing,
overalltime = "elapsedtime",
outcome = "outcome",
explanatory = "treatment",
analysistype = "compete",
dod = "Dead of Disease",
dooc = "Dead of Other",
awd = "Alive w Disease",
awod = "Alive w/o Disease"
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:4. Gray’s Test
Gray’s test compares cumulative incidence functions between groups. It is the competing-risks analog of the log-rank test. Unlike the log-rank test, it tests equality of the subdistribution hazard (i.e., the CIF) rather than the cause-specific hazard.
result_gray <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
graystest = TRUE
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:The summary output includes the Gray’s test chi-squared statistic, degrees of freedom, and p-value for each event type.
Gray’s Test with a Multi-Level Group Variable
Using Tumor_Stage (4 levels) to test whether CIF differs across stages:
result_gray_stage <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Tumor_Stage",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
graystest = TRUE
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:5. Fine-Gray Subdistribution Hazard
The Fine-Gray model estimates the subdistribution hazard ratio (SHR). Unlike cause-specific Cox regression, the SHR directly relates to the CIF: a higher SHR means a higher cumulative incidence of the event over time.
result_fg <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
subdistribution = TRUE
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:The fineGrayTable shows the coefficient, hazard ratio,
confidence interval, standard error, z-statistic, and p-value. The
survivalTable also gains a row for “Subdistribution HR
(Fine-Gray)” alongside the standard competing risks result.
Fine-Gray with the Second Dataset
result_fg2 <- competingsurvival(
data = survival_competing,
overalltime = "elapsedtime",
outcome = "outcome",
explanatory = "treatment",
analysistype = "compete",
dod = "Dead of Disease",
dooc = "Dead of Other",
awd = "Alive w Disease",
awod = "Alive w/o Disease",
subdistribution = TRUE
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:6. Stacked CIF Plot
The stacked probability plot shows how the total probability is partitioned at each time point into three components: CIF for disease death, CIF for competing death, and survival probability. They must sum to 100%.
result_stacked <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
showStackedPlot = TRUE,
cifColors = "colorblind"
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:At time 0, survival is 100% and both CIFs are 0%. As time progresses, survival decreases while the cumulative incidence of disease death and competing death increase, always summing to 100%.
7. KM vs CIF Comparison
This plot directly demonstrates why competing risks methods are necessary. The naive 1-KM estimate (which treats competing deaths as censored) overestimates the cumulative incidence of disease death compared to the proper CIF.
result_kmcif <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
showKMvsCIF = TRUE
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:The dashed line (1-KM) always lies above the solid line (CIF). The gap between them represents the bias introduced by ignoring competing events. This difference is clinically meaningful in older populations or when competing causes of death are frequent.
8. Custom Timepoints and Confidence Level
Custom CIF Timepoints
By default, cumulative incidence is estimated at 12, 24, 36, and 60 months. Custom timepoints can be specified as a comma-separated string.
result_tp <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
timepoints = "6,12,18,24,30,36,48,60"
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:Adjusting Confidence Level
The default confidence level is 0.95 (95%). You can change this to, for example, 0.90 for narrower intervals.
result_cl90 <- competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease",
subdistribution = TRUE,
confidencelevel = 0.90
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:The Fine-Gray table and timepoint confidence intervals will reflect the 90% confidence level.
9. Assumptions and Interpretation
Key Assumptions
Independent censoring: Censoring must be independent of the event process. If patients are censored because they are sicker (or healthier), all estimates will be biased.
Correct event classification: Each patient must be correctly classified. Misclassifying a disease death as death from other causes (or vice versa) directly biases CIF estimates.
Complete case analysis: Observations with missing time, outcome, or grouping variables are excluded. Report the proportion of missing data.
Adequate follow-up: CIF estimates beyond the maximum observed time are unreliable. Late timepoints should be interpreted cautiously.
Fine-Gray model interpretation: The subdistribution HR has a different meaning than the cause-specific HR. It reflects both the direct effect on the event and the indirect effect through competing events. An SHR > 1 means a group has a higher cumulative incidence over time, which is often the most clinically relevant quantity.
Gray’s test: Tests equality of CIF curves, not cause-specific hazards. It is appropriate when the research question concerns cumulative incidence (probability of event), not the instantaneous rate (hazard).
When to Use Which Approach
| Research Question | Method | Analysis Type |
|---|---|---|
| What is the all-cause mortality? | Overall Survival | overall |
| What is the direct effect of treatment on disease death rate? | Cause-Specific Cox | cause |
| What is the probability of dying from disease accounting for other deaths? | CIF / Fine-Gray | compete |
| Do CIF curves differ between groups? | Gray’s Test |
compete + graystest = TRUE
|
| What is the treatment effect on cumulative incidence? | Subdistribution HR |
compete + subdistribution = TRUE
|
10. Edge Cases
Minimum Event Requirement
The function requires at least 5 events of each type for competing risks analysis. This protects against unstable CIF and Fine-Gray estimates.
# Create a small subset with few events
set.seed(42)
small_data <- competing_survival_data[sample(1:300, 15), ]
# This may error if disease or competing events < 5
competingsurvival(
data = small_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
dooc = "Dead_of_Other",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease"
)
#> Error in `private$.competingRisksSurvival()`:
#> ! Too few competing events (0). Competing risks analysis requires at least 5 events of each type.Competing Risks Requires Both Death Types
If only dod is defined without dooc,
competing risks analysis will produce an informative error.
competingsurvival(
data = competing_survival_data,
overalltime = "Overall_Time",
outcome = "Outcome",
explanatory = "Treatment",
analysistype = "compete",
dod = "Dead_of_Disease",
awd = "Alive_w_Disease",
awod = "Alive_wo_Disease"
)
#> Error in `competingsurvival()`:
#> ! argument "dooc" is missing, with no defaultAll Three Analysis Types in Sequence
A common workflow compares results across all three approaches:
# Overall
res_all_os <- competingsurvival(
data = survival_competing,
overalltime = "elapsedtime",
outcome = "outcome",
explanatory = "treatment",
analysistype = "overall",
dod = "Dead of Disease",
dooc = "Dead of Other",
awd = "Alive w Disease",
awod = "Alive w/o Disease"
)
# Cause-specific
res_all_css <- competingsurvival(
data = survival_competing,
overalltime = "elapsedtime",
outcome = "outcome",
explanatory = "treatment",
analysistype = "cause",
dod = "Dead of Disease",
dooc = "Dead of Other",
awd = "Alive w Disease",
awod = "Alive w/o Disease"
)
# Competing risks with full features
res_all_cr <- competingsurvival(
data = survival_competing,
overalltime = "elapsedtime",
outcome = "outcome",
explanatory = "treatment",
analysistype = "compete",
dod = "Dead of Disease",
dooc = "Dead of Other",
awd = "Alive w Disease",
awod = "Alive w/o Disease",
graystest = TRUE,
subdistribution = TRUE,
showStackedPlot = TRUE,
showKMvsCIF = TRUE,
timepoints = "12,24,36,60",
confidencelevel = 0.95
)
#> Error in `value[[3L]]()`:
#> ! Competing risks analysis failed:Comparing the hazard ratios across these three analyses reveals how competing risks affect the estimated treatment effect. The cause-specific HR captures the direct treatment effect on disease death rate. The subdistribution HR captures the net treatment effect on cumulative incidence, which is often the quantity patients and clinicians care about.
Complete Option Reference
| Option | Type | Default | Description |
|---|---|---|---|
data |
Data | (required) | The data as a data frame |
overalltime |
Variable (numeric) | (required) | Follow-up time in months |
outcome |
Variable (factor) | (required) | Multi-level outcome factor |
explanatory |
Variable (factor) | NULL | Grouping variable for comparison |
dod |
Level | NULL | Level of outcome indicating death from disease |
dooc |
Level | NULL | Level of outcome indicating death from other
causes |
awd |
Level | NULL | Level of outcome indicating alive with disease |
awod |
Level | NULL | Level of outcome indicating alive without disease |
analysistype |
List | “overall” | Analysis type: “overall”, “cause”, or “compete” |
graystest |
Bool | FALSE | Perform Gray’s test comparing CIF curves between groups |
subdistribution |
Bool | FALSE | Fit Fine-Gray subdistribution hazard model |
timepoints |
String | “12,24,36,60” | Comma-separated time points (months) for CIF estimates |
confidencelevel |
Number | 0.95 | Confidence level for intervals (0.50 to 0.99) |
showrisksets |
Bool | FALSE | Show number at risk summary below CIF plot |
showStackedPlot |
Bool | FALSE | Display stacked CIF + survival probability plot |
showKMvsCIF |
Bool | FALSE | Display 1-KM vs CIF comparison plot |
cifColors |
List | “default” | Color palette: “default” (Red/Blue), “colorblind”, or “grayscale” |
Output Elements
| Output | Type | Visibility |
|---|---|---|
todo |
Html | When no variables selected |
summary |
Html | Always |
survivalTable |
Table | Always |
cuminc |
Table | When analysistype = "compete"
|
comprisksPlot |
Image | When analysistype = "compete"
|
stackedPlot |
Image | When showStackedPlot = TRUE and
analysistype = "compete"
|
kmvscifPlot |
Image | When showKMvsCIF = TRUE and
analysistype = "compete"
|
interpretation |
Html | Always |
assumptions |
Html | Always |
fineGrayTable |
Table | When subdistribution = TRUE
|
References
- Fine JP, Gray RJ (1999). A proportional hazards model for the subdistribution of a competing risk. Journal of the American Statistical Association, 94(446):496-509.
- Gray RJ (1988). A class of K-sample tests for comparing the cumulative incidence of a competing risk. Annals of Statistics, 16(3):1141-1154.
- Putter H, Fiocco M, Geskus RB (2007). Tutorial in biostatistics: competing risks and multi-state models. Statistics in Medicine, 26(11):2389-2430.
- Austin PC, Lee DS, Fine JP (2016). Introduction to the analysis of survival data in the presence of competing risks. Circulation, 133(6):601-609.
- Dignam JJ, Zhang Q, Kocherginsky M (2012). The use and interpretation of competing risks regression models. Clinical Cancer Research, 18(8):2301-2308.