Requirements on Presence and Absence

library(CohortConstructor)
library(CohortCharacteristics)
library(ggplot2)

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

con <- DBI::dbConnect(duckdb::duckdb(), dbdir = eunomia_dir())
cdm <- cdm_from_con(con, cdm_schema = "main", 
                    write_schema = c(prefix = "my_study_", schema = "main"))

Let’s start by creating two drug cohorts, one for users of diclofenac and another for users of acetaminophen.

cdm$medications <- conceptCohort(cdm = cdm, 
                                 conceptSet = list("diclofenac" = 1124300,
                                                   "acetaminophen" = 1127433), 
                                 name = "medications")
cohortCount(cdm$medications)
#> # A tibble: 2 × 3
#>   cohort_definition_id number_records number_subjects
#>                  <int>          <int>           <int>
#> 1                    1           9365            2580
#> 2                    2            830             830

As well as our medication cohorts, 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" = 192671),
                              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, requiring that individuals have one or more intersections with the GI bleed cohort.

cdm$medications_gi_bleed <- cdm$medications  %>%
  requireCohortIntersect(intersections = c(1,Inf),
                         targetCohortTable = "gi_bleed", 
                         targetCohortId = 1,
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "medications_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$medications_gi_bleed)
plotCohortAttrition(summary_attrition, cohortId = 1)

The flow chart above illustrates the changes to cohort 1 (users of acetaminophen) when restricted to only include individuals who intersect with the GI bleed cohort at least once before the cohort start date. 2,296 individuals and 8,765 records were excluded.

Instead of requiring that individuals intersect with the GI bleed cohort, we could instead require that they don’t intersect with it. In this case we can again use the requireCohortIntersect() function, but this time set the intersections argument to 0 to require individuals’ absence in this other cohort rather than their presence in it.

cdm$medications_no_gi_bleed <- cdm$medications %>%
  requireCohortIntersect(intersections = 0,
                         targetCohortTable = "gi_bleed", 
                         targetCohortId = 1,
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "medications_no_gi_bleed") 

summary_attrition <- summariseCohortAttrition(cdm$medications_no_gi_bleed)
plotCohortAttrition(summary_attrition, cohortId = 1)

The flow chart above illustrates the changes to cohort 1 when restricted to only include individuals with no intersects with the GI bleed cohort before the cohort start date. 36 individuals and 600 records were excluded.

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$medications_gi_bleed <- cdm$medications  %>%
  requireConceptIntersect(conceptSet = list("gi_bleed" = 192671), 
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "medications_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$medications_gi_bleed)
plotCohortAttrition(summary_attrition, cohortId = 1)

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$medications_no_gi_bleed <- cdm$medications  %>%
  requireConceptIntersect(intersections = 0,
                         conceptSet = list("gi_bleed" = 192671), 
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "medications_no_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$medications_no_gi_bleed)
plotCohortAttrition(summary_attrition, cohortId = 1)

The flow chart above illustrates the changes to cohort 1 when restricted to only include individuals who have not had events of GI bleeding before the cohort start date. 36 individuals and 600 records were excluded.

Restrictions on presence in clinical tables

A clinical table is a table which contains ‘raw’ clinical data. We can use clinical tables to filter our cohorts using the requireTableIntersect() function. This will allow us to filter individuals in the medications cohort based on whether they have intersections with the GI bleed clinical table or not.

cdm$medications_gi_bleed <- cdm$medications  %>%
  requireTableIntersect(tableName = "gi_bleed",
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "medications_gi_bleed")

summary_attrition <- summariseCohortAttrition(cdm$medications_gi_bleed)
plotCohortAttrition(summary_attrition, cohortId = 1)

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

Instead of requiring that individuals intersect with the GI bleed clinical table, we could instead require that they don’t intersect with it. In this case we can again use the requireCohortIntersect() function, but this time set the intersections argument to 0 to require individuals’ absence in the GI bleed clinical table.

cdm$medications_no_gi_bleed <- cdm$medications  %>%
  requireTableIntersect(tableName = "gi_bleed",
                         indexDate = "cohort_start_date", 
                         window = c(-Inf, 0), 
                         name = "medications_no_gi_bleed",
                        intersections = 0)

summary_attrition <- summariseCohortAttrition(cdm$medications_no_gi_bleed)
plotCohortAttrition(summary_attrition, cohortId = 1)

The flow chart above illustrates the changes to cohort 1 when restricted to only include individuals who have no intersects with the GI bleeding clinical table before the cohort start date. 36 individuals and 600 records were excluded.

Restrictions on deaths

We could require that individuals in our medication cohorts are seen to have (or not have) a death. To do this we can use the requireDeathFlag() function, requiring that individuals are seen (or not seen) to have died after the cohort start date.

cdm$medications_deaths <- cdm$medications  %>%
  requireDeathFlag(window = c(0,Inf), 
                         name = "medications_deaths")

summary_attrition <- summariseCohortAttrition(cdm$medications_deaths)
plotCohortAttrition(summary_attrition, cohortId = 1)

The flow chart above illustrates the changes to cohort 1 when restricted to only include individuals who died after the cohort start date. None of the individuals in cohort 1 died and therefore they are all excluded from this cohort.

To exclude individuals who died we add the argument ‘negate = TRUE’ to the function requireDeathFlag().

cdm$medications_no_deaths <- cdm$medications  %>%
  requireDeathFlag(window = c(0,Inf), 
                   name = "medications_no_deaths",
                   negate = TRUE)

summary_attrition <- summariseCohortAttrition(cdm$medications_no_deaths)
plotCohortAttrition(summary_attrition, cohortId = 1)

The flow chart above illustrates the changes to cohort 1 when restricted to only include individuals who did not die after the cohort start date. None of the individuals in cohort 1 died and therefore no one was excluded.