ltRISK estimates lifetime and age-conditional risks of developing or dying from cancer using population-based cancer registry data. It provides a reproducible R interface for comparing several established approaches used in cancer surveillance:
The main wrapper, calc_ltr(), returns risk estimates and confidence
intervals. Both gamma-based and delta-method confidence intervals are
supported through the ci_method argument. DevCan, Wun, AMP, and
cumulative risk support the piecewise mid-age group joinpoint (PMAJ)
model for age-specific rates. Wun retains its historical
piecewise-constant calculation by default; set maj_method = "pmaj"
explicitly to use PMAJ.
You can install ltRISK from R-universe with:
install.packages(
"ltRISK",
repos = c("https://gigu003.r-universe.dev", "https://cloud.r-project.org")
)
You can install the development version from GitHub with:
# install.packages("devtools")
devtools::install_github("gigu003/ltRISK")
The package includes example data from DevCan-related publications and SEER data. The following example estimates the lifetime and age-conditional risks of developing breast cancer using the DevCan method.
library(ltRISK)
data("seer_example_data")
breast <- seer_example_data[seer_example_data$site == "Breast", ]
all_sites <- seer_example_data[
seer_example_data$site == "All" & seer_example_data$sex == 0,
]
calc_ltr(
ages = breast$ages,
cancer = breast$cancer,
cancer_death = breast$cancer_death,
death = breast$death,
pys = breast$pys,
risk_func = "devcan",
maj_method = "constant",
ci_method = "gamma",
age_start = c(0, 30, 50, 70),
age_end = c(30, 50, 70, Inf),
digits = 4
)
#> start end risk lower upper
#> 1 0 30 0.0470 0.0424 0.0519
#> 2 0 50 1.8995 1.8708 1.9286
#> 3 0 70 7.7861 7.7130 7.8598
#> 4 0 Inf 13.3198 13.2170 13.4235
#> 5 30 50 1.8817 1.8529 1.9108
#> 6 30 70 7.8609 7.7868 7.9355
#> 7 30 Inf 13.4816 13.3773 13.5868
#> 8 50 70 6.2505 6.1793 6.3224
#> 9 50 Inf 12.1264 12.0217 12.2320
#> 10 70 Inf 7.3149 7.2202 7.4109
The same calculation can be written with the data-frame interface
calc_ltr_df(), which is convenient for pipe-based workflows:
calc_ltr_df(
breast,
ages = ages,
cancer = cancer,
cancer_death = cancer_death,
death = death,
pys = pys,
risk_func = "devcan",
maj_method = "constant",
ci_method = "gamma",
age_start = c(0, 30, 50, 70),
age_end = c(30, 50, 70, Inf),
digits = 4
)
#> start end risk lower upper
#> 1 0 30 0.0470 0.0424 0.0519
#> 2 0 50 1.8995 1.8708 1.9286
#> 3 0 70 7.7861 7.7130 7.8598
#> 4 0 Inf 13.3198 13.2170 13.4235
#> 5 30 50 1.8817 1.8529 1.9108
#> 6 30 70 7.8609 7.7868 7.9355
#> 7 30 Inf 13.4816 13.3773 13.5868
#> 8 50 70 6.2505 6.1793 6.3224
#> 9 50 Inf 12.1264 12.0217 12.2320
#> 10 70 Inf 7.3149 7.2202 7.4109
For multiple registry strata, calc_ltr_df() can calculate risks by
group:
calc_ltr_df(
seer_example_data,
by = c("site", "sex"),
ages = ages,
cancer = cancer,
cancer_death = cancer_death,
death = death,
pys = pys,
risk_func = "devcan",
maj_method = "constant",
ci_method = "delta",
age_start = 0,
age_end = Inf,
digits = 4
)
#> site sex start end risk lower upper
#> 1 All 0 0 Inf 39.1670 39.1072 39.2268
#> 2 All 1 0 Inf 39.4881 39.4018 39.5744
#> 3 All 2 0 Inf 38.9734 38.8899 39.0569
#> 4 Breast 2 0 Inf 13.3198 13.2168 13.4228
By default, calc_ltr() returns every valid combination of age_start
and age_end. Use age_combine = "pairwise" for positional, mutually
exclusive ranges such as 0–40, 40–50, and 50 years to the end of life.
calc_ltr(
ages = all_sites$ages,
cancer = all_sites$cancer,
cancer_death = all_sites$cancer_death,
death = all_sites$death,
pys = all_sites$pys,
age_start = c(0, 40, 50),
age_end = c(40, 50, Inf),
age_combine = "pairwise",
ci_method = "delta",
digits = 4
)
#> start end risk lower upper
#> 1 0 40 2.0321 2.0212 2.0431
#> 2 40 50 2.8292 2.8155 2.8429
#> 3 50 Inf 38.3877 38.3238 38.4515
For point estimates only, use ci_method = "none". DevCan, AMP, Wun,
and cumulative-risk models use analytic variances by default where
available; variance_method = "finite_difference" remains available for
verification. For many independent registry strata, calc_ltr_df()
supports cross-platform parallel processing.
risks <- calc_ltr_df(
seer_example_data,
by = c("site", "sex"),
ci_method = "delta",
variance_method = "analytic",
parallel = TRUE,
workers = 2,
return_variance = TRUE
)
Repeated calculations use internal memoisation. Long-running pipelines can inspect or clear these caches explicitly:
ltr_cache_info()
clear_ltr_cache()
For a large grouped job whose inputs are unlikely to repeat, use
cache = "none" in calc_ltr_df(). This discards memoised entries
after each group, including on reused PSOCK workers, and reduces peak
cache growth.
Package developers can reproduce the confidence-interval timing comparison from the source tree with:
Rscript inst/benchmarks/benchmark-ci.R
The DevCan implementation is externally regression-tested against the female breast cancer estimates and confidence intervals in Fay et al. (2003), Table II. A seeded parametric coverage diagnostic can be run from the source tree:
Rscript inst/validation/simulate-ci-coverage.R 1000
The variance model treats incidence, cancer-death, and other-death counts as independent Poisson components and treats person-years as fixed. Comparisons of overlapping populations or periods require covariance information that the package does not estimate automatically.
format_risk_ci() combines estimates and confidence limits for tables
while retaining the precision selected in calc_ltr(). With
return_variance = TRUE, grouped results can also be passed to
ztest(), pairwise_ztest(), or trend_test().
sex_risks <- calc_ltr_df(
seer_example_data[
seer_example_data$site == "All" &
seer_example_data$sex %in% c(1, 2),
],
by = "sex",
ci_method = "delta",
return_variance = TRUE,
digits = 4
)
format_risk_ci(sex_risks)
#> sex start end risk lower upper variance se
#> 1 1 0 Inf 39.2052 39.1189 39.2915 0.001938403 0.04402730
#> 2 2 0 Inf 38.7289 38.6453 38.8124 0.001816086 0.04261556
#> risk_95ci
#> 1 39.2052 (39.1189, 39.2915)
#> 2 38.7289 (38.6453, 38.8124)
ztest(sex_risks, group = "sex", ref = 2, compare = 1)
#> group_compare group_ref start end risk_compare risk_ref difference se
#> 1 1 2 0 Inf 39.2052 38.7289 0.4763 0.061274
#> z p lower upper
#> 1 7.773295 7.647009e-15 0.356205 0.596395
The same estimates can be calculated with delta-method confidence intervals:
calc_ltr(
ages = breast$ages,
cancer = breast$cancer,
cancer_death = breast$cancer_death,
death = breast$death,
pys = breast$pys,
risk_func = "devcan",
maj_method = "constant",
ci_method = "delta",
age_start = c(0, 30, 50, 70),
age_end = c(30, 50, 70, Inf),
digits = 4
)
#> start end risk lower upper
#> 1 0 30 0.0470 0.0423 0.0517
#> 2 0 50 1.8995 1.8707 1.9284
#> 3 0 70 7.7861 7.7128 7.8594
#> 4 0 Inf 13.3198 13.2168 13.4228
#> 5 30 50 1.8817 1.8527 1.9106
#> 6 30 70 7.8609 7.7866 7.9351
#> 7 30 Inf 13.4816 13.3771 13.5861
#> 8 50 70 6.2505 6.1791 6.3220
#> 9 50 Inf 12.1264 12.0214 12.2313
#> 10 70 Inf 7.3149 7.2199 7.4100
To estimate the risk of dying from cancer instead of developing cancer,
set type = "dying".
calc_ltr(
ages = breast$ages,
cancer = breast$cancer,
cancer_death = breast$cancer_death,
death = breast$death,
pys = breast$pys,
risk_func = "devcan",
maj_method = "constant",
ci_method = "gamma",
type = "dying",
age_start = c(0, 30, 50, 70),
age_end = c(30, 50, 70, Inf),
digits = 4
)
#> start end risk lower upper
#> 1 0 30 0.0051 0.0037 0.0069
#> 2 0 50 0.2901 0.2789 0.3016
#> 3 0 70 1.4657 1.4339 1.4981
#> 4 0 Inf 3.2027 3.1514 3.2548
#> 5 30 50 0.2893 0.2781 0.3009
#> 6 30 70 1.4830 1.4507 1.5158
#> 7 30 Inf 3.2465 3.1944 3.2994
#> 8 50 70 1.2276 1.1965 1.2593
#> 9 50 Inf 3.0413 2.9890 3.0945
#> 10 70 Inf 2.1361 2.0862 2.1870
The same calc_ltr() interface can be used with the Wun and AMP methods
by changing risk_func.
# Wun method
calc_ltr(
ages = all_sites$ages,
cancer = all_sites$cancer,
cancer_death = all_sites$cancer_death,
death = all_sites$death,
pys = all_sites$pys,
risk_func = "wun",
maj_method = "pmaj",
pmaj_sub_interval = 1,
ci_method = "gamma",
age_start = c(0, 50, 70),
age_end = Inf,
digits = 4
)
#> start end risk lower upper
#> 1 0 Inf 38.7774 38.7184 38.8364
#> 2 50 Inf 38.2360 38.1731 38.2990
#> 3 70 Inf 30.2010 30.1274 30.2748
# AMP method
calc_ltr(
ages = all_sites$ages,
cancer = all_sites$cancer,
cancer_death = all_sites$cancer_death,
death = all_sites$death,
pys = all_sites$pys,
risk_func = "amp",
ci_method = "gamma",
age_start = c(0, 50, 70),
age_end = Inf,
digits = 4
)
#> start end risk lower upper
#> 1 0 Inf 33.2386 33.1989 33.2784
#> 2 50 Inf 32.1052 32.0634 32.1470
#> 3 70 Inf 23.3479 23.3008 23.3951
Traditional cumulative risk can be calculated directly with calc_ltr()
by setting risk_func = "cumulative", or with the lower-level
cumulative() and get_risk() workflow. Unlike DevCan, Wun, or AMP,
this approach does not account for competing mortality.
calc_ltr(
ages = all_sites$ages,
cancer = all_sites$cancer,
cancer_death = all_sites$cancer_death,
death = all_sites$death,
pys = all_sites$pys,
risk_func = "cumulative",
type = "developing",
maj_method = "constant",
ci_method = "delta",
age_start = 0,
age_end = c(75, 85),
digits = 4
)
#> start end risk lower upper
#> 1 0 75 31.9419 31.9007 31.9831
#> 2 0 85 42.4122 42.3572 42.4673
cumu_developing <- cumulative(
ages = all_sites$ages,
cancer = all_sites$cancer,
cancer_death = all_sites$cancer_death,
death = all_sites$death,
pys = all_sites$pys,
type = "developing",
maj_method = "constant"
)
get_risk(cumu_developing, age_start = 0, age_end = c(75, 85))
#> [1] 0.3194190 0.4241222
For a detailed introduction to the implemented methods, confidence interval calculations, and additional examples, see the package vignette:
vignette("use-ltRISK", package = "ltRISK")