Applying requirements related to other cohorts, concept sets, or tables

library(CodelistGenerator)
library(CohortConstructor)
library(CohortCharacteristics)
library(visOmopResults)
library(ggplot2)

For this example we’ll use the Eunomia synthetic data from the CDMConnector package.

con <- DBI::dbConnect(duckdb::duckdb(), dbdir = eunomiaDir())
cdm <- CDMConnector::cdmFromCon(con, cdmSchema = "main", 
                    writeSchema = "main", writePrefix = "my_study_")

Let’s start by creating a cohort of warfarin users.

warfarin_codes <- getDrugIngredientCodes(cdm, "warfarin")
cdm$warfarin <- conceptCohort(cdm = cdm, 
                                 conceptSet = warfarin_codes, 
                                 name = "warfarin")
cohortCount(cdm$warfarin)
#> # A tibble: 1 × 3
#>   cohort_definition_id number_records number_subjects
#>                  <int>          <int>           <int>
#> 1                    1            137             137

As well as our warfarin cohort, let’s also make another cohort containing individuals with a record of a GI bleed. Later we’ll use this cohort when specifying inclusion/ exclusion criteria.

cdm$gi_bleed <- conceptCohort(cdm = cdm,  
                              conceptSet = list("gi_bleed" = 192671L),
                              name = "gi_bleed")

Restrictions on cohort presence

We could require that individuals in our medication cohorts are seen (or not seen) in another cohort. To do this we can use the requireCohortIntersect() function. Here, for example, we require that individuals have one or more intersections with the GI bleed cohort.

cdm$warfarin_gi_bleed <- cdm$warfarin  |>
  requireCohortIntersect(intersections = c(1,Inf),
                         targetCohortTable = "gi_bleed", 
                         targetCohortId = 1,
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "warfarin_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$warfarin_gi_bleed)
plotCohortAttrition(summary_attrition)
%0 1->2 2->3 3->4 4->5 7->6 9->8 11->10 13->12 1 Initial events N subjects = 137 N records = 137 2 N subjects = 137 N records = 137 3 N subjects = 137 N records = 137 4 N subjects = 137 N records = 137 5 Final events N subjects = 26 N records = 26 6 N subjects = 0 N records = 0 7 Record start <= record end 8 N subjects = 0 N records = 0 9 Record in observation 10 N subjects = 0 N records = 0 11 Merge overlapping records 12 N subjects = 111 N records = 111 13 In cohort gi_bleed between -Inf & 0 days relative to cohort_start_date between 1 and Inf times

The flow chart above illustrates the changes to the cohort of users of acetaminophen when restricted to only include individuals who have at least one record in the GI bleed cohort before their start date for acetaminophen.

Instead of requiring that individuals have a record in the GI bleed cohort, we could instead require that they don’t. In this case we can again use the requireCohortIntersect() function, but this time we set the intersections argument to 0 so as to require individuals’ absence in this other cohort.

cdm$warfarin_no_gi_bleed <- cdm$warfarin |>
  requireCohortIntersect(intersections = 0,
                         targetCohortTable = "gi_bleed", 
                         targetCohortId = 1,
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "warfarin_no_gi_bleed") 

summary_attrition <- summariseCohortAttrition(cdm$warfarin_no_gi_bleed)
plotCohortAttrition(summary_attrition)
%0 1->2 2->3 3->4 4->5 7->6 9->8 11->10 13->12 1 Initial events N subjects = 137 N records = 137 2 N subjects = 137 N records = 137 3 N subjects = 137 N records = 137 4 N subjects = 137 N records = 137 5 Final events N subjects = 111 N records = 111 6 N subjects = 0 N records = 0 7 Record start <= record end 8 N subjects = 0 N records = 0 9 Record in observation 10 N subjects = 0 N records = 0 11 Merge overlapping records 12 N subjects = 26 N records = 26 13 Not in cohort gi_bleed between -Inf & 0 days relative to cohort_start_date

Restrictions on concept presence

We could require that individuals in our medication cohorts have been seen (or not seen) to have events related to a concept list. To do this we can use the requireConceptIntersect() function, allowing us to filter our cohort based on whether they have or have not had events of GI bleeding before they entered the cohort.

cdm$warfarin_gi_bleed <- cdm$warfarin  |>
  requireConceptIntersect(conceptSet = list("gi_bleed" = 192671), 
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "warfarin_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$warfarin_gi_bleed)
plotCohortAttrition(summary_attrition)
%0 1->2 2->3 3->4 4->5 7->6 9->8 11->10 13->12 1 Initial events N subjects = 137 N records = 137 2 N subjects = 137 N records = 137 3 N subjects = 137 N records = 137 4 N subjects = 137 N records = 137 5 Final events N subjects = 26 N records = 26 6 N subjects = 0 N records = 0 7 Record start <= record end 8 N subjects = 0 N records = 0 9 Record in observation 10 N subjects = 0 N records = 0 11 Merge overlapping records 12 N subjects = 111 N records = 111 13 Concept gi_bleed between -Inf & 0 days relative to cohort_start_date between 1 and Inf

The flow chart above illustrates the changes to cohort 1 when restricted to only include individuals who have had events of GI bleeding at least once before the cohort start date. 2,296 individuals and 8,765 records were excluded.

Instead of requiring that individuals have events of GI bleeding, we could instead require that they don’t have any events of it. In this case we can again use the requireConceptIntersect() function, but this time set the intersections argument to 0 to require individuals without past events of GI bleeding.

cdm$warfarin_no_gi_bleed <- cdm$warfarin  |>
  requireConceptIntersect(intersections = 0,
                         conceptSet = list("gi_bleed" = 192671), 
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "warfarin_no_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$warfarin_no_gi_bleed)
plotCohortAttrition(summary_attrition)
%0 1->2 2->3 3->4 4->5 7->6 9->8 11->10 13->12 1 Initial events N subjects = 137 N records = 137 2 N subjects = 137 N records = 137 3 N subjects = 137 N records = 137 4 N subjects = 137 N records = 137 5 Final events N subjects = 111 N records = 111 6 N subjects = 0 N records = 0 7 Record start <= record end 8 N subjects = 0 N records = 0 9 Record in observation 10 N subjects = 0 N records = 0 11 Merge overlapping records 12 N subjects = 26 N records = 26 13 Not in concept gi_bleed between -Inf & 0 days relative to cohort_start_date

Restrictions on presence in clinical tables

We can also impose requirements around individuals presence (or absence) in clinical tables in the OMOP CDM using the requireTableIntersect() function. Here for example we reuire that individuals in our warfarin cohort have at least one prior record in the visit occurrence table.

cdm$warfarin_visit <- cdm$warfarin  |>
  requireTableIntersect(tableName = "visit_occurrence",
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, -1), 
                         name = "warfarin_visit")

summary_attrition <- summariseCohortAttrition(cdm$warfarin_visit)
plotCohortAttrition(summary_attrition)
%0 1->2 2->3 3->4 4->5 7->6 9->8 11->10 13->12 1 Initial events N subjects = 137 N records = 137 2 N subjects = 137 N records = 137 3 N subjects = 137 N records = 137 4 N subjects = 137 N records = 137 5 Final events N subjects = 49 N records = 49 6 N subjects = 0 N records = 0 7 Record start <= record end 8 N subjects = 0 N records = 0 9 Record in observation 10 N subjects = 0 N records = 0 11 Merge overlapping records 12 N subjects = 88 N records = 88 13 In table visit_occurrence between -Inf & -1 days relative to cohort_start_date between 1 and Inf