Accurately defining cohort entry and exit dates is crucial in
observational research to ensure the validity of study findings. The
CohortConstructor
package provides several functions to
adjust these dates based on specific criteria, and this vignette
demonstrates how to use them.
Functions to update cohort dates can be categorized into four groups:
Exit at Specific Date Functions: Adjust the cohort end date to predefined events (observation end and death date).
Cohort Entry or Exit Based on Other Date Columns: Modify cohort start or end dates to the earliest or latests from a set of date columns.
Trim Dates Functions: Restrict cohort entries based on demographic criteria or specific date ranges.
Pad Dates Functions: Adjust cohort start or end dates by adding or subtracting a specified number of days.
We’ll explore each category in the following sections.
First, we’ll connect to the Eunomia synthetic data and create a mock cohort of women in the database to use as example in the vignette.
library(CohortConstructor)
library(CohortCharacteristics)
library(PatientProfiles)
library(CDMConnector)
if (Sys.getenv("EUNOMIA_DATA_FOLDER") == ""){
Sys.setenv("EUNOMIA_DATA_FOLDER" = file.path(tempdir(), "eunomia"))}
if (!dir.exists(Sys.getenv("EUNOMIA_DATA_FOLDER"))){ dir.create(Sys.getenv("EUNOMIA_DATA_FOLDER"))
downloadEunomiaData()
}
con <- DBI::dbConnect(duckdb::duckdb(), dbdir = CDMConnector::eunomiaDir())
cdm <- CDMConnector::cdmFromCon(con, cdmSchema = "main",
writeSchema = "main", writePrefix = "my_study_")
cdm$cohort <- demographicsCohort(cdm = cdm, name = "cohort", sex = "Female")
#> ℹ Building new trimmed cohort
#> Adding demographics information
#> Creating initial cohort
#> Trim sex
#> ✔ Cohort trimmed
exitAtObservationEnd()
The exitAtObservationEnd()
function updates the cohort
end date to the end of the observation period for each subject. This
ensures that the cohort exit does not extend beyond the period during
which data is available for the subject.
As cohort entries cannot overlap, updating the end date to the observation end may result in overlapping records. In such cases, overlapping records are collapsed into a single entry (starting at the earliest entry and ending at the end of observation).
This function has an argument limitToCurrentPeriod
to
consider cases when a subject may have more than one observation period.
If limitToCurrentPeriod = TRUE
(default) end date will be
set to the end of the observation period where the record is registered.
If limitToCurrentPeriod = FALSE
, in addition to updating
the cohort end to the allocated observation end, cohort entries are
created for each of the subsequent observation periods.
exitAtDeath()
The exitAtDeath()
function sets the cohort end date to
the recorded death date of the subject.
By default, it keeps the end date of subjects who do not have a death
record unmodified; however, these can be dropped with the argument
requireDeath.
entryAtFirstDate()
The entryAtFirstDate()
function updates the cohort start
date to the earliest date among specified columns.
Next we want to set the entry date to the first of: diclofenac or acetaminophen prescriptions after cohort start, or cohort end date.
# create cohort with of drugs diclofenac and acetaminophen
cdm$medications <- conceptCohort(
cdm = cdm, name = "medications",
conceptSet = list("diclofenac" = 1124300, "acetaminophen" = 1127433)
)
#> Warning: ! `codelist` casted to integers.
#> ℹ Subsetting table drug_exposure using 2 concepts with domain: drug.
#> ℹ Combining tables.
#> ℹ Creating cohort attributes.
#> ℹ Applying cohort requirements.
#> ℹ Merging overlapping records.
#> ✔ Cohort medications created.
# add date first ocurrence of these drugs from index date
cdm$cohort_dates <- cdm$cohort |>
addCohortIntersectDate(
targetCohortTable = "medications",
nameStyle = "{cohort_name}",
name = "cohort_dates"
)
# set cohort start at the first ocurrence of one of the drugs, or the end date
cdm$cohort_entry_first <- cdm$cohort_dates |>
entryAtFirstDate(
dateColumns = c("diclofenac", "acetaminophen", "cohort_end_date"),
name = "cohort_entry_first"
)
#> Joining with `by = join_by(cohort_definition_id, subject_id, cohort_end_date)`
cdm$cohort_entry_first
#> # Source: table<my_study_cohort_entry_first> [?? x 7]
#> # Database: DuckDB v1.0.0 [eburn@Windows 10 x64:R 4.2.1/C:\Users\eburn\AppData\Local\Temp\RtmpUtkMzn\file75f018e4f08.duckdb]
#> cohort_definition_id subject_id cohort_start_date cohort_end_date
#> <int> <int> <date> <date>
#> 1 1 152 1976-09-10 2018-10-29
#> 2 1 177 2000-05-31 2019-05-13
#> 3 1 374 1986-04-06 2017-05-25
#> 4 1 390 1989-10-20 2019-06-05
#> 5 1 422 1976-12-08 2019-04-28
#> 6 1 431 1964-11-03 2018-09-28
#> 7 1 525 1994-09-07 2018-07-23
#> 8 1 689 2010-03-27 2019-04-21
#> 9 1 670 1977-09-15 2018-09-13
#> 10 1 730 1962-09-16 2018-12-16
#> # ℹ more rows
#> # ℹ 3 more variables: entry_reason <chr>, diclofenac <date>,
#> # acetaminophen <date>
entryAtLastDate()
The entryAtLastDate()
function works similarly to
entryAtFirstDate()
, however now the selected column is the
latest date among specified columns.
cdm$cohort_entry_last <- cdm$cohort_dates |>
entryAtLastDate(
dateColumns = c("diclofenac", "acetaminophen", "cohort_end_date"),
keepDateColumns = FALSE,
name = "cohort_entry_last"
)
cdm$cohort_entry_last
#> # Source: table<my_study_cohort_entry_last> [?? x 5]
#> # Database: DuckDB v1.0.0 [eburn@Windows 10 x64:R 4.2.1/C:\Users\eburn\AppData\Local\Temp\RtmpUtkMzn\file75f018e4f08.duckdb]
#> cohort_definition_id subject_id cohort_start_date cohort_end_date
#> <int> <int> <date> <date>
#> 1 1 409 2019-01-18 2019-01-18
#> 2 1 2876 2018-11-09 2018-11-09
#> 3 1 4359 2019-03-07 2019-03-07
#> 4 1 4480 2018-10-09 2018-10-09
#> 5 1 4649 2019-06-03 2019-06-03
#> 6 1 1478 2019-06-04 2019-06-04
#> 7 1 3025 2002-10-21 2002-10-21
#> 8 1 3759 2018-08-12 2018-08-12
#> 9 1 3929 2006-01-23 2006-01-23
#> 10 1 2771 2018-09-07 2018-09-07
#> # ℹ more rows
#> # ℹ 1 more variable: entry_reason <chr>
In this example, we set keepDateColumns
to FALSE, which
drops columns in dateColumns
.
exitAtFirstDate()
The exitAtFirstDate()
function updates the cohort end
date to the earliest date among specified columns.
For instance, next we want the exit to be observation end, except if there is a record of diclofenac or acetaminophen, in which case that would be the end:
cdm$cohort_exit_first <- cdm$cohort_dates |>
addFutureObservation(futureObservationType = "date", name = "cohort_exit_first") |>
exitAtFirstDate(
dateColumns = c("future_observation", "acetaminophen", "diclofenac"),
keepDateColumns = FALSE
)
cdm$cohort_exit_first
#> # Source: table<my_study_cohort_exit_first> [?? x 5]
#> # Database: DuckDB v1.0.0 [eburn@Windows 10 x64:R 4.2.1/C:\Users\eburn\AppData\Local\Temp\RtmpUtkMzn\file75f018e4f08.duckdb]
#> cohort_definition_id subject_id cohort_start_date cohort_end_date exit_reason
#> <int> <int> <date> <date> <chr>
#> 1 1 2909 1945-02-26 1952-03-21 acetaminop…
#> 2 1 5199 1962-01-16 1963-10-09 acetaminop…
#> 3 1 3533 1961-11-30 1994-10-09 acetaminop…
#> 4 1 1478 1961-03-21 1975-09-05 acetaminop…
#> 5 1 3759 1964-08-09 1982-08-05 acetaminop…
#> 6 1 4261 1922-03-12 1929-09-02 acetaminop…
#> 7 1 4738 1909-09-17 1922-12-17 acetaminop…
#> 8 1 1229 1954-05-15 1957-07-29 acetaminop…
#> 9 1 1791 1954-11-25 1963-05-14 acetaminop…
#> 10 1 2135 1948-02-02 1953-02-06 acetaminop…
#> # ℹ more rows
exitAtLastDate()
Similarly, the exitAtLastDate()
function sets the cohort
end date to the latest date among specified columns.
cdm$cohort_exit_last <- cdm$cohort_dates |>
exitAtLastDate(
dateColumns = c("cohort_end_date", "acetaminophen", "diclofenac"),
returnReason = FALSE,
keepDateColumns = FALSE,
name = "cohort_exit_last"
)
cdm$cohort_exit_last
#> # Source: table<my_study_cohort_exit_last> [?? x 4]
#> # Database: DuckDB v1.0.0 [eburn@Windows 10 x64:R 4.2.1/C:\Users\eburn\AppData\Local\Temp\RtmpUtkMzn\file75f018e4f08.duckdb]
#> cohort_definition_id subject_id cohort_start_date cohort_end_date
#> <int> <int> <date> <date>
#> 1 1 144 1974-12-20 2019-01-04
#> 2 1 1016 1967-06-14 2019-06-26
#> 3 1 1115 1948-07-05 2018-12-10
#> 4 1 5279 1946-01-27 2019-06-09
#> 5 1 2997 1981-10-04 2018-12-16
#> 6 1 3857 1944-01-05 2018-08-01
#> 7 1 4641 1967-07-13 2018-07-19
#> 8 1 5335 1958-08-22 2019-03-18
#> 9 1 1407 1967-11-11 2018-11-17
#> 10 1 212 1970-03-21 2019-05-11
#> # ℹ more rows
In this last example, the return cohort doesn’t have the specified
date columns, neither the “reason” column indicating which date was used
for entry/exit. These was set with the keepDateColumns
and
returnReason
arguments, common throughout the functions in
this category.
trimDemographics()
The trimDemographics()
function restricts the cohort
based on patient demographics. This means that cohort start and end
dates are moved (within the original cohort entry dates) to ensure that
individuals meet specific demographic criteria throughout their cohort
participation. If individuals do not satisfy the criteria at any point
during their cohort period, their records are excluded.
For instance, if we trim using an age range from 18 to 65, individuals will only contribute in the cohort form the day they are 18 or older, up to the day before turning 66 (or before if they leave the database).
trimToDateRange()
The trimToDateRange()
function confines cohort entry and
exit dates within a specified date range, ensuring that cohort periods
align with the defined timeframe. If only the start or end of a range is
required, the other can be set to NA
.
For example, to restrict cohort dates to be on or after January 1st, 2015:
padCohortStart()
The padCohortStart()
function adds (or subtracts) a
specified number of days to the cohort start date.
For example, to subtract 50 days from the cohort start date:
# Substract 50 days to cohort start
cdm$cohort <- cdm$cohort |> padCohortStart(days = -50, collapse = FALSE)
When subtracting days, it may result in cohort start dates preceding
the observation period start. By default, such entries are corrected to
the observation period start. To drop these entries instead, set the
padObservation
argument to FALSE.
Additionally, adjusting cohort start dates may lead to overlapping
entries for the same subject. The collapse
argument manages
this: if TRUE, merges overlapping entries into a single record with the
earliest start and latest end date (default), if FALSE retains only the
first of the overlapping entries.
padCohortEnd()
Similarly, the padCohortEnd()
function adjusts the
cohort end date by adding (or subtracting) a specified number of
days.
The example below adds 1000 days to cohort end date, while dropping records that are outside of observation after adding days.
cdm$cohort_pad <- cdm$cohort |>
padCohortEnd(days = 1000, padObservation = FALSE, name = "cohort_pad")
Additionally, days to add can also be specified with a numeric column in the cohort, which allows to add a specific number of days for each record:
padCohortDate()
The padCohortDate()
function provides a more flexible
approach by allowing adjustments to either the cohort start or end date
based on specified parameters. You can define which date to adjust
(cohortDate
), the reference date for the adjustment
(indexDate
), and the number of days to add or subtract.
For example, to set the cohort end date to be 365 days after the cohort start date:
For all these functions, the cohortId argument specifies which cohorts to modify. This allows for targeted adjustments without altering other cohorts. For instance, to add 10 days to the end date of the acetaminophen cohort and 20 days to the diclofenac cohort we can do the following: