| Title: | Generate Synthetic ADaM Datasets |
|---|---|
| Description: | Generates synthetic ADaM (Analysis Data Model) datasets from real clinical trial data. Preserves the structure of real datasets (column names, value ranges, relationships between treatment and flag columns) while removing identifiable patient information. Supports subject-level (ADSL), longitudinal (BDS), occurrence (OCCDS), and time-to-event (TTE) dataset types. |
| Authors: | David Zhang [aut, cre], Thibaud Coroller [ctb], Peter Krusche [ctb], Chengyang Gao [ctb], Novartis AG [cph] |
| Maintainer: | David Zhang <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.3.3 |
| Built: | 2026-07-22 12:27:33 UTC |
| Source: | https://github.com/cran/synadam |
Scans a directory of .sas7bdat files, infers dataset_type and
per-dataset glimpse arguments using CDISC filename and column-name
conventions, and writes a draft YAML config suitable for simulate_study().
Inferred fields are tagged with inline # REVIEW comments where the signal
is weak so users know what to verify before running the simulation.
generate_study_config( adam_dir, output_dir, config_yaml_name = "synadam_config.yaml", seed = 123 )generate_study_config( adam_dir, output_dir, config_yaml_name = "synadam_config.yaml", seed = 123 )
adam_dir |
|
output_dir |
|
config_yaml_name |
|
seed |
|
Only files whose basename matches ad*.sas7bdat (case-insensitive) are
considered. Any other files in adam_dir are skipped with a single
warning listing them.
character(1) - the path the YAML was written to
(file.path(output_dir, config_yaml_name)).
Filename match (case-insensitive, basename without extension):
starts with adsl -> adsl
starts with adae/adcm/admh/addv -> occds
starts with adtte -> tte
any other name (including ad*) -> fall through to column inspection
Column inspection rules (checked in order; USUBJID is required in
every ADaM dataset, so it is not used as a discriminator). ADSL is
classified from the filename only - any non-adsl* file that lacks
BDS/TTE/OCCDS column signatures falls through to "REVIEW":
has PARAM -> bds (checked before CNSR so oncology hybrid
datasets like ADRECIST that carry TTE-derived parameters inline
classify as the longitudinal BDS they actually are)
has CNSR -> tte (CNSR is the only structurally required TTE
variable in ADaM; EVNTDESC is conventional but not universal)
has any *SEQ column -> occds
otherwise -> "REVIEW" placeholder + warning
Errors if no ADSL file is detected; simulate_study() requires exactly
one. If multiple ADSL candidates are detected, a file named exactly
adsl.sas7bdat (case-insensitive) is preferred; otherwise the
alphabetically-first candidate is used. The picked file is kept and the
rest are dropped with a warning.
Within a classified dataset, the column-role inference picks up:
id_cols: USUBJID and SUBJID when present.
treatment_cols (ADSL): ACTARM, ACTARMCD, ARM, ARMCD,
TRTSEQP, TRTSEQA and any
TRT##A/TRT##AN/TRT##AL/TRT##P/TRT##PN/TRT##PL matches,
plus TRT##(A|P)GR\d* and TRT##(A|P)GR\d*N group variants.
visit_cols (BDS): AVISIT, AVISITN, VISIT, VISITNUM,
ATPT, ATPTN when present.
param_cols (BDS, TTE): PARAM, PARAMCD, and any PARCAT* columns.
seq_col (OCCDS): the first known domain-coded *SEQ column
(AESEQ, CMSEQ, MHSEQ, PRSEQ, EXSEQ, DSSEQ); falls back
to the first *SEQ column if none of those are present.
censor_cols (TTE): CNSR, EVNTDESC, CNSDTDSC - only emitted
when two or more of these are detected. A single CNSR flows
through as a regular column and censor_cols is omitted.
ordered_col_sets: X/XN/XL groups where two or three variants of a
base column name co-exist.
Some config decisions are opinionated and intended to be pruned or extended by the user after generation:
flag_cols emits every *FL column found. The user is expected to
trim this list down to the flags they want to preserve.
Non-FL flag-like indicators (e.g. AESER) are not detected.
Ordered column sets that share semantics but not naming (e.g.
AEBODSYS/AEDECOD) are not auto-paired; add them by hand.
For BDS and TTE datasets param_cols auto-includes PARAM,
PARAMCD, and any PARCAT* columns present, but NOT PARAMTYP
or PARAMN; add these manually if relevant.
For BDS, OCCDS, and TTE datasets ordered_col_sets excludes any
column also present in the chosen ADSL. ADSL-shared columns are
pulled in via the ADSL spine at simulation time, so listing them
here would duplicate the column.
yaml_path <- generate_study_config( adam_dir, output_dir = file.path(tempdir(), "syn_out") ) yaml_pathyaml_path <- generate_study_config( adam_dir, output_dir = file.path(tempdir(), "syn_out") ) yaml_path
Extracts a statistical summary from a vector that preserves its structure while enabling synthetic data generation. The summary type varies by vector class: character vectors output unique values, numeric vectors output min/max values, and date/time vectors output earliest/latest dates.
glimpse(x, ...) ## S3 method for class 'character' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'Date' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'POSIXct' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'difftime' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'numeric' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...)glimpse(x, ...) ## S3 method for class 'character' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'Date' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'POSIXct' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'difftime' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...) ## S3 method for class 'numeric' glimpse(x, col_name, na_mode = "mirror", seed = NULL, ...)
x |
|
... |
additional arguments passed to methods. |
col_name |
|
na_mode |
|
seed |
|
summary - contains summary of the input vector.
glimpse(character): glimpse a character vector using
.get_unique_values().
glimpse(Date): glimpse a Date vector into a summary containing
the min, max, and NA positions.
glimpse(POSIXct): glimpse a POSIXct vector into a summary containing
the min, max, and NA positions.
glimpse(difftime): glimpse a difftime vector into a summary containing
the min, max, units, and NA positions.
glimpse(numeric): glimpse a numeric vector into a summary containing the
min, max, and NA positions. Detects if values are integer or double.
# Glimpse a character vector, then simulate synthetic values from it. summary <- glimpse(c("A", "B", "B", "C"), col_name = "column_name") simulate(summary, output_length = 10, seed = 1)# Glimpse a character vector, then simulate synthetic values from it. summary <- glimpse(c("A", "B", "B", "C"), col_name = "column_name") simulate(summary, output_length = 10, seed = 1)
Summarizes an ADSL (subject-level) dataset for synthetic simulation by preserving treatment-flag relationships, capturing ordered column combinations and extracting summaries for all other variables.
glimpse_adsl( adsl, id_cols, treatment_cols, flag_cols = character(), ordered_col_sets = list(), seed = NULL )glimpse_adsl( adsl, id_cols, treatment_cols, flag_cols = character(), ordered_col_sets = list(), seed = NULL )
adsl |
|
id_cols |
|
treatment_cols |
|
flag_cols |
|
ordered_col_sets |
|
seed |
|
summary_adsl - list of summary objects, with each summarising a
column or set of columns in the input ADSL.
# Glimpse the ADSL, then simulate a synthetic version from the summary. adsl_summary <- glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN"), flag_cols = c("SAFFL", "ITTFL", "EFFFL"), ordered_col_sets = list(c("REGION1", "REGION1N")), seed = 42 ) syn_adsl <- simulate_adsl(adsl_summary, seed = 42) head(syn_adsl)# Glimpse the ADSL, then simulate a synthetic version from the summary. adsl_summary <- glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN"), flag_cols = c("SAFFL", "ITTFL", "EFFFL"), ordered_col_sets = list(c("REGION1", "REGION1N")), seed = 42 ) syn_adsl <- simulate_adsl(adsl_summary, seed = 42) head(syn_adsl)
Summarizes a BDS (Basic Data Structure) e.g. ADLB, ADVS dataset for synthetic simulation by extracting per-subject parameter/visit profiles, preserving relationships with ADSL columns, and extracting summaries of all other variables. All PARAMCDs in the dataset are included.
glimpse_bds( bds, syn_adsl, id_cols, param_cols, visit_cols = character(), flag_cols = character(), ordered_col_sets = list(), seed = NULL )glimpse_bds( bds, syn_adsl, id_cols, param_cols, visit_cols = character(), flag_cols = character(), ordered_col_sets = list(), seed = NULL )
bds |
|
syn_adsl |
|
id_cols |
|
param_cols |
|
visit_cols |
|
flag_cols |
|
ordered_col_sets |
|
seed |
|
summary_bds - summary object for BDS simulation.
# BDS simulation needs a synthetic ADSL first to provide the subject spine. syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) bds_summary <- glimpse_bds( adlb, syn_adsl, id_cols = "USUBJID", param_cols = c("PARAM", "PARAMCD"), visit_cols = c("AVISIT", "AVISITN"), flag_cols = "ANL01FL" ) syn_adlb <- simulate_bds(bds_summary, seed = 42) head(syn_adlb)# BDS simulation needs a synthetic ADSL first to provide the subject spine. syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) bds_summary <- glimpse_bds( adlb, syn_adsl, id_cols = "USUBJID", param_cols = c("PARAM", "PARAMCD"), visit_cols = c("AVISIT", "AVISITN"), flag_cols = "ANL01FL" ) syn_adlb <- simulate_bds(bds_summary, seed = 42) head(syn_adlb)
Glimpse an ID vector.
glimpse_id(x, col_name)glimpse_id(x, col_name)
x |
|
col_name |
|
summary - contains column name for ID generation.
# Glimpse an ID column, then simulate fresh sequential IDs. summary <- glimpse_id(c("S1", "S2", "S3"), col_name = "USUBJID") simulate(summary, output_length = 5)# Glimpse an ID column, then simulate fresh sequential IDs. summary <- glimpse_id(c("S1", "S2", "S3"), col_name = "USUBJID") simulate(summary, output_length = 5)
Summarizes an OCCDS (Occurrence Data Structure) dataset for simulation. Works with ADAE, ADCM, ADMH, ADDV and other occurrence-based datasets.
glimpse_occds( occds, syn_adsl, id_cols, seq_col, flag_cols = character(0), ordered_col_sets = list(), seed = NULL )glimpse_occds( occds, syn_adsl, id_cols, seq_col, flag_cols = character(0), ordered_col_sets = list(), seed = NULL )
occds |
|
syn_adsl |
|
id_cols |
|
seq_col |
|
flag_cols |
|
ordered_col_sets |
|
seed |
|
summary_occds - summary object for OCCDS simulation.
# OCCDS simulation needs a synthetic ADSL first to provide the subject spine. syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) occds_summary <- glimpse_occds( adae, syn_adsl, id_cols = "USUBJID", seq_col = "AESEQ", ordered_col_sets = list(c("AEBODSYS", "AEDECOD")) ) syn_adae <- simulate_occds(occds_summary, seed = 42) head(syn_adae)# OCCDS simulation needs a synthetic ADSL first to provide the subject spine. syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) occds_summary <- glimpse_occds( adae, syn_adsl, id_cols = "USUBJID", seq_col = "AESEQ", ordered_col_sets = list(c("AEBODSYS", "AEDECOD")) ) syn_adae <- simulate_occds(occds_summary, seed = 42) head(syn_adae)
Counts the number of occurrences (records) per subject in an OCCDS dataset and captures the ID and sequence column names needed for spine construction.
glimpse_occurrence_id_seq(df, id_cols, seq_col)glimpse_occurrence_id_seq(df, id_cols, seq_col)
df |
|
id_cols |
|
seq_col |
|
summary_occurrence_id_seq - contains occurrence counts per subject,
ID column names, and sequence column name.
# Capture per-subject occurrence counts (used within glimpse_occds()). glimpse_occurrence_id_seq(adae, id_cols = "USUBJID", seq_col = "AESEQ")# Capture per-subject occurrence counts (used within glimpse_occds()). glimpse_occurrence_id_seq(adae, id_cols = "USUBJID", seq_col = "AESEQ")
Ordered columns are those which should be simulated together, such as PARAM/PARAMCD or REGION1/REGION1N/REGION2/REGION2N. Rare combinations (count = 1) are masked for privacy protection.
glimpse_ordered(df)glimpse_ordered(df)
df |
|
summary - contains column names, unique combinations, and
NA positions.
df <- data.frame( REGION1 = c("North America", "North America", "Europe", "Europe"), REGION1N = c(1, 1, 2, 2) ) summary <- glimpse_ordered(df) simulate(summary, output_length = 6, seed = 1)df <- data.frame( REGION1 = c("North America", "North America", "Europe", "Europe"), REGION1N = c(1, 1, 2, 2) ) summary <- glimpse_ordered(df) simulate(summary, output_length = 6, seed = 1)
Extracts per-subject param/visit profiles from a BDS dataset. Rare
param/visit combinations (count = 1) are masked for privacy protection.
Subjects are grouped by their set of surviving param/visit combinations
to form profiles, which are used by simulate_bds() to construct the
simulation spine.
glimpse_param_visits(df, id_cols, param_visit_cols)glimpse_param_visits(df, id_cols, param_visit_cols)
df |
|
id_cols |
|
param_visit_cols |
|
summary_param_visits - contains deduplicated profiles with masked
counts and the unique param/visit combinations (after masking).
# Build per-subject parameter/visit profiles (used within glimpse_bds()). glimpse_param_visits( adlb, id_cols = "USUBJID", param_visit_cols = c("PARAM", "PARAMCD", "AVISIT", "AVISITN") )# Build per-subject parameter/visit profiles (used within glimpse_bds()). glimpse_param_visits( adlb, id_cols = "USUBJID", param_visit_cols = c("PARAM", "PARAMCD", "AVISIT", "AVISITN") )
Extracts unique combinations of parameter columns without filtering. Used for TTE datasets where all PARAMCDs are simulated. Rare combinations (count = 1) are masked for privacy protection.
glimpse_params(df)glimpse_params(df)
df |
|
summary_params - contains unique parameter combinations.
df <- data.frame( PARAM = c("Overall Survival", "Overall Survival", "Progression Free"), PARAMCD = c("OS", "OS", "PFS") ) glimpse_params(df)df <- data.frame( PARAM = c("Overall Survival", "Overall Survival", "Progression Free"), PARAMCD = c("OS", "OS", "PFS") ) glimpse_params(df)
Reads the YAML configuration used by simulate_study(), runs the
appropriate glimpse_*() for each dataset, and saves the collected
summaries (plus seed and version metadata) to a single .rds file.
glimpse_study(config_path, study_summary_path)glimpse_study(config_path, study_summary_path)
config_path |
|
study_summary_path |
|
The resulting study summary can later be passed to
simulate_study_from_summary() to generate the synthetic datasets,
decoupling the glimpse phase (which requires access to real .sas7bdat
files) from the simulate phase.
NULL (invisibly). The study summary is a named list with elements
summaries (named list of glimpse summary objects, keyed by dataset
name from the YAML), seed, synadam_version, and glimpsed_at.
simulate_study_from_summary(), simulate_study().
# Generate a config for the staged ADaM datasets. yaml_path <- generate_study_config( adam_dir, output_dir = file.path(tempdir(), "syn_glimpse_out") ) # Glimpse phase: write the study summary (decoupled from the SAS files). summary_path <- tempfile(fileext = ".rds") glimpse_study(yaml_path, summary_path) # Simulate phase: generate synthetic datasets from the study summary. out_dir <- file.path(tempdir(), "syn_glimpse_out") simulate_study_from_summary(summary_path, out_dir) list.files(out_dir, pattern = "\\.rds$")# Generate a config for the staged ADaM datasets. yaml_path <- generate_study_config( adam_dir, output_dir = file.path(tempdir(), "syn_glimpse_out") ) # Glimpse phase: write the study summary (decoupled from the SAS files). summary_path <- tempfile(fileext = ".rds") glimpse_study(yaml_path, summary_path) # Simulate phase: generate synthetic datasets from the study summary. out_dir <- file.path(tempdir(), "syn_glimpse_out") simulate_study_from_summary(summary_path, out_dir) list.files(out_dir, pattern = "\\.rds$")
Captures unique combinations of treatment and flag columns with their counts, preserving the relationship between treatments and analysis flags. Combinations with count = 1 are masked for privacy protection by adding their counts to the most common combination.
glimpse_treatment_flag(df)glimpse_treatment_flag(df)
df |
|
summary - contains treatment-flag combinations with counts.
df <- data.frame( TRT01A = c("Placebo", "Placebo", "Drug A", "Drug A"), SAFFL = c("Y", "Y", "Y", "N") ) summary <- glimpse_treatment_flag(df) # simulate() preserves the exact treatment-flag counts (no output_length). simulate(summary)df <- data.frame( TRT01A = c("Placebo", "Placebo", "Drug A", "Drug A"), SAFFL = c("Y", "Y", "Y", "N") ) summary <- glimpse_treatment_flag(df) # simulate() preserves the exact treatment-flag counts (no output_length). simulate(summary)
Summarizes a TTE (Time-to-Event) dataset for synthetic simulation by extracting parameter combinations, preserving censoring column relationships, and extracting summaries of all other variables.
glimpse_tte( tte, syn_adsl, param_cols, censor_cols = character(), flag_cols = character(), ordered_col_sets = list(), seed = NULL )glimpse_tte( tte, syn_adsl, param_cols, censor_cols = character(), flag_cols = character(), ordered_col_sets = list(), seed = NULL )
tte |
|
syn_adsl |
|
param_cols |
|
censor_cols |
|
flag_cols |
|
ordered_col_sets |
|
seed |
|
summary_tte - summary object for TTE simulation.
# TTE simulation needs a synthetic ADSL to provide the subject spine. syn_adsl <- data.frame( USUBJID = as.character(1:5), TRT01A = c("Placebo", "Placebo", "Drug A", "Drug A", "Drug A"), TRT01AN = c(1, 1, 2, 2, 2) ) tte <- data.frame( USUBJID = as.character(rep(1:3, each = 2)), PARAM = rep(c("Overall Survival", "Progression Free Survival"), 3), PARAMCD = rep(c("OS", "PFS"), 3), CNSR = c(0, 1, 0, 1, 1, 0), EVNTDESC = c( "DEATH", "COMPLETED", "DEATH", "COMPLETED", "COMPLETED", "PROGRESSION" ), AVAL = c(365, 500, 180, 250, 600, 120) ) tte_summary <- glimpse_tte( tte, syn_adsl, param_cols = c("PARAM", "PARAMCD"), censor_cols = c("CNSR", "EVNTDESC") ) syn_tte <- simulate_tte(tte_summary, seed = 42) head(syn_tte)# TTE simulation needs a synthetic ADSL to provide the subject spine. syn_adsl <- data.frame( USUBJID = as.character(1:5), TRT01A = c("Placebo", "Placebo", "Drug A", "Drug A", "Drug A"), TRT01AN = c(1, 1, 2, 2, 2) ) tte <- data.frame( USUBJID = as.character(rep(1:3, each = 2)), PARAM = rep(c("Overall Survival", "Progression Free Survival"), 3), PARAMCD = rep(c("OS", "PFS"), 3), CNSR = c(0, 1, 0, 1, 1, 0), EVNTDESC = c( "DEATH", "COMPLETED", "DEATH", "COMPLETED", "COMPLETED", "PROGRESSION" ), AVAL = c(365, 500, 180, 250, 600, 120) ) tte_summary <- glimpse_tte( tte, syn_adsl, param_cols = c("PARAM", "PARAMCD"), censor_cols = c("CNSR", "EVNTDESC") ) syn_tte <- simulate_tte(tte_summary, seed = 42) head(syn_tte)
Loads in a ADaM dataset and and convert all missing values to NA.
read_sas7bdat(adam_path)read_sas7bdat(adam_path)
adam_path |
|
data.frame - ADaM dataset.
adam <- read_sas7bdat(sas_path) head(adam)adam <- read_sas7bdat(sas_path) head(adam)
Generates synthetic subject-level data from an ADSL summary, preserving the structure of the original dataset.
simulate_adsl(adsl_summary, seed = NULL)simulate_adsl(adsl_summary, seed = NULL)
adsl_summary |
|
seed |
|
data.frame - synthetic ADSL with the same columns (and column
order) as the dataset that was glimpsed, and one row per subject.
adsl_summary <- glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN"), flag_cols = "SAFFL" ) syn_adsl <- simulate_adsl(adsl_summary, seed = 42) head(syn_adsl)adsl_summary <- glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN"), flag_cols = "SAFFL" ) syn_adsl <- simulate_adsl(adsl_summary, seed = 42) head(syn_adsl)
Generates synthetic BDS data by creating a spine from parameter/visit combinations and ADSL subject records, then populating remaining columns, preserving the original data structure.
simulate_bds(bds_summary, seed = NULL)simulate_bds(bds_summary, seed = NULL)
bds_summary |
|
seed |
|
data.frame - synthetic BDS dataset.
syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) bds_summary <- glimpse_bds( adlb, syn_adsl, id_cols = "USUBJID", param_cols = c("PARAM", "PARAMCD"), visit_cols = c("AVISIT", "AVISITN") ) syn_adlb <- simulate_bds(bds_summary, seed = 42) head(syn_adlb)syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) bds_summary <- glimpse_bds( adlb, syn_adsl, id_cols = "USUBJID", param_cols = c("PARAM", "PARAMCD"), visit_cols = c("AVISIT", "AVISITN") ) syn_adlb <- simulate_bds(bds_summary, seed = 42) head(syn_adlb)
Generates synthetic OCCDS data from a summary created by glimpse_occds().
simulate_occds(occds_summary, seed = NULL)simulate_occds(occds_summary, seed = NULL)
occds_summary |
|
seed |
|
data.frame - synthetic OCCDS dataset.
syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) occds_summary <- glimpse_occds( adae, syn_adsl, id_cols = "USUBJID", seq_col = "AESEQ" ) syn_adae <- simulate_occds(occds_summary, seed = 42) head(syn_adae)syn_adsl <- simulate_adsl(glimpse_adsl( adsl, id_cols = c("USUBJID", "SUBJID"), treatment_cols = c("TRT01A", "TRT01AN") )) occds_summary <- glimpse_occds( adae, syn_adsl, id_cols = "USUBJID", seq_col = "AESEQ" ) syn_adae <- simulate_occds(occds_summary, seed = 42) head(syn_adae)
Taking as input a yaml configuration that specifies the ADaM datasets for a study of interest, this function will simulate synthetic versions of each and save them as individual .rds files in a specified directory.
simulate_study(config_path)simulate_study(config_path)
config_path |
|
The YAML configuration file should have the following structure:
output_dir: "/path/to/output_directory"
seed: 32
datasets:
adsl:
dataset_type: "adsl"
path: "/path/to/adsl.sas7bdat"
id_cols: ["USUBJID", "SUBJID"]
treatment_cols: ["TRT01A", "TRT01AN"]
flag_cols: ["SAFFL", "ITTFL"]
ordered_col_sets:
- ["REGION1", "REGION1N"]
adlb:
dataset_type: "bds"
path: "/path/to/adlb.sas7bdat"
id_cols: ["USUBJID"]
param_cols: ["PARAM", "PARAMCD"]
visit_cols: ["AVISIT", "AVISITN"]
flag_cols: ["ANL01FL"]
adtte:
dataset_type: "tte"
path: "/path/to/adtte.sas7bdat"
param_cols: ["PARAM", "PARAMCD"]
censor_cols: ["CNSR", "EVNTDESC", "CNSDTDSC"]
flag_cols: ["ANL01FL"]
ordered_col_sets:
- ["SRCDOM", "SRCVAR"]
adae:
dataset_type: "occds"
path: "/path/to/adae.sas7bdat"
id_cols: ["USUBJID"]
seq_col: "AESEQ"
flag_cols: ["AOCCFL", "TRTEMFL"]
ordered_col_sets:
- ["AEBODSYS", "AEDECOD"]
Dataset names in the output files are determined by the YAML keys under
datasets: (e.g., syn_adsl.rds, syn_adlb.rds). Exactly one dataset
must have dataset_type: "adsl". The output_dir directory will be
created automatically if it doesn't exist.
NULL (invisibly). Synthetic datasets are saved as individual
.rds files named syn_{key}.rds in the output_dir directory, where
{key} is the dataset name from the YAML config. Each dataset has a
synadam_version attribute containing the package version.
out_dir <- file.path(tempdir(), "syn_study") yaml_path <- generate_study_config(adam_dir, output_dir = out_dir) # Simulate the whole study; synthetic syn_*.rds files land in out_dir. simulate_study(yaml_path) list.files(out_dir, pattern = "\\.rds$")out_dir <- file.path(tempdir(), "syn_study") yaml_path <- generate_study_config(adam_dir, output_dir = out_dir) # Simulate the whole study; synthetic syn_*.rds files land in out_dir. simulate_study(yaml_path) list.files(out_dir, pattern = "\\.rds$")
Reads a study summary written by glimpse_study() and produces synthetic
datasets, decoupling simulation from the original .sas7bdat files.
simulate_study_from_summary(study_summary_path, output_dir, seed = NULL)simulate_study_from_summary(study_summary_path, output_dir, seed = NULL)
study_summary_path |
|
output_dir |
|
seed |
|
NULL (invisibly). Synthetic datasets are saved as
syn_{key}.rds files in output_dir. Each dataset has a
synadam_version attribute.
glimpse_study(), simulate_study().
# Generate a config and glimpse the datasets into a study summary. yaml_path <- generate_study_config( adam_dir, output_dir = file.path(tempdir(), "syn_data") ) study_summary_path <- tempfile(fileext = ".rds") glimpse_study(yaml_path, study_summary_path) # Simulate synthetic datasets from the saved study summary. out_dir <- file.path(tempdir(), "syn_data") simulate_study_from_summary(study_summary_path, out_dir) list.files(out_dir, pattern = "\\.rds$")# Generate a config and glimpse the datasets into a study summary. yaml_path <- generate_study_config( adam_dir, output_dir = file.path(tempdir(), "syn_data") ) study_summary_path <- tempfile(fileext = ".rds") glimpse_study(yaml_path, study_summary_path) # Simulate synthetic datasets from the saved study summary. out_dir <- file.path(tempdir(), "syn_data") simulate_study_from_summary(study_summary_path, out_dir) list.files(out_dir, pattern = "\\.rds$")
Generates synthetic TTE data by creating a spine from parameter combinations and ADSL subject records, then populating remaining columns, preserving the original data structure. Produces exactly one record per subject per parameter (the defining TTE constraint).
simulate_tte(tte_summary, seed = NULL)simulate_tte(tte_summary, seed = NULL)
tte_summary |
|
seed |
|
data.frame - synthetic TTE dataset.
syn_adsl <- data.frame( USUBJID = as.character(1:5), TRT01A = c("Placebo", "Placebo", "Drug A", "Drug A", "Drug A"), TRT01AN = c(1, 1, 2, 2, 2) ) tte <- data.frame( USUBJID = as.character(rep(1:3, each = 2)), PARAM = rep(c("Overall Survival", "Progression Free Survival"), 3), PARAMCD = rep(c("OS", "PFS"), 3), CNSR = c(0, 1, 0, 1, 1, 0), AVAL = c(365, 500, 180, 250, 600, 120) ) tte_summary <- glimpse_tte( tte, syn_adsl, param_cols = c("PARAM", "PARAMCD") ) syn_tte <- simulate_tte(tte_summary, seed = 42) head(syn_tte)syn_adsl <- data.frame( USUBJID = as.character(1:5), TRT01A = c("Placebo", "Placebo", "Drug A", "Drug A", "Drug A"), TRT01AN = c(1, 1, 2, 2, 2) ) tte <- data.frame( USUBJID = as.character(rep(1:3, each = 2)), PARAM = rep(c("Overall Survival", "Progression Free Survival"), 3), PARAMCD = rep(c("OS", "PFS"), 3), CNSR = c(0, 1, 0, 1, 1, 0), AVAL = c(365, 500, 180, 250, 600, 120) ) tte_summary <- glimpse_tte( tte, syn_adsl, param_cols = c("PARAM", "PARAMCD") ) syn_tte <- simulate_tte(tte_summary, seed = 42) head(syn_tte)
Simulate a vector from a summary object.
## S3 method for class 'summary_ordered' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_treatment_flag' simulate(summary, ...) simulate(summary, ...) ## S3 method for class 'summary_character' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_Date' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_POSIXct' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_difftime' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_integer' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_double' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_id' simulate(summary, output_length, ...) ## S3 method for class 'summary_flag' simulate(summary, output_length, seed = NULL, ...)## S3 method for class 'summary_ordered' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_treatment_flag' simulate(summary, ...) simulate(summary, ...) ## S3 method for class 'summary_character' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_Date' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_POSIXct' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_difftime' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_integer' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_double' simulate(summary, output_length, seed = NULL, ...) ## S3 method for class 'summary_id' simulate(summary, output_length, ...) ## S3 method for class 'summary_flag' simulate(summary, output_length, seed = NULL, ...)
summary |
|
output_length |
|
seed |
|
... |
additional arguments passed to methods. |
data.frame - the simulated dataset.
simulate(summary_ordered): simulate ordered columns by sampling from unique
combinations.
simulate(summary_treatment_flag): simulate treatment and flag columns by preserving
exact counts for each combination.
simulate(summary_character): simulate a character vector by sampling from unique
values.
simulate(summary_Date): simulate a Date vector by sampling uniformly
between min and max.
simulate(summary_POSIXct): simulate a POSIXct vector by sampling uniformly
between min and max.
simulate(summary_difftime): simulate a difftime vector by sampling uniformly
between min and max.
simulate(summary_integer): simulate an integerish vector by sampling uniformly
between min and max and rounding.
simulate(summary_double): simulate a double vector by sampling uniformly
between min and max.
simulate(summary_id): simulate an ID vector by generating sequential IDs.
simulate(summary_flag): simulate a flag vector by sampling Y/N in proportion
to input.
# Summarise a vector with glimpse(). summary <- glimpse(c("A", "B", "B", "C"), col_name = "column_name") simulate(summary, output_length = 10, seed = 1)# Summarise a vector with glimpse(). summary <- glimpse(c("A", "B", "B", "C"), col_name = "column_name") simulate(summary, output_length = 10, seed = 1)