This document contains the algorithms necessary to code all the outcomes which measure “abstinence from substance use” or “relapse to substance use”. We only include outcomes which result in a single value per subject. These outcomes are:
Group | Endpoint | Class | Reference | Definition | Missing is |
---|---|---|---|---|---|
Relapse | Time to relapse | survival | CTN-0094 | Weeks to relapse (4 consecutive weeks of positive UOS) | Positive |
Relapse | Time to study dropout | survival | CTN-0094 | Weeks to study dropout (4 consecutive weeks of missing UOS) | Missing |
Relapse | Relapse/failure rate | logical | Johnson, Jaffe, & Fudala, 1992 | Failure rate: 2 consecutive positive UOS following 4 weeks of treatment | Positive |
Relapse | Relapse/failure rate | logical | Krupitsky et al., 2004 | Relapse rate (3 consecutive positive UOS) | Positive |
Relapse | Relapse/failure rate | logical | Krupitsky et al., 2006 | Relapse rate (3 consecutive positive UOS) | Positive |
Relapse | Time to opioid use/relapse | survival | Lee et al., 2016 | Weeks to relapse (≥10 days of opioid use in a 28‐day period [a positive UOS was computed as 5 days of opioid use]) | Positive |
Relapse | Time to opioid use/relapse | survival | Lee et al., 2018 CTN-0051 | Weeks to relapse (starting at day 21 post-randomization: 4 consecutive weeks with positive UOS) | Positive |
Relapse | Time to opioid use/relapse | survival | Schottenfeld et al., 2008 | Days to relapse (3 consecutive positive UOS) | Positive |
We will use the table of participant opioid use patterns from the
ctn0094DataExtra
package to calculate these endpoints (we
have a copy of the endpoints in the dataset
outcomesCTN0094
). Importantly, if you wish to apply these
algorithms to calculate endpoints for your data, the participants’
substance use patterns must be stored in the “substance use pattern
word” format shown here. We also show a subset of the data to visualize
a variety of different real substance use patterns.
We first define the following five-value legend:
### Full Data ###
udsOutcomes_df <-
CTNote::outcomesCTN0094 %>%
select(who, usePatternUDS)
# Make a copy
outcomesRel_df <- udsOutcomes_df
### Examples ###
examplePeople_int <- c(1, 163, 210, 242, 4, 17, 13, 1103, 233, 2089)
outcomesRel_df %>%
filter(who %in% examplePeople_int)
## # A tibble: 10 × 2
## who usePatternUDS
## <dbl> <chr>
## 1 1 ooooooooooooooo
## 2 4 -------------------o-o-o
## 3 13 ------------o-oooooooooo
## 4 17 --++*++++++-++++++-+++-
## 5 163 -o---o---o--o+----------
## 6 210 -++++++++-+++-----------
## 7 233 *+++++++++++o++++++++++o
## 8 242 -----------------------
## 9 1103 ++--oo--o-+-+--o----------o-o-oo++o
## 10 2089 ++++---+--------------o-
For example, participant 1 has a use pattern
ooooooooooooooo
(all missing UDS), which means that they
dropped out of the study. In contrast, participant 233 has a use pattern
*+++++++++++o++++++++++o
(nearly all positive UDS): they
did not drop out of the study, but the treatment was completely
ineffective for them. Participant 2089 started the study in a rough
patch, but greatly improved in treatment over time
(++++---+--------------o-
).
Our CTN-0094 research group has two relapse outcomes: Weeks to relapse (4 consecutive weeks of positive UOS) and Weeks to study dropout (4 consecutive weeks of missing UOS).
Definition: Weeks to relapse (4 consecutive weeks of positive UOS); missing is positive
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = usePatternUDS
)
) %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = udsPattern,
missing_is = "*"
)
) %>%
mutate(
ctn0094_relapse = detect_in_window(
use_pattern = udsPattern,
window_width = 4L,
threshold = 4L
)
) %>%
unnest(cols = "ctn0094_relapse", names_sep = "_") %>%
select(who, starts_with("ctn0094_relapse")) %>%
rename(
RsT_ctnNinetyFour_2023 = ctn0094_relapse_time,
RsE_ctnNinetyFour_2023 = ctn0094_relapse_event
) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, RsT_ctnNinetyFour_2023, RsE_ctnNinetyFour_2023)
## # A tibble: 10 × 4
## who usePatternUDS RsT_ctnNinetyFour_2023 RsE_ctnNinetyFour_2023
## <dbl> <chr> <int> <int>
## 1 1 ooooooooooooooo 1 1
## 2 4 -------------------o-o-o 21 0
## 3 13 ------------o-oooooooooo 15 1
## 4 17 --++*++++++-++++++-+++- 3 1
## 5 163 -o---o---o--o+---------- 21 0
## 6 210 -++++++++-+++----------- 2 1
## 7 233 *+++++++++++o++++++++++o 1 1
## 8 242 ----------------------- 20 0
## 9 1103 ++--oo--o-+-+--o--------… 31 1
## 10 2089 ++++---+--------------o- 1 1
Definition: Weeks to study dropout (4 consecutive weeks of missing UOS)
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
# do NOT recode any missing visits
mutate(
ctn0094_dropout = detect_in_window(
use_pattern = usePatternUDS,
window_width = 4L,
threshold = 4L,
match_is = "o"
)
) %>%
unnest(cols = "ctn0094_dropout", names_sep = "_") %>%
select(who, starts_with("ctn0094_dropout")) %>%
rename(
DrT_ctnNinetyFour_2023 = ctn0094_dropout_time,
DrE_ctnNinetyFour_2023 = ctn0094_dropout_event
) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, DrT_ctnNinetyFour_2023, DrE_ctnNinetyFour_2023)
## # A tibble: 10 × 4
## who usePatternUDS DrT_ctnNinetyFour_2023 DrE_ctnNinetyFour_2023
## <dbl> <chr> <int> <int>
## 1 1 ooooooooooooooo 1 1
## 2 4 -------------------o-o-o 21 0
## 3 13 ------------o-oooooooooo 15 1
## 4 17 --++*++++++-++++++-+++- 20 0
## 5 163 -o---o---o--o+---------- 21 0
## 6 210 -++++++++-+++----------- 21 0
## 7 233 *+++++++++++o++++++++++o 21 0
## 8 242 ----------------------- 20 0
## 9 1103 ++--oo--o-+-+--o--------… 32 0
## 10 2089 ++++---+--------------o- 21 0
Definition: Failure rate: 2 consecutive positive UOS following 4 weeks of treatment; missing is positive
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = usePatternUDS,
)
) %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = udsPattern,
missing_is = "*"
)
) %>%
mutate(
Rs_johnson_1992 = detect_subpattern(
use_pattern = udsPattern,
subpattern = "++",
# Starting at 4 weeks of treatment
start = 4L
)
) %>%
select(who, Rs_johnson_1992) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, Rs_johnson_1992)
## # A tibble: 10 × 3
## who usePatternUDS Rs_johnson_1992
## <dbl> <chr> <lgl>
## 1 1 ooooooooooooooo TRUE
## 2 4 -------------------o-o-o FALSE
## 3 13 ------------o-oooooooooo TRUE
## 4 17 --++*++++++-++++++-+++- TRUE
## 5 163 -o---o---o--o+---------- TRUE
## 6 210 -++++++++-+++----------- TRUE
## 7 233 *+++++++++++o++++++++++o TRUE
## 8 242 ----------------------- FALSE
## 9 1103 ++--oo--o-+-+--o----------o-o-oo++o TRUE
## 10 2089 ++++---+--------------o- FALSE
Definition: Relapse rate (3 consecutive positive UOS); missing is positive (their papers do not explicitly state what to do with missing UDS, but their previous protocols treated missing as positive).
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = usePatternUDS,
)
) %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = udsPattern,
missing_is = "*"
)
) %>%
mutate(
Rs_krupitsky_2004 = detect_subpattern(
use_pattern = udsPattern,
subpattern = "+++"
)
) %>%
select(who, Rs_krupitsky_2004) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, Rs_krupitsky_2004)
## # A tibble: 10 × 3
## who usePatternUDS Rs_krupitsky_2004
## <dbl> <chr> <lgl>
## 1 1 ooooooooooooooo TRUE
## 2 4 -------------------o-o-o FALSE
## 3 13 ------------o-oooooooooo TRUE
## 4 17 --++*++++++-++++++-+++- TRUE
## 5 163 -o---o---o--o+---------- FALSE
## 6 210 -++++++++-+++----------- TRUE
## 7 233 *+++++++++++o++++++++++o TRUE
## 8 242 ----------------------- FALSE
## 9 1103 ++--oo--o-+-+--o----------o-o-oo++o TRUE
## 10 2089 ++++---+--------------o- TRUE
Definition: Weeks to relapse (≥10 days of opioid use in a 28‐day period [a positive UOS was computed as 5 days of opioid use]); missing is positive
We interpret their outcome as “two or more positive weekly UDS in a 4-week window”.
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = usePatternUDS
)
) %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = udsPattern,
missing_is = "*"
)
) %>%
mutate(
lee2016_rel = detect_in_window(
use_pattern = udsPattern,
window_width = 4L,
threshold = 2L
)
) %>%
unnest(cols = "lee2016_rel", names_sep = "_") %>%
select(who, starts_with("lee2016_rel")) %>%
rename(
RsT_lee_2016 = lee2016_rel_time,
RsE_lee_2016 = lee2016_rel_event
) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, contains("lee_2016"))
## # A tibble: 10 × 4
## who usePatternUDS RsT_lee_2016 RsE_lee_2016
## <dbl> <chr> <int> <int>
## 1 1 ooooooooooooooo 3 1
## 2 4 -------------------o-o-o 21 1
## 3 13 ------------o-oooooooooo 14 1
## 4 17 --++*++++++-++++++-+++- 3 1
## 5 163 -o---o---o--o+---------- 12 1
## 6 210 -++++++++-+++----------- 3 1
## 7 233 *+++++++++++o++++++++++o 3 1
## 8 242 ----------------------- 22 0
## 9 1103 ++--oo--o-+-+--o----------o-o-oo++o 3 1
## 10 2089 ++++---+--------------o- 3 1
Definition: Weeks to relapse (starting at day 21 post-randomization: 4 consecutive weeks with positive UOS); missing is positive
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = usePatternUDS
)
) %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = udsPattern,
missing_is = "*"
)
) %>%
mutate(
udsPatternTrimmed = str_sub(udsPattern, start = 3L)
) %>%
rowwise() %>%
mutate(
lee2018_rel = detect_in_window(
use_pattern = udsPatternTrimmed,
window_width = 4L,
threshold = 4L
)
) %>%
unnest(cols = "lee2018_rel", names_sep = "_") %>%
mutate(lee2018_rel_time = lee2018_rel_time + 2) %>%
select(who, starts_with("lee2018_rel")) %>%
rename(
RsT_ctnFiftyOne_2018 = lee2018_rel_time,
RsE_ctnFiftyOne_2018 = lee2018_rel_event
) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, contains("ctnFiftyOne_2018"))
## # A tibble: 10 × 4
## who usePatternUDS RsT_ctnFiftyOne_2018 RsE_ctnFiftyOne_2018
## <dbl> <chr> <dbl> <int>
## 1 1 ooooooooooooooo 3 1
## 2 4 -------------------o-o-o 21 0
## 3 13 ------------o-oooooooooo 15 1
## 4 17 --++*++++++-++++++-+++- 3 1
## 5 163 -o---o---o--o+---------- 21 0
## 6 210 -++++++++-+++----------- 3 1
## 7 233 *+++++++++++o++++++++++o 3 1
## 8 242 ----------------------- 20 0
## 9 1103 ++--oo--o-+-+--o----------o-… 31 1
## 10 2089 ++++---+--------------o- 21 0
Definition: Days to relapse (3 consecutive positive UOS); missing is positive
outcomesRel_df <-
outcomesRel_df %>%
rowwise() %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = usePatternUDS
)
) %>%
mutate(
udsPattern = recode_missing_visits(
use_pattern = udsPattern,
missing_is = "*"
)
) %>%
mutate(
schottenfeld2008_rel = detect_in_window(
use_pattern = udsPattern,
window_width = 3L,
threshold = 3L
)
) %>%
unnest(cols = "schottenfeld2008_rel", names_sep = "_") %>%
select(who, starts_with("schottenfeld2008_rel")) %>%
rename(
RsT_schottenfeld_2008 = schottenfeld2008_rel_time,
RsE_schottenfeld_2008 = schottenfeld2008_rel_event
) %>%
left_join(outcomesRel_df, ., by = "who")
outcomesRel_df %>%
filter(who %in% examplePeople_int) %>%
select(who, usePatternUDS, contains("schottenfeld_2008"))
## # A tibble: 10 × 4
## who usePatternUDS RsT_schottenfeld_2008 RsE_schottenfeld_2008
## <dbl> <chr> <int> <int>
## 1 1 ooooooooooooooo 1 1
## 2 4 -------------------o-o-o 22 0
## 3 13 ------------o-oooooooooo 15 1
## 4 17 --++*++++++-++++++-+++- 3 1
## 5 163 -o---o---o--o+---------- 22 0
## 6 210 -++++++++-+++----------- 2 1
## 7 233 *+++++++++++o++++++++++o 1 1
## 8 242 ----------------------- 21 0
## 9 1103 ++--oo--o-+-+--o----------… 31 1
## 10 2089 ++++---+--------------o- 1 1
Here is the information concerning the system configuration, packages, and their versions used in this computation:
## R version 4.4.2 (2024-10-31)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] lubridate_1.9.3 forcats_1.0.0 stringr_1.5.1 dplyr_1.1.4
## [5] purrr_1.0.2 readr_2.1.5 tidyr_1.3.1 tibble_3.2.1
## [9] ggplot2_3.5.1 tidyverse_2.0.0 kableExtra_1.4.0 readxl_1.4.3
## [13] CTNote_0.1.3 rmarkdown_2.29
##
## loaded via a namespace (and not attached):
## [1] sass_0.4.9 utf8_1.2.4 generics_0.1.3 xml2_1.3.6
## [5] lattice_0.22-6 stringi_1.8.4 hms_1.1.3 digest_0.6.37
## [9] magrittr_2.0.3 timechange_0.3.0 evaluate_1.0.1 grid_4.4.2
## [13] fastmap_1.2.0 Matrix_1.7-1 cellranger_1.1.0 jsonlite_1.8.9
## [17] survival_3.7-0 fansi_1.0.6 viridisLite_0.4.2 scales_1.3.0
## [21] jquerylib_0.1.4 cli_3.6.3 rlang_1.1.4 splines_4.4.2
## [25] munsell_0.5.1 withr_3.0.2 cachem_1.1.0 yaml_2.3.10
## [29] tools_4.4.2 tzdb_0.4.0 colorspace_2.1-1 buildtools_1.0.0
## [33] vctrs_0.6.5 R6_2.5.1 lifecycle_1.0.4 pkgconfig_2.0.3
## [37] bslib_0.8.0 pillar_1.9.0 gtable_0.3.6 glue_1.8.0
## [41] systemfonts_1.1.0 xfun_0.49 tidyselect_1.2.1 rstudioapi_0.17.1
## [45] sys_3.4.3 knitr_1.49 htmltools_0.5.8.1 svglite_2.1.3
## [49] maketools_1.3.1 compiler_4.4.2