Let us first load the packages required.
We will create a cdm reference to use our example MGUS2 survival dataset again. In practice you would use the CDMConnector package to connect to your data mapped to the OMOP CDM.
We will proceed as we did with the single event survival, but this time we are considering an event of interest (progression of disease) with a competing risk (mortality). A competing outcome is an event that changes the interpretation of follow-up because, once it occurs, the event of interest can no longer be observed in the same way. In this example, death competes with later observed progression.
All the details provided in the single event survival vignette are also valid in this study case: the potential input changes for the estimation, the different output formats available or the options for the table and plot functions. Everything discussed previously is also applicable when adding a competing outcome, as we will show in this vignette. Therefore we will not provide as much detail in all the possible combinations of inputs here, but rather focus in the particularities of estimating survival with an outcome and a competing outcome.
Let us take a glimpse at the three cohorts we will use this time: the mgus diagnosis as a target, and both the death cohort and the progression to multiple myeloma as outcomes.
cdm$mgus_diagnosis |>
glimpse()
#> Rows: ??
#> Columns: 10
#> $ cohort_definition_id <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
#> $ subject_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15…
#> $ cohort_start_date <date> 1981-01-01, 1968-01-01, 1980-01-01, 1977-01-01, …
#> $ cohort_end_date <date> 1981-01-01, 1968-01-01, 1980-01-01, 1977-01-01, …
#> $ age <dbl> 88, 78, 94, 68, 90, 90, 89, 87, 86, 79, 86, 89, 8…
#> $ sex <fct> F, F, M, M, F, M, F, F, F, F, M, F, M, F, M, F, F…
#> $ hgb <dbl> 13.1, 11.5, 10.5, 15.2, 10.7, 12.9, 10.5, 12.3, 1…
#> $ creat <dbl> 1.30, 1.20, 1.50, 1.20, 0.80, 1.00, 0.90, 1.20, 0…
#> $ mspike <dbl> 0.5, 2.0, 2.6, 1.2, 1.0, 0.5, 1.3, 1.6, 2.4, 2.3,…
#> $ age_group <chr> ">=70", ">=70", ">=70", "<70", ">=70", ">=70", ">…
cdm$death_cohort |>
glimpse()
#> Rows: ??
#> Columns: 4
#> $ cohort_definition_id <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
#> $ subject_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 1…
#> $ cohort_start_date <date> 1981-01-31, 1968-01-26, 1980-02-16, 1977-04-03, …
#> $ cohort_end_date <date> 1981-01-31, 1968-01-26, 1980-02-16, 1977-04-03, …
cdm$progression |>
glimpse()
#> Rows: ??
#> Columns: 4
#> $ cohort_definition_id <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
#> $ subject_id <int> 56, 81, 83, 111, 124, 127, 147, 163, 165, 167, 18…
#> $ cohort_start_date <date> 1978-01-30, 1985-01-15, 1974-08-17, 1993-01-14, …
#> $ cohort_end_date <date> 1978-01-30, 1985-01-15, 1974-08-17, 1993-01-14, …This package allows to estimate the cumulative incidence of both an
outcome and a competing outcome. We can then stratify, see information
on events or summarise the estimates, among others, in the same way we
did for the single event survival analysis. The only additional
requirement here is to specify the
competingOutcomeCohortTable argument.
MGUS_death_prog <- estimateCompetingRiskSurvival(cdm,
targetCohortTable = "mgus_diagnosis",
outcomeCohortTable = "progression",
competingOutcomeCohortTable = "death_cohort"
)
MGUS_death_prog |>
asSurvivalResult() |>
glimpse()
#> Rows: 850
#> Columns: 10
#> $ cdm_name <chr> "mock", "mock", "mock", "mock", "mock", "mock", "m…
#> $ target_cohort <chr> "mgus_diagnosis", "mgus_diagnosis", "mgus_diagnosi…
#> $ outcome <chr> "progression", "progression", "progression", "prog…
#> $ competing_outcome <chr> "death_cohort", "death_cohort", "death_cohort", "d…
#> $ variable <chr> "progression", "progression", "progression", "prog…
#> $ time <dbl> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, …
#> $ result_type <chr> "survival_estimates", "survival_estimates", "survi…
#> $ estimate <dbl> 0.0000, 0.0000, 0.0014, 0.0014, 0.0022, 0.0029, 0.…
#> $ estimate_95CI_lower <dbl> 0.0000, 0.0000, 0.0004, 0.0004, 0.0007, 0.0011, 0.…
#> $ estimate_95CI_upper <dbl> 0.0000, 0.0000, 0.0058, 0.0058, 0.0067, 0.0077, 0.…As we can see above our results have been outputted in long format,
once transformed into the survival format. For competing-risk results,
estimate is interpreted as cumulative incidence for the
row’s variable, which will be either the outcome of
interest or the competing outcome. This is why we use
cumulativeFailure = TRUE when plotting:
plotSurvival(MGUS_death_prog, cumulativeFailure = TRUE,
colour = "variable") +
theme(legend.position = "top")The summary table of survival now has a row for each of the outcomes:
| Data source | Target cohort | Outcome type | Outcome name |
Estimate name
|
||
|---|---|---|---|---|---|---|
| Number records | Number events | Restricted mean survival (95% CI) | ||||
| mock | mgus_diagnosis | outcome | progression | 1,384 | 106 | 35.00 (28.00, 42.00) |
| competing_outcome | death_cohort | 1,384 | 869 | 260.00 (250.00, 269.00) | ||
The restricted mean summary follows the same principle as in the
single-event analysis: it is calculated up to
restrictedMeanFollowUp. If
restrictedMeanFollowUp = NULL, the horizon is left to the
underlying survival summary. In stratified analyses, this can use a
common maximum follow-up time across the fitted curves. A stratum with
shorter observed follow-up may therefore have its last estimate carried
forward and integrated beyond its own maximum follow-up. This can make
restricted mean summaries larger than the observed follow-up time for
some strata and can make comparisons misleading. For comparisons, set a
common clinically meaningful horizon in
estimateCompetingRiskSurvival() that is supported by
follow-up in all groups, for example
restrictedMeanFollowUp = 365.
The outcome and competing outcome can have separate washout
definitions. outcomeWashout controls prior events of the
outcome of interest, while competingOutcomeWashout controls
prior competing events. In both cases, Inf means any prior
event before target cohort entry and 0 means no pre-index
washout. Other censoring parameters, such as followUpDays,
censorOnCohortExit, and censorOnDate, behave
as in the single-event setting.
Again, to estimate survival for particular strata of interest we need these features to have been added to the target cohort table. We can then give the names of these strata columns to the estimating function like so:
MGUS_death_prog <- estimateCompetingRiskSurvival(cdm,
targetCohortTable = "mgus_diagnosis",
outcomeCohortTable = "progression",
competingOutcomeCohortTable = "death_cohort",
strata = list(c("sex"))
)As well as results for each strata, we will always also have overall results returned. We can filter the output table to plot only the results for the different strata levels, if we do not wish to add the overall cohort in the plot. We can also ask for the cumulative failure probability to be plotted instead of the survival probability, which makes more sense in the competing outcome case.
plotSurvival(MGUS_death_prog |>
dplyr::filter(strata_name != "Overall"),
facet = "sex",
colour = "variable",
cumulativeFailure = TRUE)And we also now have summary statistics for each of the strata as well as overall.
| Data source | Target cohort | Sex | Outcome type | Outcome name |
Estimate name
|
||
|---|---|---|---|---|---|---|---|
| Number records | Number events | Restricted mean survival (95% CI) | |||||
| mock | mgus_diagnosis | overall | outcome | progression | 1,384 | 106 | 35.00 (28.00, 42.00) |
| competing_outcome | death_cohort | 1,384 | 869 | 260.00 (250.00, 269.00) | |||
| F | outcome | progression | 631 | 55 | 40.00 (32.00, 49.00) | ||
| M | outcome | progression | 753 | 51 | 29.00 (21.00, 37.00) | ||
| F | competing_outcome | death_cohort | 631 | 374 | 245.00 (231.00, 258.00) | ||
| M | competing_outcome | death_cohort | 753 | 495 | 272.00 (259.00, 285.00) | ||