As a clinical trial statistician or programmer, challenge anything in this benchmark: describe a problem in Comments, or propose a fix with the Edit button on any source file.
- Task: Would a real study need this derivation, specified this way? Does it follow CDISC ADaM: variable names, controlled terms, record structure? Flag any rule that is ambiguous or that a sponsor would handle differently.
- Inputs: Do they look like data collected in a real trial, and do they include the situations you would expect to meet in one?
- Expected output: Would independent QC programming reproduce every value from these inputs and rules?
The other tabs beside Comments are background for assessment, not under review.
Summary
README.mdGoal: split each adverse event (AE) into continuous analysis periods
and mark treatment-emergent periods (TRTEMFL).
Input: AE holds one record per event, with its sequence (AESEQ),
term (AEDECOD), overall start/end (AESTDTC, AEENDTC) and maximum
severity/grade (AESEV, AETOXGR). Findings About (FA) holds severity
(SEV) and toxicity-grade (TOXGR) findings at onset and each collected
change time (FADTC). FALNKID matches the event's AELNKID. The
subject-level analysis dataset (ADSL) supplies first exposure (TRTSDTM),
empty for an untreated subject.
Variables:
ASEQnumbers analysis periods within a subject; repeatedAESEQretains the source event identity and its original values.ASTDTMstarts a period at a collected change time.AENDTMis the next period's start, or the original end for the last period; an ongoing event's last end stays empty.ASEVandATOXGRNhold the period's severity and numeric toxicity grade (1 through 5). Each persists until that dimension changes; without an earlier collected value it stays empty.TRTEMFLisYfor events starting at or after first exposure. For an ongoing pre-treatment event, it starts at the first post-exposure increase over the last pre-treatment severity or grade and remainsYon subsequent periods. Earlier periods, improvement alone and untreated subjects' periods stay empty.
Note: findings are collected effective change times, rather than visit assessments from which a change time must be inferred. Simultaneous severity and grade changes create one period. Missing comparison values show no worsening for that dimension. Separate events sharing a term remain separate. Periods are continuous with end equal to next start.
Inputs
Under review3 source filesinput/adsl.csv
Edit5 rows| STUDYID | USUBJID | TRTSDTM |
|---|---|---|
| PILOT7 | 2025-03-04T09:00:00 | |
| PILOT7 | 2025-03-04T09:00:00 | |
| PILOT7 | 2025-03-04T09:00:00 | |
| PILOT7 | — | |
| PILOT7 | 2025-03-04T09:00:00 |
input/ae.csv
Edit6 rows| STUDYID | USUBJID | AESEQ | AELNKID | AEDECOD | AESTDTC | AEENDTC | AESEV | AETOXGR |
|---|---|---|---|---|---|---|---|---|
| PILOT7 | 1 | AE-1 | HEADACHE | 2025-03-04T07:00:00 | 2025-03-05T10:00:00 | SEVERE | 1 | |
| PILOT7 | 2 | AE-2 | HEADACHE | 2025-03-06T10:00:00 | 2025-03-06T11:00:00 | MILD | 1 | |
| PILOT7 | 1 | AE-1 | RASH | 2025-03-03T09:00:00 | 2025-03-07T09:00:00 | SEVERE | 2 | |
| PILOT7 | 1 | AE-1 | VOMITING | 2025-03-03T10:00:00 | 2025-03-06T10:00:00 | MODERATE | 2 | |
| PILOT7 | 1 | AE-1 | FATIGUE | 2025-03-03T09:00:00 | 2025-03-06T09:00:00 | SEVERE | 1 | |
| PILOT7 | 1 | AE-1 | COUGH | 2025-03-03T09:00:00 | — | SEVERE | 3 |
input/fa.csv
Edit20 rows| STUDYID | USUBJID | FASEQ | FALNKID | FATESTCD | FAOBJ | FASTRESC | FADTC |
|---|---|---|---|---|---|---|---|
| PILOT7 | 1 | AE-1 | SEV | HEADACHE | MILD | 2025-03-04T07:00:00 | |
| PILOT7 | 2 | AE-1 | TOXGR | HEADACHE | 1 | 2025-03-04T07:00:00 | |
| PILOT7 | 3 | AE-2 | SEV | HEADACHE | MILD | 2025-03-06T10:00:00 | |
| PILOT7 | 4 | AE-2 | TOXGR | HEADACHE | 1 | 2025-03-06T10:00:00 | |
| PILOT7 | 1 | AE-1 | SEV | RASH | MODERATE | 2025-03-03T09:00:00 | |
| PILOT7 | 2 | AE-1 | TOXGR | RASH | 2 | 2025-03-03T09:00:00 | |
| PILOT7 | 1 | AE-1 | SEV | VOMITING | MODERATE | 2025-03-03T10:00:00 | |
| PILOT7 | 2 | AE-1 | TOXGR | VOMITING | 1 | 2025-03-03T10:00:00 | |
| PILOT7 | 1 | AE-1 | SEV | FATIGUE | MILD | 2025-03-03T09:00:00 | |
| PILOT7 | 2 | AE-1 | TOXGR | FATIGUE | 1 | 2025-03-03T09:00:00 | |
| PILOT7 | 1 | AE-1 | SEV | COUGH | SEVERE | 2025-03-03T09:00:00 | |
| PILOT7 | 2 | AE-1 | TOXGR | COUGH | 3 | 2025-03-03T09:00:00 | |
| PILOT7 | 5 | AE-1 | SEV | HEADACHE | MODERATE | 2025-03-04T11:00:00 | |
| PILOT7 | 6 | AE-1 | SEV | HEADACHE | SEVERE | 2025-03-04T13:00:00 | |
| PILOT7 | 7 | AE-1 | SEV | HEADACHE | MILD | 2025-03-05T06:00:00 | |
| PILOT7 | 3 | AE-1 | SEV | RASH | MILD | 2025-03-05T09:00:00 | |
| PILOT7 | 4 | AE-1 | SEV | RASH | SEVERE | 2025-03-06T09:00:00 | |
| PILOT7 | 3 | AE-1 | TOXGR | VOMITING | 2 | 2025-03-05T10:00:00 | |
| PILOT7 | 3 | AE-1 | SEV | FATIGUE | SEVERE | 2025-03-05T09:00:00 | |
| PILOT7 | 3 | AE-1 | SEV | COUGH | MODERATE | 2025-03-05T09:00:00 |
Expected output
Under review14 expected rowsexpected/adae.csv
Edit14 rows| STUDYID | USUBJID | ASEQ | AESEQ | AEDECOD | AESTDTC | AEENDTC | ASTDTM | AENDTM | TRTSDTM | AESEV | AETOXGR | ASEV | ATOXGRN | TRTEMFL |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| PILOT7 | 1 | 1 | HEADACHE | 2025-03-04T07:00:00 | 2025-03-05T10:00:00 | 2025-03-04T07:00:00 | 2025-03-04T11:00:00 | 2025-03-04T09:00:00 | SEVERE | 1 | MILD | 1 | — | |
| PILOT7 | 2 | 1 | HEADACHE | 2025-03-04T07:00:00 | 2025-03-05T10:00:00 | 2025-03-04T11:00:00 | 2025-03-04T13:00:00 | 2025-03-04T09:00:00 | SEVERE | 1 | MODERATE | 1 | Y | |
| PILOT7 | 3 | 1 | HEADACHE | 2025-03-04T07:00:00 | 2025-03-05T10:00:00 | 2025-03-04T13:00:00 | 2025-03-05T06:00:00 | 2025-03-04T09:00:00 | SEVERE | 1 | SEVERE | 1 | Y | |
| PILOT7 | 4 | 1 | HEADACHE | 2025-03-04T07:00:00 | 2025-03-05T10:00:00 | 2025-03-05T06:00:00 | 2025-03-05T10:00:00 | 2025-03-04T09:00:00 | SEVERE | 1 | MILD | 1 | Y | |
| PILOT7 | 5 | 2 | HEADACHE | 2025-03-06T10:00:00 | 2025-03-06T11:00:00 | 2025-03-06T10:00:00 | 2025-03-06T11:00:00 | 2025-03-04T09:00:00 | MILD | 1 | MILD | 1 | Y | |
| PILOT7 | 1 | 1 | RASH | 2025-03-03T09:00:00 | 2025-03-07T09:00:00 | 2025-03-03T09:00:00 | 2025-03-05T09:00:00 | 2025-03-04T09:00:00 | SEVERE | 2 | MODERATE | 2 | — | |
| PILOT7 | 2 | 1 | RASH | 2025-03-03T09:00:00 | 2025-03-07T09:00:00 | 2025-03-05T09:00:00 | 2025-03-06T09:00:00 | 2025-03-04T09:00:00 | SEVERE | 2 | MILD | 2 | — | |
| PILOT7 | 3 | 1 | RASH | 2025-03-03T09:00:00 | 2025-03-07T09:00:00 | 2025-03-06T09:00:00 | 2025-03-07T09:00:00 | 2025-03-04T09:00:00 | SEVERE | 2 | SEVERE | 2 | Y | |
| PILOT7 | 1 | 1 | VOMITING | 2025-03-03T10:00:00 | 2025-03-06T10:00:00 | 2025-03-03T10:00:00 | 2025-03-05T10:00:00 | 2025-03-04T09:00:00 | MODERATE | 2 | MODERATE | 1 | — | |
| PILOT7 | 2 | 1 | VOMITING | 2025-03-03T10:00:00 | 2025-03-06T10:00:00 | 2025-03-05T10:00:00 | 2025-03-06T10:00:00 | 2025-03-04T09:00:00 | MODERATE | 2 | MODERATE | 2 | Y | |
| PILOT7 | 1 | 1 | FATIGUE | 2025-03-03T09:00:00 | 2025-03-06T09:00:00 | 2025-03-03T09:00:00 | 2025-03-05T09:00:00 | — | SEVERE | 1 | MILD | 1 | — | |
| PILOT7 | 2 | 1 | FATIGUE | 2025-03-03T09:00:00 | 2025-03-06T09:00:00 | 2025-03-05T09:00:00 | 2025-03-06T09:00:00 | — | SEVERE | 1 | SEVERE | 1 | — | |
| PILOT7 | 1 | 1 | COUGH | 2025-03-03T09:00:00 | — | 2025-03-03T09:00:00 | 2025-03-05T09:00:00 | 2025-03-04T09:00:00 | SEVERE | 3 | SEVERE | 3 | — | |
| PILOT7 | 2 | 1 | COUGH | 2025-03-03T09:00:00 | — | 2025-03-05T09:00:00 | — | 2025-03-04T09:00:00 | SEVERE | 3 | MODERATE | 3 | — |
Comments and assessment materials
| Dataset Name | Variable Name | Variable Label | Type | Codelist/Controlled Terms | Core | Computational Method | Origin |
|---|---|---|---|---|---|---|---|
| ADAE | STUDYID | Study Identifier | character | Set per constructed row; see the Row construction sheet. | Derived | ||
| ADAE | USUBJID | Unique Subject Identifier | character | Set per constructed row; see the Row construction sheet. | Derived | ||
| ADAE | AESEQ | Source Adverse Event Sequence Number | numeric | Take AESEQ from the AE record matching on STUDYID, USUBJID and AELNKID, and a row with no match is an error. | Derived | ||
| ADAE | AEDECOD | Dictionary-Derived Term | character | Take AEDECOD from the AE record matching on STUDYID, USUBJID and AELNKID, and a row with no match is an error. | Derived | ||
| ADAE | AESTDTC | Source Event Start Date/Time | numeric | ISO 8601 | Take AESTDTC from the AE record matching on STUDYID, USUBJID and AELNKID, and a row with no match is an error. | Derived | |
| ADAE | AEENDTC | Source Event End Date/Time | numeric | ISO 8601 | Take AEENDTC from the AE record matching on STUDYID, USUBJID and AELNKID, and a row with no match is an error. | Derived | |
| ADAE | ASTDTM | Analysis Segment Start Date/Time | numeric | ISO 8601 | Set per constructed row; see the Row construction sheet. | Derived | |
| ADAE | AENDTM | Analysis Segment End Date/Time | numeric | ISO 8601 | First non-missing of NEXTSTART and AEENDTC. | Derived | |
| ADAE | TRTSDTM | Datetime of First Exposure to Treatment | numeric | ISO 8601 | Copy value from ADSL.TRTSDTM. | Predecessor | |
| ADAE | AESEV | Source Event Severity/Intensity | character | Take AESEV from the AE record matching on STUDYID, USUBJID and AELNKID, and a row with no match is an error. | Derived | ||
| ADAE | AETOXGR | Source Event Standard Toxicity Grade | character | Take AETOXGR from the AE record matching on STUDYID, USUBJID and AELNKID, and a row with no match is an error. | Derived | ||
| ADAE | ASEV | Analysis Severity/Intensity | character | MILD, MODERATE, SEVERE | Last observation carried forward from SEVCOL using window EVENT_ORDER. | Derived | |
| ADAE | ATOXGRN | Analysis Toxicity Grade (N) | numeric | 1, 2, 3, 4, 5 | Last observation carried forward from GRDCOL using window EVENT_ORDER. | Derived | |
| ADAE | TRTEMFL | Treatment Emergent Analysis Flag | character | Y | "Y" when AESTDTC IS NOT NULL AND TRTSDTM IS NOT NULL AND (AESTDTC >= TRTSDTM OR ASTDTM >= FIRSTWRS); blank otherwise. | Derived | |
| ADAE | ASEQ | Analysis Sequence Number | numeric | Row number within each group of STUDYID, USUBJID, ordered by AESEQ then ASTDTM. | Derived |
| Template | Include when | STUDYID | USUBJID | AELNKID | ASTDTM | SEVCOL | GRDCOL |
|---|---|---|---|---|---|---|---|
| severity_periods | Aggregate MAX(FA.STUDYID) | Aggregate MAX(FA.USUBJID) | Aggregate MAX(FA.FALNKID) | Aggregate MAX(FA.FADTC) | Aggregate ONLY(FA.FASTRESC) over records matching on the shared output keys, where FA.FATESTCD = 'SEV' | Aggregate ONLY(FA.FASTRESC) over records matching on the shared output keys, where FA.FATESTCD = 'TOXGR' |
| Variable | Permitted values |
|---|---|
| ASEV | MILD, MODERATE, SEVERE |
| ATOXGRN | 1, 2, 3, 4, 5 |
| TRTEMFL | Y |
| Version | Date | Author | Description | Reviewer | Sign-off |
|---|---|---|---|---|---|
| 1.3 | 2026-09-29 | yamaa docs build | Show study codelist names, external dictionaries, and ISO 8601 formats in variable rows; list the document's codelist values and metadata | ||
| 1.2 | 2026-09-29 | yamaa docs build | Classify ADaM copies from a declared input as Predecessor and recodes as Derived, and SDTM recodes of locally derived columns as Derived | ||
| 1.1 | 2026-09-29 | yamaa docs build | Resolve lookups into the donor record they select, and give every derivation shape a plain-language rule instead of its raw YAML | ||
| 1.0 | yamaa docs build | Initial generation from spec.yaml |
prompts/adam-adae-worsening-emergence/full.md
Edit42 linesFollowing CDISC ADaM standards, use the provided AE, FA and ADSL datasets to create an ADAE dataset with one record per analysis severity period.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, ASEQ, AESEQ, AEDECOD, AESTDTC, AEENDTC, ASTDTM, AENDTM, TRTSDTM, AESEV, AETOXGR, ASEV, ATOXGRN, TRTEMFL
AE contains one record per source event with its overall start, end and maximum severity/grade. Copy AESEQ, AEDECOD, AESTDTC, AEENDTC, AESEV and AETOXGR unchanged to every period for that event. Match FA to AE by STUDYID, USUBJID and FALNKID = AELNKID. FA contains a SEV and TOXGR finding at onset, then findings at each collected effective change time FADTC. All change times are within the source event. There is at most one finding per event, time and FATESTCD. These times are actual changes, rather than visit assessments requiring an inferred onset.
Create one period per distinct event and FADTC, including onset. Simultaneous severity and grade findings create one period. ASTDTM is FADTC. AENDTM is the next ASTDTM for the same source event, or AEENDTC for the last period; a missing original end means the last period is ongoing. Periods share exactly equal end/start boundaries. ASEV takes FASTRESC for SEV and persists until the next severity finding. ATOXGRN similarly takes the numeric TOXGR finding, from 1 through 5. A dimension with no earlier collected value stays empty; missing findings do not supply a new value. AESEQ remains the source event identifier. ASEQ numbers periods from 1 within each STUDYID and USUBJID, ordered by numeric AESEQ and ASTDTM.
TRTSDTM is first exposure from ADSL, matched by STUDYID and USUBJID. For an event starting at or after exposure, TRTEMFL is Y on every period. For an event starting before exposure, compare each period at or after exposure with the last severity and grade strictly before exposure. Severity order is MILD < MODERATE < SEVERE. TRTEMFL first becomes Y when either known dimension increases over its known pre-treatment value; it stays Y on subsequent periods, even if intensity later decreases. Earlier periods and improvement without worsening have no flag. A missing comparison value shows no worsening for that dimension. When original onset or exposure is missing, TRTEMFL has no value. Separate source events with the same term never share treatment-emergent status.
Read the source datasets from /app/input and save the completed dataset as /app/output/adae.csv.
prompts/adam-adae-worsening-emergence/conventions.md
Edit12 linesFollowing CDISC ADaM standards, use the provided AE, FA and ADSL datasets to create an ADAE dataset with one record per analysis severity period.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, ASEQ, AESEQ, AEDECOD, AESTDTC, AEENDTC, ASTDTM, AENDTM, TRTSDTM, AESEV, AETOXGR, ASEV, ATOXGRN, TRTEMFL
ASEV is MILD, MODERATE or SEVERE. ATOXGRN holds a toxicity grade from 1 through 5, or is empty. TRTEMFL is Y or has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/adae.csv.
prompts/adam-adae-worsening-emergence/brief.md
Edit9 linesFollowing CDISC ADaM standards, use the provided AE, FA and ADSL datasets to create an ADAE dataset with one record per analysis severity period.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, ASEQ, AESEQ, AEDECOD, AESTDTC, AEENDTC, ASTDTM, AENDTM, TRTSDTM, AESEV, AETOXGR, ASEV, ATOXGRN, TRTEMFL
Read the source datasets from /app/input and save the completed dataset as /app/output/adae.csv.
run.R
Edit4 lineslibrary(yamaa)adae <- yamaa_domain("spec.yaml")$outputadaerun.py
Edit4 linesimport yamaaadae = yamaa.yamaa_domain("spec.yaml").outputadaesolutions/adam-adae-worsening-emergence/result.R
Edit86 lines# R reference for the yamaa benchmark adam-adae-worsening-emergence.# Uses the collected event records and dated findings to construct periods.library(readr)read_input <- function(name) { read_csv(paste0('/app/input/', name), col_types = cols(.default = col_character()), show_col_types = FALSE)}normalize <- function(x) { short <- !is.na(x) & nchar(x) == 16L x[short] <- paste0(x[short], ':00') x}ae <- read_input('ae.csv')fa <- read_input('fa.csv')adsl <- read_input('adsl.csv')fa$FADTC <- normalize(fa$FADTC)ae <- ae[order(ae$STUDYID, ae$USUBJID, as.integer(ae$AESEQ)), ]ranks <- c(MILD = 1L, MODERATE = 2L, SEVERE = 3L)output <- list()previous_study <- previous_subject <- NA_character_aseq <- 0Lfor (i in seq_len(nrow(ae))) { event <- ae[i, ] subject <- event$USUBJID study <- event$STUDYID if (!identical(study, previous_study) || !identical(subject, previous_subject)) aseq <- 0L previous_study <- study previous_subject <- subject trt <- normalize(adsl$TRTSDTM[ adsl$STUDYID == study & adsl$USUBJID == subject ])[1] onset <- normalize(event$AESTDTC) ending <- normalize(event$AEENDTC) findings <- fa[fa$STUDYID == study & fa$USUBJID == subject & fa$FALNKID == event$AELNKID, ] times <- sort(unique(findings$FADTC)) sevs <- rep(NA_character_, length(times)) grades <- rep(NA_integer_, length(times)) sev <- NA_character_ grade <- NA_integer_ for (j in seq_along(times)) { updates <- findings[findings$FADTC == times[j], ] if (anyDuplicated(updates$FATESTCD)) stop('Duplicate finding at event/time') new_sev <- updates$FASTRESC[updates$FATESTCD == 'SEV'] new_grade <- updates$FASTRESC[updates$FATESTCD == 'TOXGR'] if (length(new_sev) && !is.na(new_sev)) sev <- new_sev if (length(new_grade) && !is.na(new_grade)) grade <- as.integer(new_grade) sevs[j] <- sev grades[j] <- grade } before <- if (is.na(trt)) integer() else which(times < trt) baseline_sev <- baseline_grade <- NA_integer_ if (length(before)) { last <- tail(before, 1) baseline_sev <- unname(ranks[sevs[last]]) baseline_grade <- grades[last] } emergent <- FALSE for (j in seq_along(times)) { if (!is.na(onset) && !is.na(trt)) { if (onset >= trt) emergent <- TRUE else if (times[j] >= trt) { rank <- unname(ranks[sevs[j]]) sev_worse <- !is.na(rank) && !is.na(baseline_sev) && rank > baseline_sev grade_worse <- !is.na(grades[j]) && !is.na(baseline_grade) && grades[j] > baseline_grade emergent <- emergent || sev_worse || grade_worse } } aseq <- aseq + 1L output[[length(output) + 1L]] <- data.frame( STUDYID = study, USUBJID = subject, ASEQ = aseq, AESEQ = as.integer(event$AESEQ), AEDECOD = event$AEDECOD, AESTDTC = onset, AEENDTC = ending, ASTDTM = times[j], AENDTM = if (j < length(times)) times[j + 1L] else ending, TRTSDTM = trt, AESEV = event$AESEV, AETOXGR = event$AETOXGR, ASEV = sevs[j], ATOXGRN = grades[j], TRTEMFL = if (emergent) 'Y' else NA_character_ ) }}dir.create('/app/output', showWarnings = FALSE)write_csv(do.call(rbind, output), '/app/output/adae.csv', na = '')solutions/adam-adae-worsening-emergence/result.py
Edit88 lines# Python reference for the yamaa benchmark adam-adae-worsening-emergence.# Uses the collected event records and dated findings to construct periods.from pathlib import Pathimport polars as pldef normalize(value): return value + ":00" if value and len(value) == 16 else valueae = pl.read_csv("/app/input/ae.csv", infer_schema=False).to_dicts()fa = pl.read_csv("/app/input/fa.csv", infer_schema=False).to_dicts()exposure = { (row["STUDYID"], row["USUBJID"]): normalize(row["TRTSDTM"]) for row in pl.read_csv("/app/input/adsl.csv", infer_schema=False).to_dicts()}severity_rank = {"MILD": 1, "MODERATE": 2, "SEVERE": 3}output = []sequences = {}for event in sorted(ae, key=lambda r: (r["STUDYID"], r["USUBJID"], int(r["AESEQ"]))): subject = event["STUDYID"], event["USUBJID"] trt = exposure.get(subject) onset, end = normalize(event["AESTDTC"]), normalize(event["AEENDTC"]) changes = {} for finding in fa: if (finding["STUDYID"], finding["USUBJID"]) != subject: continue if finding["FALNKID"] != event["AELNKID"]: continue time = normalize(finding["FADTC"]) values = changes.setdefault(time, {}) test = finding["FATESTCD"] if test in values: raise ValueError("Duplicate finding at the same event and time") values[test] = finding["FASTRESC"] states = [] sev, grade = None, None for time, values in sorted(changes.items()): if values.get("SEV") is not None: sev = values["SEV"] if values.get("TOXGR") is not None: grade = int(values["TOXGR"]) states.append((time, sev, grade)) before = [state for state in states if trt and state[0] < trt] baseline_sev = severity_rank.get(before[-1][1]) if before else None baseline_grade = before[-1][2] if before else None emergent = False for i, (time, sev, grade) in enumerate(states): if onset and trt: if onset >= trt: emergent = True elif time >= trt: rank = severity_rank.get(sev) sev_worse = ( rank is not None and baseline_sev is not None and rank > baseline_sev ) grade_worse = ( grade is not None and baseline_grade is not None and grade > baseline_grade ) emergent = emergent or sev_worse or grade_worse sequences[subject] = sequences.get(subject, 0) + 1 output.append( { "STUDYID": event["STUDYID"], "USUBJID": event["USUBJID"], "ASEQ": sequences[subject], "AESEQ": int(event["AESEQ"]), "AEDECOD": event["AEDECOD"], "AESTDTC": onset, "AEENDTC": end, "ASTDTM": time, "AENDTM": states[i + 1][0] if i + 1 < len(states) else end, "TRTSDTM": trt, "AESEV": event["AESEV"], "AETOXGR": event["AETOXGR"], "ASEV": sev, "ATOXGRN": grade, "TRTEMFL": "Y" if emergent else None, } )Path("/app/output").mkdir(exist_ok=True)pl.DataFrame(output).write_csv("/app/output/adae.csv")solutions/adam-adae-worsening-emergence/result.sas
Edit124 lines/* opensas reference for yamaa's adam-adae-worsening-emergence benchmark. Construct periods from one AE and its collected, dated FA findings. */data ae; length STUDYID USUBJID AELNKID AEDECOD AESTDTC AEENDTC AESEV AETOXGR $1024; infile '/app/input/ae.csv' dsd dlm=',' firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. AESEQ AELNKID : $char1024. AEDECOD : $char1024. AESTDTC : $char1024. AEENDTC : $char1024. AESEV : $char1024. AETOXGR : $char1024.; if lengthn(AESTDTC)=16 then AESTDTC=cats(AESTDTC,':00'); if lengthn(AEENDTC)=16 then AEENDTC=cats(AEENDTC,':00');run;data fa; length STUDYID USUBJID FALNKID FATESTCD FAOBJ FASTRESC FADTC $1024; infile '/app/input/fa.csv' dsd dlm=',' firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. FASEQ FALNKID : $char1024. FATESTCD : $char1024. FAOBJ : $char1024. FASTRESC : $char1024. FADTC : $char1024.; if lengthn(FADTC)=16 then FADTC=cats(FADTC,':00'); SEVRANK=.; if FATESTCD='SEV' then do; select(FASTRESC); when('MILD') SEVRANK=1; when('MODERATE') SEVRANK=2; when('SEVERE') SEVRANK=3; otherwise SEVRANK=.; end; end;run;data adsl; length STUDYID USUBJID TRTSDTM $1024; infile '/app/input/adsl.csv' dsd dlm=',' firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. TRTSDTM : $char1024.; if lengthn(TRTSDTM)=16 then TRTSDTM=cats(TRTSDTM,':00');run;proc sql; create table changes as select STUDYID,USUBJID,FALNKID,FADTC as ASTDTM, max(SEVRANK) as SEVCOLN, max(case when FATESTCD='TOXGR' then input(FASTRESC,best32.) else . end) as GRDCOL from fa group by STUDYID,USUBJID,FALNKID,FADTC; create table joined as select a.*,c.ASTDTM,c.SEVCOLN,c.GRDCOL,b.TRTSDTM from changes as c inner join ae as a on c.STUDYID=a.STUDYID and c.USUBJID=a.USUBJID and c.FALNKID=a.AELNKID left join adsl as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID;quit;proc sort data=joined; by STUDYID USUBJID AESEQ ASTDTM;run;data states; length ASEV $1024; set joined; by STUDYID USUBJID AESEQ; retain ASEVN ATOXGRN; if first.AESEQ then do; ASEVN=.; ATOXGRN=.; end; if not missing(SEVCOLN) then ASEVN=SEVCOLN; if not missing(GRDCOL) then ATOXGRN=GRDCOL; select(ASEVN); when(1) ASEV='MILD'; when(2) ASEV='MODERATE'; when(3) ASEV='SEVERE'; otherwise ASEV=''; end;run;/* Read the next start by scanning periods in reverse chronological order. */proc sort data=states; by STUDYID USUBJID AESEQ descending ASTDTM;run;data periods; length AENDTM NEXTSTART $1024; set states; by STUDYID USUBJID AESEQ; retain NEXTSTART; if first.AESEQ then NEXTSTART=''; if not missing(NEXTSTART) then AENDTM=NEXTSTART; else AENDTM=AEENDTC; NEXTSTART=ASTDTM;run;proc sql; create table pretreatment as select STUDYID,USUBJID,AESEQ,max(ASTDTM) as BASEDTM from periods where not missing(TRTSDTM) and ASTDTM<TRTSDTM group by STUDYID,USUBJID,AESEQ; create table baseline as select a.STUDYID,a.USUBJID,a.AESEQ, a.ASEVN as PRESEV,a.ATOXGRN as PREGRD from periods as a inner join pretreatment as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID and a.AESEQ=b.AESEQ and a.ASTDTM=b.BASEDTM; create table compared as select a.*,b.PRESEV,b.PREGRD from periods as a left join baseline as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID and a.AESEQ=b.AESEQ; create table worsening as select STUDYID,USUBJID,AESEQ,min(ASTDTM) as FIRSTWRS from compared where not missing(TRTSDTM) and ASTDTM>=TRTSDTM and ((not missing(ASEVN) and not missing(PRESEV) and ASEVN>PRESEV) or (not missing(ATOXGRN) and not missing(PREGRD) and ATOXGRN>PREGRD)) group by STUDYID,USUBJID,AESEQ; create table flagged as select a.*,b.FIRSTWRS from periods as a left join worsening as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID and a.AESEQ=b.AESEQ;quit;proc sort data=flagged; by STUDYID USUBJID AESEQ ASTDTM;run;data result; length TRTEMFL $1; set flagged; by STUDYID USUBJID; retain ASEQ; if first.USUBJID then ASEQ=0; ASEQ=ASEQ+1; TRTEMFL=''; if not missing(AESTDTC) and not missing(TRTSDTM) then do; if AESTDTC>=TRTSDTM or (not missing(FIRSTWRS) and ASTDTM>=FIRSTWRS) then TRTEMFL='Y'; end;run;proc sql; create table final as select STUDYID,USUBJID,ASEQ,AESEQ,AEDECOD,AESTDTC,AEENDTC, ASTDTM,AENDTM,TRTSDTM,AESEV,AETOXGR,ASEV,ATOXGRN,TRTEMFL from result;quit;proc export data=final outfile='/app/output/adae.csv' dbms=csv replace; run;
yamaa
Comments
Signed in with GitHub; saved in repository Discussions