As a clinical trial statistician or programmer, answer three short questions in Your review: the task, the inputs and outputs, and the AI-assisted review. Agreeing with all three approves this benchmark; disagreeing with any needs a comment. Propose a fix with the Edit button on any source file, or add it to your comments.
We suggest spending no more than 5 minutes on a review. The other tabs beside Your review are background for assessment, not under review.
Summary
README.mdPublic entries: Python and R. Passing coverage requires an installed inventory.
Goal: for each subject and visit, derive the change on standing in
systolic blood pressure (SYSBPOC), diastolic blood pressure (DIABPOC)
and heart rate (HROC), and flag orthostatic hypotension (OHYPO) and
orthostatic tachycardia (OTACHY).
Input: collected vital signs with systolic (SYSBP) and diastolic
(DIABP) blood pressure in mmHg and heart rate (HR) in beats/min, taken
supine and then standing at the same visit; the position is in VSPOS and
the planned time point in VSTPT: a standing reading after three minutes
and, at some visits, an earlier one after one minute.
Variables:
PARAMCDandPARAMname the change or the flag the record holds.AVAL: on a change record, the test's reading after three minutes standing minus its supine reading at the same visit, not rounded, so a fall is negative. The reading after one minute is never used. No change record is added when either reading is missing or was not taken. Empty on a flag record.AVALC: on anOHYPOrecord,Ywhen systolic pressure falls by 20 mmHg or more or diastolic pressure falls by 10 mmHg or more, either fall being enough even when the other change is missing;Nwhen both changes are present and neither falls that far. On anOTACHYrecord,Ywhen heart rate rises by 30 beats/min or more andNwhen it rises less. Empty on a change record.
Note: each threshold includes its boundary, so a fall of exactly 20 or
10 mmHg, or a rise of exactly 30 beats/min, meets it. A visit gets no
OHYPO record when neither change meets its threshold but one of them is
missing, and no OTACHY record when the heart rate change is missing. A
test with more than one supine reading, or more than one reading after three
minutes standing, at one visit stops the run rather than choosing one.
Inputs
Under review1 source fileinput/vs.csv
Edit26 rows| STUDYID | USUBJID | VSSEQ | VISIT | VSTESTCD | VSPOS | VSTPT | VSSTRESN |
|---|---|---|---|---|---|---|---|
| YAMAA-01 | 1 | BASELINE | SYSBP | SUPINE | AFTER 5 MIN SUPINE | 130 | |
| YAMAA-01 | 2 | BASELINE | DIABP | SUPINE | AFTER 5 MIN SUPINE | 80 | |
| YAMAA-01 | 3 | BASELINE | HR | SUPINE | AFTER 5 MIN SUPINE | 70 | |
| YAMAA-01 | 4 | BASELINE | SYSBP | STANDING | AFTER 3 MIN STANDING | 110 | |
| YAMAA-01 | 5 | BASELINE | DIABP | STANDING | AFTER 3 MIN STANDING | 74 | |
| YAMAA-01 | 6 | BASELINE | HR | STANDING | AFTER 3 MIN STANDING | 100 | |
| YAMAA-01 | 7 | WEEK 2 | SYSBP | SUPINE | AFTER 5 MIN SUPINE | 128 | |
| YAMAA-01 | 8 | WEEK 2 | DIABP | SUPINE | AFTER 5 MIN SUPINE | 82 | |
| YAMAA-01 | 9 | WEEK 2 | HR | SUPINE | AFTER 5 MIN SUPINE | 72 | |
| YAMAA-01 | 10 | WEEK 2 | SYSBP | STANDING | AFTER 1 MIN STANDING | 104 | |
| YAMAA-01 | 11 | WEEK 2 | DIABP | STANDING | AFTER 1 MIN STANDING | 70 | |
| YAMAA-01 | 12 | WEEK 2 | HR | STANDING | AFTER 1 MIN STANDING | 106 | |
| YAMAA-01 | 13 | WEEK 2 | SYSBP | STANDING | AFTER 3 MIN STANDING | 109 | |
| YAMAA-01 | 14 | WEEK 2 | DIABP | STANDING | AFTER 3 MIN STANDING | 73 | |
| YAMAA-01 | 15 | WEEK 2 | HR | STANDING | AFTER 3 MIN STANDING | 101 | |
| YAMAA-01 | 1 | BASELINE | SYSBP | SUPINE | AFTER 5 MIN SUPINE | 118 | |
| YAMAA-01 | 2 | BASELINE | DIABP | SUPINE | AFTER 5 MIN SUPINE | 78 | |
| YAMAA-01 | 3 | BASELINE | HR | SUPINE | AFTER 5 MIN SUPINE | 66 | |
| YAMAA-01 | 4 | BASELINE | SYSBP | STANDING | AFTER 3 MIN STANDING | — | |
| YAMAA-01 | 5 | BASELINE | DIABP | STANDING | AFTER 3 MIN STANDING | 68 | |
| YAMAA-01 | 6 | BASELINE | HR | STANDING | AFTER 3 MIN STANDING | 84 | |
| YAMAA-01 | 7 | WEEK 2 | SYSBP | SUPINE | AFTER 5 MIN SUPINE | 124 | |
| YAMAA-01 | 8 | WEEK 2 | DIABP | SUPINE | AFTER 5 MIN SUPINE | 79 | |
| YAMAA-01 | 9 | WEEK 2 | HR | SUPINE | AFTER 5 MIN SUPINE | 64 | |
| YAMAA-01 | 10 | WEEK 2 | SYSBP | STANDING | AFTER 3 MIN STANDING | 116 | |
| YAMAA-01 | 11 | WEEK 2 | DIABP | STANDING | AFTER 3 MIN STANDING | — |
Expected output
Under review15 expected rowsexpected/advs.csv
Edit15 rows| STUDYID | USUBJID | AVISIT | PARAMCD | PARAM | AVAL | AVALC |
|---|---|---|---|---|---|---|
| YAMAA-01 | BASELINE | SYSBPOC | Systolic Blood Pressure Change on Standing (mmHg) | -20 | — | |
| YAMAA-01 | WEEK 2 | SYSBPOC | Systolic Blood Pressure Change on Standing (mmHg) | -19 | — | |
| YAMAA-01 | WEEK 2 | SYSBPOC | Systolic Blood Pressure Change on Standing (mmHg) | -8 | — | |
| YAMAA-01 | BASELINE | DIABPOC | Diastolic Blood Pressure Change on Standing (mmHg) | -6 | — | |
| YAMAA-01 | WEEK 2 | DIABPOC | Diastolic Blood Pressure Change on Standing (mmHg) | -9 | — | |
| YAMAA-01 | BASELINE | DIABPOC | Diastolic Blood Pressure Change on Standing (mmHg) | -10 | — | |
| YAMAA-01 | BASELINE | HROC | Heart Rate Change on Standing (beats/min) | 30 | — | |
| YAMAA-01 | WEEK 2 | HROC | Heart Rate Change on Standing (beats/min) | 29 | — | |
| YAMAA-01 | BASELINE | HROC | Heart Rate Change on Standing (beats/min) | 18 | — | |
| YAMAA-01 | BASELINE | OHYPO | Orthostatic Hypotension | — | Y | |
| YAMAA-01 | WEEK 2 | OHYPO | Orthostatic Hypotension | — | N | |
| YAMAA-01 | BASELINE | OHYPO | Orthostatic Hypotension | — | Y | |
| YAMAA-01 | BASELINE | OTACHY | Orthostatic Tachycardia | — | Y | |
| YAMAA-01 | WEEK 2 | OTACHY | Orthostatic Tachycardia | — | N | |
| YAMAA-01 | BASELINE | OTACHY | Orthostatic Tachycardia | — | N |
Human review and assessment
| Dataset Name | Variable Name | Variable Label | Type | Codelist/Controlled Terms | Core | Computational Method | Origin |
|---|---|---|---|---|---|---|---|
| ADVS | STUDYID | Study Identifier | character | Copy value from VS.STUDYID. | Predecessor | ||
| ADVS | USUBJID | Unique Subject Identifier | character | Copy value from VS.USUBJID. | Predecessor | ||
| ADVS | AVISIT | Analysis Visit | character | Copy value from VS.VISIT. | Predecessor | ||
| ADVS | PARAMCD | Parameter Code | character | Set per constructed row; see the Row construction sheet. | Derived | ||
| ADVS | PARAM | Parameter | character | Set per constructed row; see the Row construction sheet. | Derived | ||
| ADVS | AVAL | Analysis Value | numeric | Set constant value "None". | Assigned | ||
| ADVS | AVALC | Analysis Value (C) | character | Y, N | Set constant value "None". | Assigned |
| Template | Include when | PARAMCD | PARAM | SYSBP_SUP | SYSBP_STD | AVAL | DIABP_SUP | DIABP_STD | HR_SUP | HR_STD | AVALC |
|---|---|---|---|---|---|---|---|---|---|---|---|
| systolic_change | AVAL IS NOT NULL | Constant "SYSBPOC" | Constant "Systolic Blood Pressure Change on Standing (mmHg)" | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'SYSBP' AND VS.VSPOS = 'SUPINE' | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'SYSBP' AND VS.VSPOS = 'STANDING' AND VS.VSTPT = 'AFTER 3 MIN STANDING' | Copy SYSBP_CHG | None | None | None | None | None |
| diastolic_change | AVAL IS NOT NULL | Constant "DIABPOC" | Constant "Diastolic Blood Pressure Change on Standing (mmHg)" | None | None | Copy DIABP_CHG | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'DIABP' AND VS.VSPOS = 'SUPINE' | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'DIABP' AND VS.VSPOS = 'STANDING' AND VS.VSTPT = 'AFTER 3 MIN STANDING' | None | None | None |
| heart_rate_change | AVAL IS NOT NULL | Constant "HROC" | Constant "Heart Rate Change on Standing (beats/min)" | None | None | Copy HR_CHG | None | None | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'HR' AND VS.VSPOS = 'SUPINE' | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'HR' AND VS.VSPOS = 'STANDING' AND VS.VSTPT = 'AFTER 3 MIN STANDING' | None |
| orthostatic_hypotension | AVALC IS NOT NULL | Constant "OHYPO" | Constant "Orthostatic Hypotension" | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'SYSBP' AND VS.VSPOS = 'SUPINE' | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'SYSBP' AND VS.VSPOS = 'STANDING' AND VS.VSTPT = 'AFTER 3 MIN STANDING' | None | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'DIABP' AND VS.VSPOS = 'SUPINE' | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'DIABP' AND VS.VSPOS = 'STANDING' AND VS.VSTPT = 'AFTER 3 MIN STANDING' | None | None | "Y" when SYSBP_CHG <= -20 OR DIABP_CHG <= -10; "N" otherwise; blank when the condition is unknown |
| orthostatic_tachycardia | AVALC IS NOT NULL | Constant "OTACHY" | Constant "Orthostatic Tachycardia" | None | None | None | None | None | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'HR' AND VS.VSPOS = 'SUPINE' | Aggregate ONLY(VS.VSSTRESN) over records matching on the shared output keys, where VS.VSTESTCD = 'HR' AND VS.VSPOS = 'STANDING' AND VS.VSTPT = 'AFTER 3 MIN STANDING' | "Y" when HR_CHG >= 30; "N" otherwise; blank when the condition is unknown |
| Variable | Permitted values |
|---|---|
| AVALC | Y, N |
| Version | Date | Author | Description | Reviewer | Sign-off |
|---|---|---|---|---|---|
| 1.7 | 2026-10-20 | yamaa docs build | Read a specification in the 1.0 surface as its 0.5 counterpart; state that missing values stay missing where a mapping declares no missing handler, and leave out a declared missing answer that restates a handler's default | ||
| 1.6 | 2026-10-17 | yamaa docs build | Describe collected date parts written as ISO 8601 date text and times of day counted in seconds since midnight | ||
| 1.5 | 2026-10-17 | yamaa docs build | Name collected precision in words instead of letter codes; state imputation fallbacks, minimum source precision, bounds ignored outside the collected period, and invalid text with no handler as an error; describe date and datetime shifts, imputation flag codes, and partial text giving no date part | ||
| 1.4 | 2026-10-15 | yamaa docs build | State datetime precision codes through the hour and minute, and complete only the time parts a collected datetime lacks | ||
| 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-advs-orthostatic-criteria/full.md
Edit33 linesFollowing CDISC ADaM standards, use the provided VS dataset to create an ADVS dataset with one record per subject per visit per parameter.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, AVISIT, PARAMCD, PARAM, AVAL, AVALC
PARAMCD and PARAM name the change or the flag the record holds: SYSBPOC is "Systolic Blood Pressure Change on Standing (mmHg)", DIABPOC is "Diastolic Blood Pressure Change on Standing (mmHg)", HROC is "Heart Rate Change on Standing (beats/min)", OHYPO is "Orthostatic Hypotension", and OTACHY is "Orthostatic Tachycardia".
On a change record, AVAL is the test's reading after three minutes standing minus its supine reading at the same visit, not rounded, so a fall is negative. The reading after one minute standing is never used. No change record is added when either reading is missing or was not taken. AVALC has no value on a change record, and AVAL has no value on a flag record.
On an OHYPO record, AVALC is "Y" when systolic blood pressure falls by 20 mmHg or more or diastolic blood pressure falls by 10 mmHg or more, and either fall is enough on its own even when the other change is missing. AVALC is "N" when both changes are present and neither falls that far. A visit has no OHYPO record when neither change meets its threshold but one of the changes is missing.
On an OTACHY record, AVALC is "Y" when heart rate rises by 30 beats/min or more and "N" when it rises less. A visit has no OTACHY record when the heart rate change is missing. Each threshold includes its boundary, so a fall of exactly 20 or 10 mmHg, or a rise of exactly 30 beats/min, meets it.
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
prompts/adam-advs-orthostatic-criteria/conventions.md
Edit18 linesFollowing CDISC ADaM standards, use the provided VS dataset to create an ADVS dataset with one record per subject per visit per parameter.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, AVISIT, PARAMCD, PARAM, AVAL, AVALC
PARAMCD and PARAM name the change or the flag the record holds: SYSBPOC is "Systolic Blood Pressure Change on Standing (mmHg)", DIABPOC is "Diastolic Blood Pressure Change on Standing (mmHg)", HROC is "Heart Rate Change on Standing (beats/min)", OHYPO is "Orthostatic Hypotension", and OTACHY is "Orthostatic Tachycardia".
On a change record, AVAL is not rounded. AVALC is "Y" or "N" on a flag record and has no value on a change record, and AVAL has no value on a flag record.
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
prompts/adam-advs-orthostatic-criteria/brief.md
Edit8 linesFollowing CDISC ADaM standards, use the provided VS dataset to create an ADVS dataset with one record per subject per visit per parameter.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, AVISIT, PARAMCD, PARAM, AVAL, AVALC
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
R
Edit3 lineslibrary(yamaa)yamaa_spec("spec.yaml")$run()$outputPython
Edit3 linesimport yamaayamaa.spec("spec.yaml").run().outputsolutions/adam-advs-orthostatic-criteria/result.R
Edit112 lines# Reference solution for the yamaa benchmark# adam-advs-orthostatic-criteria (R track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1.library(dplyr, warn.conflicts = FALSE)library(readr)vs <- read_csv( "/app/input/vs.csv", col_types = cols( VSSEQ = col_integer(), VSSTRESN = col_double(), .default = col_character() ))# The one reading of a test in a position at a visit; no such reading,# or a reading with no result, gives no value.only_value <- function(mask, values) { picked <- values[which(mask)] if (length(picked) > 1) { stop("more than one reading for a test, position and visit") } if (length(picked) == 0) NA_real_ else picked}standing <- "AFTER 3 MIN STANDING"visits <- vs |> group_by(STUDYID, USUBJID, AVISIT = VISIT) |> summarise( SYSBP_SUP = only_value(VSTESTCD == "SYSBP" & VSPOS == "SUPINE", VSSTRESN), SYSBP_STD = only_value( VSTESTCD == "SYSBP" & VSPOS == "STANDING" & VSTPT == standing, VSSTRESN ), DIABP_SUP = only_value(VSTESTCD == "DIABP" & VSPOS == "SUPINE", VSSTRESN), DIABP_STD = only_value( VSTESTCD == "DIABP" & VSPOS == "STANDING" & VSTPT == standing, VSSTRESN ), HR_SUP = only_value(VSTESTCD == "HR" & VSPOS == "SUPINE", VSSTRESN), HR_STD = only_value( VSTESTCD == "HR" & VSPOS == "STANDING" & VSTPT == standing, VSSTRESN ), .groups = "drop" ) |> mutate( SYSBP_CHG = SYSBP_STD - SYSBP_SUP, DIABP_CHG = DIABP_STD - DIABP_SUP, HR_CHG = HR_STD - HR_SUP )change_record <- function(visits, paramcd, param, column) { visits |> filter(!is.na(.data[[column]])) |> transmute( STUDYID, USUBJID, AVISIT, PARAMCD = paramcd, PARAM = param, AVAL = .data[[column]], AVALC = NA_character_ )}# Either blood-pressure fall is enough for Y, even when the other# change is missing; N needs both changes, so a visit with neither# fall and one change missing gets no record.hypotension <- visits |> mutate( AVALC = case_when( (!is.na(SYSBP_CHG) & SYSBP_CHG <= -20) | (!is.na(DIABP_CHG) & DIABP_CHG <= -10) ~ "Y", !is.na(SYSBP_CHG) & !is.na(DIABP_CHG) ~ "N", .default = NA_character_ ) ) |> filter(!is.na(AVALC)) |> transmute( STUDYID, USUBJID, AVISIT, PARAMCD = "OHYPO", PARAM = "Orthostatic Hypotension", AVAL = NA_real_, AVALC )tachycardia <- visits |> mutate( AVALC = case_when( !is.na(HR_CHG) & HR_CHG >= 30 ~ "Y", !is.na(HR_CHG) ~ "N", .default = NA_character_ ) ) |> filter(!is.na(AVALC)) |> transmute( STUDYID, USUBJID, AVISIT, PARAMCD = "OTACHY", PARAM = "Orthostatic Tachycardia", AVAL = NA_real_, AVALC )advs <- bind_rows( change_record( visits, "SYSBPOC", "Systolic Blood Pressure Change on Standing (mmHg)", "SYSBP_CHG" ), change_record( visits, "DIABPOC", "Diastolic Blood Pressure Change on Standing (mmHg)", "DIABP_CHG" ), change_record( visits, "HROC", "Heart Rate Change on Standing (beats/min)", "HR_CHG" ), hypotension, tachycardia) |> select(STUDYID, USUBJID, AVISIT, PARAMCD, PARAM, AVAL, AVALC)dir.create("/app/output", showWarnings = FALSE)write_csv(advs, "/app/output/advs.csv", na = "")solutions/adam-advs-orthostatic-criteria/result.py
Edit136 lines# Reference solution for the yamaa benchmark adam-advs-orthostatic-criteria (Python track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1."""Build ADVS orthostatic change and flag records from the VS dataset.One record per subject per visit per parameter: SYSBPOC / DIABPOC / HROC - change records (3-minute standing minus supine) OHYPO / OTACHY - flag records"""import csvimport osINPUT_DIR = "/app/input"OUTPUT_DIR = "/app/output"PARAMS = { "SYSBPOC": "Systolic Blood Pressure Change on Standing (mmHg)", "DIABPOC": "Diastolic Blood Pressure Change on Standing (mmHg)", "HROC": "Heart Rate Change on Standing (beats/min)", "OHYPO": "Orthostatic Hypotension", "OTACHY": "Orthostatic Tachycardia",}# Source test code behind each change parameter.CHANGE_TESTS = { "SYSBPOC": "SYSBP", "DIABPOC": "DIABP", "HROC": "HR",}def parse_number(text): """Return the numeric value of a cell, or None when missing.""" if text is None: return None text = text.strip() if not text: return None return float(text)def format_number(value): """Write integral values without a decimal point.""" if value == int(value): return str(int(value)) return repr(value)def main(): with open(os.path.join(INPUT_DIR, "vs.csv"), newline="") as handle: rows = list(csv.DictReader(handle)) # readings[(study, subject, visit, test)] = (supine, standing_3min) readings = {} visit_order = {} subject_order = [] for row in rows: key = (row["STUDYID"], row["USUBJID"]) if key not in visit_order: visit_order[key] = [] subject_order.append(key) if row["VISIT"] not in visit_order[key]: visit_order[key].append(row["VISIT"]) value = parse_number(row["VSSTRESN"]) if value is None: slot_value = None else: slot_value = value entry = readings.setdefault( (row["STUDYID"], row["USUBJID"], row["VISIT"], row["VSTESTCD"]), {"supine": None, "standing": None}, ) if row["VSPOS"] == "SUPINE": entry["supine"] = slot_value elif row["VSPOS"] == "STANDING" and "3 MIN" in row["VSTPT"]: # Only the reading after three minutes standing is used; # the one-minute standing reading never counts. entry["standing"] = slot_value def change(study, subject, visit, test): entry = readings.get((study, subject, visit, test)) if entry is None or entry["supine"] is None or entry["standing"] is None: return None return entry["standing"] - entry["supine"] records = [] for study, subject in subject_order: for visit in visit_order[(study, subject)]: changes = { param: change(study, subject, visit, test) for param, test in CHANGE_TESTS.items() } for param in ("SYSBPOC", "DIABPOC", "HROC"): if changes[param] is not None: records.append( [study, subject, visit, param, PARAMS[param], format_number(changes[param]), ""] ) # Orthostatic hypotension flag. sys_chg = changes["SYSBPOC"] dia_chg = changes["DIABPOC"] sys_fall = sys_chg is not None and sys_chg <= -20 dia_fall = dia_chg is not None and dia_chg <= -10 if sys_fall or dia_fall: avalc = "Y" elif sys_chg is not None and dia_chg is not None: avalc = "N" else: avalc = None # neither meets threshold, one change missing if avalc is not None: records.append( [study, subject, visit, "OHYPO", PARAMS["OHYPO"], "", avalc] ) # Orthostatic tachycardia flag. hr_chg = changes["HROC"] if hr_chg is not None: avalc = "Y" if hr_chg >= 30 else "N" records.append( [study, subject, visit, "OTACHY", PARAMS["OTACHY"], "", avalc] ) os.makedirs(OUTPUT_DIR, exist_ok=True) with open(os.path.join(OUTPUT_DIR, "advs.csv"), "w", newline="") as handle: writer = csv.writer(handle) writer.writerow( ["STUDYID", "USUBJID", "AVISIT", "PARAMCD", "PARAM", "AVAL", "AVALC"] ) writer.writerows(records)if __name__ == "__main__": main()solutions/adam-advs-orthostatic-criteria/result.sas
Edit75 lines/* opensas reference solution for the yamaa benchmark adam-advs-orthostatic-criteria. Reads the benchmark inputs and derives the requested output. Execute with the existing opensas runtime: opensas /app/output/result.sas. */data vs; length STUDYID USUBJID VISIT VSTESTCD VSPOS VSTPT $1024; infile "/app/input/vs.csv" dsd dlm="," firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. VSSEQ VISIT : $char1024. VSTESTCD : $char1024. VSPOS : $char1024. VSTPT : $char1024. VSSTRESN;run;/* A test with more than one supine reading, or more than one reading after three minutes standing, at one visit stops the run rather than choosing one: count the readings of each kind first, before the aggregations below can pick one. */proc sql; create table dup_readings as select STUDYID, USUBJID, VISIT, VSTESTCD, count(*) as N from (select STUDYID, USUBJID, VISIT, VSTESTCD, VSPOS, case when VSPOS='SUPINE' then '' else VSTPT end as TPTKEY from vs where VSTESTCD in ('SYSBP','DIABP','HR') and (VSPOS='SUPINE' or (VSPOS='STANDING' and VSTPT='AFTER 3 MIN STANDING'))) as r group by STUDYID, USUBJID, VISIT, VSTESTCD, VSPOS, TPTKEY having count(*) > 1;quit;data _null_; set dup_readings; abort;run;/* One row per subject and visit: the supine reading and the reading after three minutes standing of each test. The reading after one minute standing is never used. */proc sql; create table visits as select STUDYID, USUBJID, VISIT as AVISIT, max(case when VSTESTCD='SYSBP' and VSPOS='SUPINE' then VSSTRESN end) as SYSBP_SUP, max(case when VSTESTCD='SYSBP' and VSPOS='STANDING' and VSTPT='AFTER 3 MIN STANDING' then VSSTRESN end) as SYSBP_STD, max(case when VSTESTCD='DIABP' and VSPOS='SUPINE' then VSSTRESN end) as DIABP_SUP, max(case when VSTESTCD='DIABP' and VSPOS='STANDING' and VSTPT='AFTER 3 MIN STANDING' then VSSTRESN end) as DIABP_STD, max(case when VSTESTCD='HR' and VSPOS='SUPINE' then VSSTRESN end) as HR_SUP, max(case when VSTESTCD='HR' and VSPOS='STANDING' and VSTPT='AFTER 3 MIN STANDING' then VSSTRESN end) as HR_STD from vs group by STUDYID, USUBJID, VISIT;quit;/* Changes are standing minus supine. Either blood-pressure fall is enough for Y, even when the other change is missing; N needs both changes. A missing value never meets a threshold in these tests because each comparison first checks the value is present. */data flagged; length OHYPO OTACHY $1; set visits; SYSBP_CHG=SYSBP_STD-SYSBP_SUP; DIABP_CHG=DIABP_STD-DIABP_SUP; HR_CHG=HR_STD-HR_SUP; if (not missing(SYSBP_CHG) and SYSBP_CHG<=-20) or (not missing(DIABP_CHG) and DIABP_CHG<=-10) then OHYPO='Y'; else if not missing(SYSBP_CHG) and not missing(DIABP_CHG) then OHYPO='N'; if not missing(HR_CHG) and HR_CHG>=30 then OTACHY='Y'; else if not missing(HR_CHG) then OTACHY='N';run;proc sql; create table result as select STUDYID, USUBJID, AVISIT, 'DIABPOC' as PARAMCD, 'Diastolic Blood Pressure Change on Standing (mmHg)' as PARAM, DIABP_CHG as AVAL, '' as AVALC from flagged where not missing(DIABP_CHG) union all select STUDYID, USUBJID, AVISIT, 'SYSBPOC' as PARAMCD, 'Systolic Blood Pressure Change on Standing (mmHg)' as PARAM, SYSBP_CHG as AVAL, '' as AVALC from flagged where not missing(SYSBP_CHG) union all select STUDYID, USUBJID, AVISIT, 'HROC' as PARAMCD, 'Heart Rate Change on Standing (beats/min)' as PARAM, HR_CHG as AVAL, '' as AVALC from flagged where not missing(HR_CHG) union all select STUDYID, USUBJID, AVISIT, 'OHYPO' as PARAMCD, 'Orthostatic Hypotension' as PARAM, . as AVAL, OHYPO as AVALC from flagged where not missing(OHYPO) union all select STUDYID, USUBJID, AVISIT, 'OTACHY' as PARAMCD, 'Orthostatic Tachycardia' as PARAM, . as AVAL, OTACHY as AVALC from flagged where not missing(OTACHY);quit;proc export data=result(keep=STUDYID USUBJID AVISIT PARAMCD PARAM AVAL AVALC) outfile="/app/output/advs.csv" dbms=csv replace; run;
yamaa