Generador de datos sintéticos
Descripción del componente
Desde el proyecto IMPaCT-Data, y con la intención de poder disponer de diferentes conjuntos de datos clínicos sintéticos para poder utilizar con fines demostrativos en otros componentes, se ha creado una pequeña guía para poder generarlos.
Para ello, se va a utilizar la librería SynthaTM y las herramientas de ETL (Extract, Transform and Load) proporcionadas por OHDSI para cargar cohortes de pacientes en una base de datos con un modelo de datos OMOP.
Synthea
Para generar los datos sintéticos utilizaremos SyntheaTM patient generator.
SyntheaTM genera datos sintéticos a partir de la historia clínica de los pacientes. Su objetivo es crear datos realistas y de alta calidad relacionados con los pacientes y los registros de salud asociados sin restricciones de privacidad y seguridad.
Una de las mayores cualidades de SyntheaTM es contar con más de 90 módulos diferentes, cada uno de los cuales contiene modelos para diferentes enfermedades u observaciones médicas. Sin embargo, la mayoría de estos módulos tienen dependencias entre ellos, y no se recomienda restringir la búsqueda a un subconjunto de ellos.
Documentación técnica
Generación de datos sintéticos e importación en la base de datos
Prerequisitos
Instalar R/RStudio
Instalar Java
Una base de datos para subir los resultados. Para estos test se utilizará un PostgreSQL instalado via Docker.
services:
postgres:
image: postgres:16
container_name: postgres
restart: always
environment:
POSTGRES_USER: 'postgres'
POSTGRES_PASSWORD: 'lollypop'
POSTGRES_DB: 'demo_omop'
volumes:
- ./data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- beacon-network
- postgresql-network
pgadmin:
image: dpage/pgadmin4
restart: always
ports:
- "8080:80"
environment:
PGADMIN_DEFAULT_EMAIL: 'pgadmin'
PGADMIN_DEFAULT_PASSWORD: 'gnome'
depends_on:
- postgres
networks:
- postgresql-network
networks:
beacon-network:
postgresql-network:
Descargar la lista de vocabularios de OMOP-CDM
Generación de datos
Sigue las instrucciones oficiales para compilar Synthea (recomendamos v3.2.0) o descarga el fichero synthea-with-dependencies.jar
Para exportar los datos en formato CSV, deberemos modificar las propiedades de Synthea en el fichero synthea.properties (en caso de que no exista se debera crear) añadiendo la siguiente línea.
exporter.csv.export = true
El comando básico para generar los datos es el siguiente:
java -jar synthea-with-dependencies.jar -c synthea.properties -p 1000
Puedes generar diferentes tipos de datos con diferentes modulos de Synthea. Para ello se debe utilizar la opción -m con el nombre de los módulos elegidos. Comprueba la lista de módulos y algún ejemplo en la web.
Importar datos sintéticos a la base de datos relacional
Para importar los datos a la base de datos, utilizaremos el ETL Synthea repo.
Primero, instalaremos la librería einstall libcurl4-gnutls-devn R desde github. Para ello nos aseguraremos de tener instalados los siguiente paquetes:
sudo apt-get install libcurl4-gnutls-dev libfontconfig1-dev libharfbuzz-dev libfribidi-dev libtiff-dev libxml2-dev libssl-dev libpq-dev
Advertencia
Dado que ETL-Synthea requiere rJava, es posible que deba ejecutar R CMD javareconf para configurar las variables ambientales necesarias
Después abriremos la consola de R y ejecutaremos los siguientes comandos para instalar las librerías necesarias:
install.packages('devtools')
devtools::install_github("OHDSI/ETL-Synthea")
devtools::install_github("rstats-db/RPostgres")
install.packages("readr") # To read CSV files
install.packages("dplyr") # To manipulate data
Y después ejecutaremos el siguiente código:
# Load library
library(ETLSyntheaBuilder)
library(readr)
library(dplyr)
# Download drivers
DatabaseConnector::downloadJdbcDrivers('postgresql', '.')
# Connect to your database
cd <- DatabaseConnector::createConnectionDetails(
dbms = "postgresql",
server = "localhost/demo_omop",
user = "postgres",
password = "lollypop",
port = 5432,
pathToDriver = "./"
)
# Needed schemas creation
conn <- DatabaseConnector::connect(cd)
DatabaseConnector::executeSql(conn, "CREATE SCHEMA IF NOT EXISTS cdm")
DatabaseConnector::executeSql(conn, "CREATE SCHEMA IF NOT EXISTS vocabularies")
DatabaseConnector::executeSql(conn, "CREATE SCHEMA IF NOT EXISTS raw")
# OMOP-CDM Database configuration
syntheaSchema <- "raw"
syntheaVersion <- "3.2.0"
syntheaFileLoc <- "./output/csv"
cdmSchema <- "cdm"
cdmVersion <- "5.4"
vocabFileLoc <- "./vocabulary_download_v5_minimal"
vocab_path <- "./vocabulary_download_v5_minimal/"
# Create OMOP-CDM tables
ETLSyntheaBuilder::CreateCDMTables(connectionDetails = cd, cdmSchema = cdmSchema, cdmVersion = cdmVersion)
# Load OMOP vocabularies
ETLSyntheaBuilder::LoadVocabFromCsv(connectionDetails = cd, cdmSchema = cdmSchema, vocabFileLoc = vocabFileLoc)
# Load Synthea data
ETLSyntheaBuilder::CreateSyntheaTables(connectionDetails = cd, syntheaSchema = syntheaSchema, syntheaVersion = syntheaVersion)
ETLSyntheaBuilder::LoadSyntheaTables(connectionDetails = cd, syntheaSchema = syntheaSchema, syntheaFileLoc = syntheaFileLoc)
# Prepare ETL
ETLSyntheaBuilder::CreateMapAndRollupTables(connectionDetails = cd, cdmSchema = cdmSchema, syntheaSchema = syntheaSchema, cdmVersion = cdmVersion, syntheaVersion = syntheaVersion)
# Execute ETL
ETLSyntheaBuilder::LoadEventTables(connectionDetails = cd, cdmSchema = cdmSchema, syntheaSchema = syntheaSchema, cdmVersion = cdmVersion, syntheaVersion = syntheaVersion)
# Load Vocabularies into vocabularies schema
tables <- c("CONCEPT", "CONCEPT_RELATIONSHIP", "CONCEPT_ANCESTOR", "RELATIONSHIP", "VOCABULARY", "DOMAIN", "DRUG_STRENGTH", "CONCEPT_CLASS")
for (table in tables) {
message(paste("Importando", table, "..."))
data <- read_delim(paste0(vocab_path, table, ".csv"), delim = "\t", col_types = cols())
DatabaseConnector::insertTable(conn,
databaseSchema = "vocabularies",
tableName = table,
data = data,
dropTableIfExists = TRUE,
createTable = TRUE,
tempTable = FALSE,
progressBar = TRUE)
}
# Optimize Vocabularies tables
DatabaseConnector::executeSql(conn,
"CREATE INDEX idx_concept_id ON vocabularies.CONCEPT (concept_id);")
DatabaseConnector::executeSql(conn,
"CREATE INDEX idx_concept_code ON vocabularies.CONCEPT (concept_code);")
DatabaseConnector::executeSql(conn,
"CREATE INDEX idx_relationship_id ON vocabularies.RELATIONSHIP (relationship_id);")
DatabaseConnector::executeSql(conn, "VACUUM ANALYZE vocabularies.CONCEPT;")
DatabaseConnector::executeSql(conn, "VACUUM ANALYZE vocabularies.RELATIONSHIP;")
# Close connection
DatabaseConnector::disconnect(conn)
Contacto
Para cualquier duda durante el periodo de uso y validación de los componentes de la Implementación de Referencia de IMPaCT-Data (Marzo, 2025), podéis poneros en contacto con: