The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Extraction

Overview

Phase 1 derives stratified prevalence tables from the records in an OMOP CDM database. The main entry point is extract_all(), which runs the full pipeline for one or more clinical domains.

Each domain produces 4 tables:

Table Content Key columns
*_prevalence Patient counts per concept x year x sex x age group concept_id, year, sex, age_group, patient_count, denominator, prevalence
*_info Concept metadata concept_id, concept_name, vocabulary_id, n_patients_total
*_chapters Hierarchy-based chapter assignments concept_id, chapter_type, chapter_id, chapter_name
*_attributes SNOMED relationship targets concept_id, relationship, target_concept_id, target_concept_name

Plus two shared tables: demographics (birth year x sex) and death_counts (deaths by stratum).

Connecting to a database

Syrona connects through CDMConnector. A production OMOP CDM is normally a PostgreSQL database, so syrona_connect_pg() is the main entry point; syrona_connect() opens a local DuckDB file (for example an Eunomia or Synthea test dataset).

PostgreSQL database

library(syrona)

# Direct connection
db <- syrona_connect_pg(
  host = "db-server.example.com",
  dbname = "omop",
  user = "analyst",
  cdm_schema = "cdm",
  write_schema = "results_analyst"
)

# Via SSH tunnel (start tunnel first: ssh -L 5432:localhost:5432 user@server)
db <- syrona_connect_pg(
  host = "localhost",
  dbname = "omop",
  user = "analyst",
  cdm_schema = "ohdsi_cdm_202511",
  write_schema = "results_analyst"
)

Credentials. You can pass password = "..." directly, but it is cleaner to omit it and let RPostgres read the password from a ~/.pgpass file or the PGPASSWORD environment variable — for example, set PGPASSWORD=... in your ~/.Renviron. This keeps the password out of your R scripts and command history.

The write_schema parameter tells CDMConnector where it can create temporary tables. This is required for cohort operations and some extraction queries. On PostgreSQL, this is typically a user-specific results schema.

DuckDB (local files)

# Read-only (default) - safe for shared databases
db <- syrona_connect("path/to/omop.duckdb")

# Writable - needed if you want to create cohort tables in the same DB
db <- syrona_connect("path/to/omop.duckdb", read_only = FALSE)

Running extraction

All domains (default)

tables <- extract_all("Dataset_A", db = db)

This extracts conditions, procedures, and drugs. Results are saved to data/sources/Dataset_A/ and returned as a named list.

Single domain

# Conditions only (fastest)
tables <- extract_all("Dataset_A", db = db, domains = "conditions")

# Drugs only
tables <- extract_all("Dataset_A", db = db, domains = "drugs")

# Conditions + procedures (no drugs)
tables <- extract_all("Dataset_A", db = db, domains = c("conditions", "procedures"))

Shorthand: pass a DuckDB path directly

# This connects, extracts, and disconnects automatically
tables <- extract_all("Synthetic", db = "path/to/omop.duckdb")

What each extractor does

Denominators (ACHILLES-116)

extract_denominators() computes the number of persons observed per year x sex x age group. This is the denominator for all prevalence calculations. A person is counted in a year if their observation period overlaps that year.

Age groups are 10-year decades (0-9, 10-19, …, 70-79, 80+). Ages above 80 are clamped into a single group for statistical stability.

Condition prevalence (ACHILLES-404)

extract_condition_prevalence() counts persons with at least one condition occurrence per concept x year x sex x age group. Events must fall within the person’s observation period. Only standard SNOMED concepts (concept_id != 0) are included.

Condition chapters

extract_condition_chapters() assigns each condition concept to chapters via three classification systems:

A concept can belong to multiple chapters. Concepts without an ICD-10 mapping get an “(Unmapped)” pseudo-chapter.

Drug prevalence

extract_drug_prevalence() rolls up drug exposures to the Ingredient level via concept_ancestor. This means a prescription for “Aspirin 100mg tablet” counts toward the “Aspirin” ingredient. One row per ingredient x year x sex x age group.

Drug chapters

extract_drug_chapters() assigns each ingredient to ATC 1st level chapters (e.g. “A. Alimentary tract and metabolism”) via concept_ancestor.

Procedure chapters

extract_procedure_chapters() assigns procedures to two SNOMED hierarchies:

k-Anonymity

After extraction, apply_k_anonymity() suppresses small-cell counts (default k=5):

  1. Concepts with fewer than k total patients are dropped entirely
  2. Individual prevalence rows (strata) with fewer than k patients are suppressed
  3. Concepts that lose all prevalence rows to suppression are moved to a *_rare table (keeps aggregate counts but no stratified data)

This ensures no individual can be identified from the output tables.

Loading and listing datasets

# List all extracted datasets
list_datasets()
#> [1] "Dataset_A" "Dataset_B" "Synthetic"

# Load a previously extracted dataset
d <- load_dataset("Dataset_A")
names(d)
#> [1] "condition_prevalence" "condition_info" "condition_chapters" ...

Disconnect

syrona_disconnect(db)

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.