library(cureAssess)
library(survival)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, unionThe cureAssess package provides tools for assessing whether a cure model may be appropriate for right-censored survival data. The package supports a two-stage workflow:
In this vignette, we demonstrate the basic workflow using two datasets from the survival package.
‘nwtco’ dataset was used to demonstrate an example when a cure model is appropriate and ‘gbsg’ dataset is used to demonstrate an example when a cure model is not appropriate.
nwtco data set — an example where a cure
model may be appropriateWe illustrate the use of cureAssess with the
nwtco data set from the survival package.
head(survival::nwtco)
#> seqno instit histol stage study rel edrel age in.subcohort
#> 1 1 2 2 1 3 0 6075 25 FALSE
#> 2 2 1 1 2 3 0 4121 50 FALSE
#> 3 3 2 2 1 3 0 6069 9 FALSE
#> 4 4 2 1 4 3 0 6200 28 TRUE
#> 5 5 2 2 2 3 0 1244 55 FALSE
#> 6 6 1 1 2 3 0 2932 32 FALSEThe nwtco data set contains 4028 observations on 9 variables:
seqno: subject identifier instit: histology from the local institution histol: histology from the central laboratory stage: disease stage study: study indicator rel: relapse indicator edrel: time to relapse age: age at diagnosis in.subcohort: indicator for inclusion in the subcohort used in the example paper
For this illustration, the data were grouped into two clinically meaningful risk categories based on the variable stage:
Low risk: stages 1 and 2, representing patients with relatively higher relapse-free survival High risk: stages 3 and 4, representing patients with relatively higher risk of relapse
This type of grouping should ideally be guided by subject-matter expertise and clinical knowledge of the disease.
In this example, age is assumed to be recorded in months, and edrel is assumed to be recorded in days. Therefore, the time variable is converted to years during data preparation.
The grouping step is performed as part of data preprocessing before applying the functions in cureAssess.
We first create the risk groups based on the disease stage.
Next, we standardize the survival data into the format required by cureAssess. Here the relapse time (edrel) is assumed to be recorded in days, so it is converted to years.
nwtco_surv <- prepare.surv.data(
data = nwtco_dat,
time = "edrel",
status = "rel",
time_scale = "days_to_years"
)
head(nwtco_surv)
#> seqno instit histol stage study rel edrel age in.subcohort stage_group
#> 1 1 2 2 1 3 0 6075 25 FALSE Low risk
#> 2 2 1 1 2 3 0 4121 50 FALSE Low risk
#> 3 3 2 2 1 3 0 6069 9 FALSE Low risk
#> 4 4 2 1 4 3 0 6200 28 TRUE High risk
#> 5 5 2 2 2 3 0 1244 55 FALSE Low risk
#> 6 6 1 1 2 3 0 2932 32 FALSE Low risk
#> Y D
#> 1 16.632444 0
#> 2 11.282683 0
#> 3 16.616016 0
#> 4 16.974675 0
#> 5 3.405886 0
#> 6 8.027379 0The prepared dataset contains the original columns plus: Y: survival time D: event indicator
Next, we fit several candidate models and compare them using AIC.
fit_res <- model.fitting(nwtco_surv, plot_km = TRUE)
#> Ignoring unknown labels:
#> • fill : "Strata"
fit_res
#>
#> Candidate model fitting results
#> --------------------------------
#> Best model by AIC: loglogistic_cure
#>
#> model model_type AIC parameter_estimates
#> loglogistic_cure cure 4339.369 theta=0.8489; shape=1.9818; scale=0.8285
#> gamma_cure cure 4380.428 theta=0.8507; shape=1.6097; rate=1.4284
#> weibull_cure cure 4407.184 theta=0.8504; shape=1.2304; scale=1.2211
#> exponential_cure cure 4444.078 theta=0.8494; rate=0.85
#> loglogistic non-cure 4941.015 shape=0.504; scale=206.8519
#> weibull non-cure 4964.699 shape=0.4736; scale=323.56
#> gamma non-cure 4986.062 shape=0.4512; rate=0.0016
#> exponential non-cure 5464.789 =0.0227
#> error
#>
#>
#>
#>
#>
#>
#>
#> The AIC table can be examined directly.
If plot_km = TRUE, the Kaplan-Meier plot is stored in
the fitted object.
print(fit_res$kmplot)
#> Ignoring unknown labels:
#> • fill : "Strata"
#> Ignoring unknown labels:
#> • fill : "Strata"
#> Ignoring unknown labels:
#> • fill : "Strata"
#> Ignoring unknown labels:
#> • colour : "Strata"fit_res$aic_table
#> model model_type AIC parameter_estimates
#> 1 loglogistic_cure cure 4339.369 theta=0.8489; shape=1.9818; scale=0.8285
#> 2 gamma_cure cure 4380.428 theta=0.8507; shape=1.6097; rate=1.4284
#> 3 weibull_cure cure 4407.184 theta=0.8504; shape=1.2304; scale=1.2211
#> 4 exponential_cure cure 4444.078 theta=0.8494; rate=0.85
#> 5 loglogistic non-cure 4941.015 shape=0.504; scale=206.8519
#> 6 weibull non-cure 4964.699 shape=0.4736; scale=323.56
#> 7 gamma non-cure 4986.062 shape=0.4512; rate=0.0016
#> 8 exponential non-cure 5464.789 =0.0227
#> error
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8The best-fitting model according to AIC is:
If desired, additional diagnostics can be computed.
The Maller–Zhou test (Maller & Zhou, 1994; 1996) is a diagnostic method used to assess whether a cure fraction may exist in right-censored survival data.
The qn statistic, proposed by Maller and Zhou (1996), is a descriptive statistic used to evaluate whether a survival plateau may exist in right-censored survival data.
test_res$qn
#>
#> qn statistic (Maller & Zhou 1996)
#> ---------------------------------
#> Statistic: 0.0007447865
#> Interpretation: The qn statistic is 7e-04 (alpha_n-equivalent threshold for sufficient follow-up at the 0.05 level is 7e-04). Because qn exceeds this threshold, there is evidence of sufficient follow-up, consistent with a survival plateau and supporting cure model appropriateness. Larger values of qn provide stronger evidence.The Shen test is a statistical method used to assess whether a cure fraction may be present in right-censored survival data.
test_res$immune
#>
#> Maller-Zhou immune summary (1996)
#> ---------------------------------
#> p_hat: 0.1505957
#> p_cens: 0.8582423
#> Last observation: 16.99932
#> Last observation censored: TRUE
#> Interpretation: The last observed time is censored, suggesting a possible survival plateau. The estimated event probability by the end of follow-up is 0.1506, and the censoring proportion is 0.8582.The RECeUS method is a diagnostic approach used to assess whether a cure model is appropriate for survival data. It evaluates both the estimated cure fraction and the amount of remaining uncured subjects at the end of follow-up.
test_res$receus
#>
#> RECeUS Cure Model Assessment
#> ----------------------------
#> Distribution: lnorm
#> Tau: 16.9993
#>
#> Estimated cure fraction (pi_hat): 0.8495
#> Remaining uncured ratio (r_hat): 3e-04
#>
#> Decision: Cure model appropriate
#>
#> Interpretation:
#> Both RECeUS conditions are satisfied: pi_hat > 0.025 and r_hat < 0.05. This suggests the presence of a cure fraction and sufficient follow-up for reliable cure model estimation.The main wrapper function combines preparation, model fitting, and optional testing. Screening only.
res_screen <- cure.appropriateness(
data = nwtco_dat,
time = "edrel",
status = "rel",
time_scale = "days_to_years",
dist = "lnorm",
plot_km = FALSE,
run_tests = "no"
)
res_screen
#>
#> Cure model appropriateness analysis
#> -----------------------------------
#> Best model by AIC: loglogistic_cure
#> Best model type: cure
#>
#> Initial decision:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.
#>
#> RECeUS distribution used: lnorm
#> Testing status:
#> Tests were not run because `run_tests = "no"`.
#>
#> Final recommendation:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.The screening results can be inspected through the screening component.
res_screen$screening$aic_table
#> model model_type AIC parameter_estimates
#> 1 loglogistic_cure cure 4339.369 theta=0.8489; shape=1.9818; scale=0.8285
#> 2 gamma_cure cure 4380.428 theta=0.8507; shape=1.6097; rate=1.4284
#> 3 weibull_cure cure 4407.184 theta=0.8504; shape=1.2304; scale=1.2211
#> 4 exponential_cure cure 4444.078 theta=0.8494; rate=0.85
#> 5 loglogistic non-cure 4941.015 shape=0.504; scale=206.8519
#> 6 weibull non-cure 4964.699 shape=0.4736; scale=323.56
#> 7 gamma non-cure 4986.062 shape=0.4512; rate=0.0016
#> 8 exponential non-cure 5464.789 =0.0227
#> error
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
res_screen$screening$best_model
#> [1] "loglogistic_cure"
res_screen$screening$initial_decision
#> [1] "The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness."Automatic testing only if the best model is a cure model.
res_auto <- cure.appropriateness(
data = nwtco_dat,
time = "edrel",
status = "rel",
time_scale = "days_to_years",
dist = "lnorm",
plot_km = FALSE,
run_tests = "auto"
)
res_auto
#>
#> Cure model appropriateness analysis
#> -----------------------------------
#> Best model by AIC: loglogistic_cure
#> Best model type: cure
#>
#> Initial decision:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.
#>
#> RECeUS distribution used: lnorm
#> Testing status:
#> Tests were run automatically because the smallest-AIC model was a cure model. RECeUS used distribution: lnorm.
#>
#> Final recommendation:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness. Additional cure-appropriateness diagnostics were run for further evaluation.Force all tests to run, regardless of which model AIC selected.
res_full <- cure.appropriateness(
data = nwtco_dat,
time = "edrel",
status = "rel",
time_scale = "days_to_years",
dist = "lnorm",
plot_km = FALSE,
run_tests = "yes"
)
res_full
#>
#> Cure model appropriateness analysis
#> -----------------------------------
#> Best model by AIC: loglogistic_cure
#> Best model type: cure
#>
#> Initial decision:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.
#>
#> RECeUS distribution used: lnorm
#> Testing status:
#> Tests were run because `run_tests = "yes"`. RECeUS used distribution: lnorm.
#>
#> Final recommendation:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness. Additional cure-appropriateness diagnostics were run for further evaluation.gbsg data set — an example where a cure
model may not be appropriate.head(survival::gbsg)
#> pid age meno size grade nodes pgr er hormon rfstime status
#> 1 132 49 0 18 2 2 0 0 0 1838 0
#> 2 1575 55 1 20 3 16 0 0 0 403 1
#> 3 1140 56 1 40 3 3 0 0 0 1603 0
#> 4 769 45 0 25 3 1 0 4 0 177 0
#> 5 130 65 1 30 2 5 0 36 1 1855 0
#> 6 1642 48 0 52 2 11 0 0 0 842 1The dataset contains 686 observations and the following variables:
pid: patient identifier age: age in years meno: menopausal status (0 = premenopausal, 1 = postmenopausal) size: tumor size (mm) grade: tumor grade nodes: number of positive lymph nodes pgr: progesterone receptor level (fmol/l) er: estrogen receptor level (fmol/l) hormon: hormonal therapy (0 = no, 1 = yes) rfstime: recurrence-free survival time (days to first recurrence, death, or last follow-up) status: event indicator (0 = alive without recurrence, 1 = recurrence or death)
We first create the groups based on the menopausal stage.
Then we need to convert input data into the format required by cureAssess. Here, recurrence-free survival time is stored in days, so we convert it to years.
gbsg_dat <- prepare.surv.data(
data = survival::gbsg,
time = "rfstime",
status = "status",
time_scale = "days_to_years"
)
head(gbsg_dat)
#> pid age meno size grade nodes pgr er hormon rfstime status Y D
#> 1 132 49 0 18 2 2 0 0 0 1838 0 5.0321697 0
#> 2 1575 55 1 20 3 16 0 0 0 403 1 1.1033539 1
#> 3 1140 56 1 40 3 3 0 0 0 1603 0 4.3887748 0
#> 4 769 45 0 25 3 1 0 4 0 177 0 0.4845996 0
#> 5 130 65 1 30 2 5 0 36 1 1855 0 5.0787132 0
#> 6 1642 48 0 52 2 11 0 0 0 842 1 2.3052704 1The prepared dataset contains the original columns plus: Y: survival time D: event indicator
Next, we fit several candidate models and compare them using AIC.
fit_res <- model.fitting(gbsg_dat, plot_km = TRUE)
#> Ignoring unknown labels:
#> • fill : "Strata"
fit_res
#>
#> Candidate model fitting results
#> --------------------------------
#> Best model by AIC: loglogistic_cure
#>
#> model model_type AIC parameter_estimates
#> loglogistic_cure cure 1719.696 theta=0.3238; shape=1.9556; scale=2.7033
#> gamma_cure cure 1723.476 theta=0.3805; shape=2.1055; rate=0.696
#> loglogistic non-cure 1731.346 shape=1.5325; scale=4.4994
#> weibull_cure cure 1733.922 theta=0.3839; shape=1.5654; scale=3.2983
#> gamma non-cure 1742.850 shape=1.4689; rate=0.2516
#> weibull non-cure 1750.005 shape=1.2715; scale=6.1871
#> exponential non-cure 1769.052 =0.1416
#> exponential_cure cure 1771.057 theta=4e-04; rate=0.1416
#> error
#>
#>
#>
#>
#>
#>
#>
#> The AIC table can be examined directly.
If plot_km = TRUE, the Kaplan-Meier plot is stored in
the fitted object.
print(fit_res$kmplot)
#> Ignoring unknown labels:
#> • fill : "Strata"
#> Ignoring unknown labels:
#> • fill : "Strata"
#> Ignoring unknown labels:
#> • fill : "Strata"
#> Ignoring unknown labels:
#> • colour : "Strata"fit_res$aic_table
#> model model_type AIC parameter_estimates
#> 1 loglogistic_cure cure 1719.696 theta=0.3238; shape=1.9556; scale=2.7033
#> 2 gamma_cure cure 1723.476 theta=0.3805; shape=2.1055; rate=0.696
#> 3 loglogistic non-cure 1731.346 shape=1.5325; scale=4.4994
#> 4 weibull_cure cure 1733.922 theta=0.3839; shape=1.5654; scale=3.2983
#> 5 gamma non-cure 1742.850 shape=1.4689; rate=0.2516
#> 6 weibull non-cure 1750.005 shape=1.2715; scale=6.1871
#> 7 exponential non-cure 1769.052 =0.1416
#> 8 exponential_cure cure 1771.057 theta=4e-04; rate=0.1416
#> error
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8The best-fitting model according to AIC is:
If desired, additional diagnostics can be computed.
The Maller–Zhou test (Maller & Zhou, 1994; 1996) is a diagnostic method used to assess whether a cure fraction may exist in right-censored survival data.
The qn statistic, proposed by Maller and Zhou (1996), is a descriptive statistic used to evaluate whether a survival plateau may exist in right-censored survival data.
test_res$qn
#>
#> qn statistic (Maller & Zhou 1996)
#> ---------------------------------
#> Statistic: 0.004373178
#> Interpretation: The qn statistic is 0.0044 (alpha_n-equivalent threshold for sufficient follow-up at the 0.05 level is 0.0044). Because qn exceeds this threshold, there is evidence of sufficient follow-up, consistent with a survival plateau and supporting cure model appropriateness. Larger values of qn provide stronger evidence.The Shen test is a statistical method used to assess whether a cure fraction may be present in right-censored survival data.
test_res$immune
#>
#> Maller-Zhou immune summary (1996)
#> ---------------------------------
#> p_hat: 0.6572415
#> p_cens: 0.5641399
#> Last observation: 7.279945
#> Last observation censored: TRUE
#> Interpretation: The last observed time is censored, suggesting a possible survival plateau. The estimated event probability by the end of follow-up is 0.6572, and the censoring proportion is 0.5641.The RECeUS method is a diagnostic approach used to assess whether a cure model is appropriate for survival data. It evaluates both the estimated cure fraction and the amount of remaining uncured subjects at the end of follow-up.
test_res$receus
#>
#> RECeUS Cure Model Assessment
#> ----------------------------
#> Distribution: lnorm
#> Tau: 7.2799
#>
#> Estimated cure fraction (pi_hat): 0.2775
#> Remaining uncured ratio (r_hat): 0.4083
#>
#> Decision: Follow-up insufficient for cure modeling
#>
#> Interpretation:
#> The remaining uncured ratio (r_hat = 0.4083 ) is greater than or equal to 0.05. This suggests that a large proportion of uncured subjects remain censored at the end of follow-up, indicating insufficient follow-up to reliably estimate a cure fraction.The main wrapper function combines preparation, model fitting, and optional testing. Screening only.
res_screen <- cure.appropriateness(
data = survival::gbsg,
time = "rfstime",
status = "status",
time_scale = "days_to_years",
dist = "lnorm",
plot_km = FALSE,
run_tests = "no"
)
res_screen
#>
#> Cure model appropriateness analysis
#> -----------------------------------
#> Best model by AIC: loglogistic_cure
#> Best model type: cure
#>
#> Initial decision:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.
#>
#> RECeUS distribution used: lnorm
#> Testing status:
#> Tests were not run because `run_tests = "no"`.
#>
#> Final recommendation:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.The screening results can be inspected through the screening component.
res_screen$screening$aic_table
#> model model_type AIC parameter_estimates
#> 1 loglogistic_cure cure 1719.696 theta=0.3238; shape=1.9556; scale=2.7033
#> 2 gamma_cure cure 1723.476 theta=0.3805; shape=2.1055; rate=0.696
#> 3 loglogistic non-cure 1731.346 shape=1.5325; scale=4.4994
#> 4 weibull_cure cure 1733.922 theta=0.3839; shape=1.5654; scale=3.2983
#> 5 gamma non-cure 1742.850 shape=1.4689; rate=0.2516
#> 6 weibull non-cure 1750.005 shape=1.2715; scale=6.1871
#> 7 exponential non-cure 1769.052 =0.1416
#> 8 exponential_cure cure 1771.057 theta=4e-04; rate=0.1416
#> error
#> 1
#> 2
#> 3
#> 4
#> 5
#> 6
#> 7
#> 8
res_screen$screening$best_model
#> [1] "loglogistic_cure"
res_screen$screening$initial_decision
#> [1] "The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness."Automatic testing only if the best model is a cure model.
res_auto <- cure.appropriateness(
data = survival::gbsg,
time = "rfstime",
status = "status",
time_scale = "days_to_years",
dist = "lnorm",
plot_km = FALSE,
run_tests = "auto"
)
res_auto
#>
#> Cure model appropriateness analysis
#> -----------------------------------
#> Best model by AIC: loglogistic_cure
#> Best model type: cure
#>
#> Initial decision:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.
#>
#> RECeUS distribution used: lnorm
#> Testing status:
#> Tests were run automatically because the smallest-AIC model was a cure model. RECeUS used distribution: lnorm.
#>
#> Final recommendation:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness. Additional cure-appropriateness diagnostics were run for further evaluation.Force all tests to run
res_full <- cure.appropriateness(
data = survival::gbsg,
time = "rfstime",
status = "status",
time_scale = "days_to_years",
dist = "lnorm",
plot_km = FALSE,
run_tests = "yes"
)
res_full
#>
#> Cure model appropriateness analysis
#> -----------------------------------
#> Best model by AIC: loglogistic_cure
#> Best model type: cure
#>
#> Initial decision:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness.
#>
#> RECeUS distribution used: lnorm
#> Testing status:
#> Tests were run because `run_tests = "yes"`. RECeUS used distribution: lnorm.
#>
#> Final recommendation:
#> The model with the smallest AIC is a cure model (loglogistic_cure). This provides initial support for cure model appropriateness. Additional cure-appropriateness diagnostics were run for further evaluation.The recommended workflow is:
This two-stage strategy helps separate initial model-based screening from deeper cure-appropriateness assessment.