Skip to contents

Build a cohort definition from clinical criteria and logical operators, then compile it to one DuckDB query (or run it into a cohort table) - the R mirror of omop_etl.phenotype_dsl in Python:

Usage

condition_criteria(
  concept_ids = NULL,
  icd_codes = NULL,
  icd_vocabularies = c("ICD9CM", "ICD10CM"),
  diagnosis = c("any", "primary", "secondary"),
  include_descendants = TRUE,
  min_occurrences = 1L,
  lookback_days = NULL,
  lookahead_days = NULL
)

measurement_criteria(
  concept_ids = NULL,
  loinc_codes = NULL,
  value_gte = NULL,
  value_gt = NULL,
  value_lte = NULL,
  value_lt = NULL,
  unit_concept_ids = NULL,
  include_descendants = FALSE,
  min_occurrences = 1L,
  lookback_days = NULL,
  lookahead_days = NULL
)

drug_criteria(
  concept_ids = NULL,
  atc_codes = NULL,
  min_days_supply = NULL,
  include_descendants = TRUE,
  min_occurrences = 1L,
  lookback_days = NULL,
  lookahead_days = NULL
)

Arguments

concept_ids

Standard concept ids (descendants are included via concept_ancestor when include_descendants = TRUE).

icd_codes

ICD-9/10 code prefixes ("E11" matches E11.9), matched against condition_source_value and the source concept's code.

icd_vocabularies

Vocabularies the source-concept match is restricted to.

diagnosis

"any", "primary" or "secondary" (via condition_status_concept_id).

include_descendants

Expand concept_ids through concept_ancestor.

min_occurrences

Require at least this many qualifying records; the index date is the n-th one.

lookback_days, lookahead_days

Window around the index table's date (requires index_table).

loinc_codes

LOINC codes, matched on measurement_source_value and the concept's code.

value_gte, value_gt, value_lte, value_lt

Thresholds on value_as_number (all must hold).

unit_concept_ids

Restrict measurements to these units.

atc_codes

ATC codes resolved through concept as additional ancestor concepts.

min_days_supply

Require days_supply (or end - start when unset) of at least this many days.

Details

t2dm <- condition_criteria(icd_codes = "E11", concept_ids = 201826) |
  measurement_criteria(loinc_codes = "4548-4", value_gte = 6.5) |
  drug_criteria(concept_ids = 21600712, min_days_supply = 30)
execute_phenotype(con, t2dm & !condition_criteria(icd_codes = "E10"), "cohort", cohort_definition_id = 7)

Criteria (condition_criteria(), measurement_criteria(), drug_criteria(), everyone()) are leaves; | / phenotype_union(), & / phenotype_intersect() and ! / phenotype_not() compose them.

Single pass. Every leaf emits (person_id, event_date, leaf) rows into one UNION ALL; one GROUP BY person_id computes each leaf's qualifying date with FILTER clauses, and the boolean tree is evaluated as one WHERE over those columns. No leaf is re-scanned per operator and no intermediate cohort tables are created.

Index date. A person's index date is the earliest qualifying event for a union, and the latest of the operands' qualifying dates for an intersection (the moment every criterion is first satisfied). ! only excludes. With index_table = the index date is that table's date instead, and a leaf's lookback_days / lookahead_days are measured relative to it: lookback only gives [index - n, index], lookahead only [index, index + m], both [index - n, index + m].