Review ask

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

Lifecycle: draftEditUnder review
What this benchmark means
README.md

Public 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:

  • PARAMCD and PARAM name 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 an OHYPO record, Y when 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; N when both changes are present and neither falls that far. On an OTACHY record, Y when heart rate rises by 30 beats/min or more and N when 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 review
1 source file

input/vs.csv

Edit
26 rows
input/vs.csv
STUDYIDUSUBJIDVSSEQVISITVSTESTCDVSPOSVSTPTVSSTRESN
YAMAA-011BASELINESYSBPSUPINEAFTER 5 MIN SUPINE130
YAMAA-012BASELINEDIABPSUPINEAFTER 5 MIN SUPINE80
YAMAA-013BASELINEHRSUPINEAFTER 5 MIN SUPINE70
YAMAA-014BASELINESYSBPSTANDINGAFTER 3 MIN STANDING110
YAMAA-015BASELINEDIABPSTANDINGAFTER 3 MIN STANDING74
YAMAA-016BASELINEHRSTANDINGAFTER 3 MIN STANDING100
YAMAA-017WEEK 2SYSBPSUPINEAFTER 5 MIN SUPINE128
YAMAA-018WEEK 2DIABPSUPINEAFTER 5 MIN SUPINE82
YAMAA-019WEEK 2HRSUPINEAFTER 5 MIN SUPINE72
YAMAA-0110WEEK 2SYSBPSTANDINGAFTER 1 MIN STANDING104
YAMAA-0111WEEK 2DIABPSTANDINGAFTER 1 MIN STANDING70
YAMAA-0112WEEK 2HRSTANDINGAFTER 1 MIN STANDING106
YAMAA-0113WEEK 2SYSBPSTANDINGAFTER 3 MIN STANDING109
YAMAA-0114WEEK 2DIABPSTANDINGAFTER 3 MIN STANDING73
YAMAA-0115WEEK 2HRSTANDINGAFTER 3 MIN STANDING101
YAMAA-011BASELINESYSBPSUPINEAFTER 5 MIN SUPINE118
YAMAA-012BASELINEDIABPSUPINEAFTER 5 MIN SUPINE78
YAMAA-013BASELINEHRSUPINEAFTER 5 MIN SUPINE66
YAMAA-014BASELINESYSBPSTANDINGAFTER 3 MIN STANDING—
YAMAA-015BASELINEDIABPSTANDINGAFTER 3 MIN STANDING68
YAMAA-016BASELINEHRSTANDINGAFTER 3 MIN STANDING84
YAMAA-017WEEK 2SYSBPSUPINEAFTER 5 MIN SUPINE124
YAMAA-018WEEK 2DIABPSUPINEAFTER 5 MIN SUPINE79
YAMAA-019WEEK 2HRSUPINEAFTER 5 MIN SUPINE64
YAMAA-0110WEEK 2SYSBPSTANDINGAFTER 3 MIN STANDING116
YAMAA-0111WEEK 2DIABPSTANDINGAFTER 3 MIN STANDING—

Expected output

Under review
15 expected rows

expected/advs.csv

Edit
15 rows
expected/advs.csv
STUDYIDUSUBJIDAVISITPARAMCDPARAMAVALAVALC
YAMAA-01BASELINESYSBPOCSystolic Blood Pressure Change on Standing (mmHg)-20—
YAMAA-01WEEK 2SYSBPOCSystolic Blood Pressure Change on Standing (mmHg)-19—
YAMAA-01WEEK 2SYSBPOCSystolic Blood Pressure Change on Standing (mmHg)-8—
YAMAA-01BASELINEDIABPOCDiastolic Blood Pressure Change on Standing (mmHg)-6—
YAMAA-01WEEK 2DIABPOCDiastolic Blood Pressure Change on Standing (mmHg)-9—
YAMAA-01BASELINEDIABPOCDiastolic Blood Pressure Change on Standing (mmHg)-10—
YAMAA-01BASELINEHROCHeart Rate Change on Standing (beats/min)30—
YAMAA-01WEEK 2HROCHeart Rate Change on Standing (beats/min)29—
YAMAA-01BASELINEHROCHeart Rate Change on Standing (beats/min)18—
YAMAA-01BASELINEOHYPOOrthostatic Hypotension—Y
YAMAA-01WEEK 2OHYPOOrthostatic Hypotension—N
YAMAA-01BASELINEOHYPOOrthostatic Hypotension—Y
YAMAA-01BASELINEOTACHYOrthostatic Tachycardia—Y
YAMAA-01WEEK 2OTACHYOrthostatic Tachycardia—N
YAMAA-01BASELINEOTACHYOrthostatic Tachycardia—N
Shaded columns are derived— = missing value

Human review and assessment

Your review

3 questions and your comments · View benchmark discussions

Mapping spec

Generated from the benchmark YAML; do not edit by hand

Dataset NameVariable NameVariable LabelTypeCodelist/Controlled TermsCoreComputational MethodOrigin
ADVSSTUDYIDStudy IdentifiercharacterCopy value from VS.STUDYID.Predecessor
ADVSUSUBJIDUnique Subject IdentifiercharacterCopy value from VS.USUBJID.Predecessor
ADVSAVISITAnalysis VisitcharacterCopy value from VS.VISIT.Predecessor
ADVSPARAMCDParameter CodecharacterSet per constructed row; see the Row construction sheet.Derived
ADVSPARAMParametercharacterSet per constructed row; see the Row construction sheet.Derived
ADVSAVALAnalysis ValuenumericSet constant value "None".Assigned
ADVSAVALCAnalysis Value (C)characterY, NSet constant value "None".Assigned
TemplateInclude whenPARAMCDPARAMSYSBP_SUPSYSBP_STDAVALDIABP_SUPDIABP_STDHR_SUPHR_STDAVALC
systolic_changeAVAL IS NOT NULLConstant "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_CHGNoneNoneNoneNoneNone
diastolic_changeAVAL IS NOT NULLConstant "DIABPOC"Constant "Diastolic Blood Pressure Change on Standing (mmHg)"NoneNoneCopy DIABP_CHGAggregate 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'NoneNoneNone
heart_rate_changeAVAL IS NOT NULLConstant "HROC"Constant "Heart Rate Change on Standing (beats/min)"NoneNoneCopy HR_CHGNoneNoneAggregate 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_hypotensionAVALC IS NOT NULLConstant "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'NoneAggregate 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'NoneNone"Y" when SYSBP_CHG <= -20 OR DIABP_CHG <= -10; "N" otherwise; blank when the condition is unknown
orthostatic_tachycardiaAVALC IS NOT NULLConstant "OTACHY"Constant "Orthostatic Tachycardia"NoneNoneNoneNoneNoneAggregate 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
VariablePermitted values
AVALCY, N
VersionDateAuthorDescriptionReviewerSign-off
1.72026-10-20yamaa docs buildRead 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.62026-10-17yamaa docs buildDescribe collected date parts written as ISO 8601 date text and times of day counted in seconds since midnight
1.52026-10-17yamaa docs buildName 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.42026-10-15yamaa docs buildState datetime precision codes through the hour and minute, and complete only the time parts a collected datetime lacks
1.32026-09-29yamaa docs buildShow study codelist names, external dictionaries, and ISO 8601 formats in variable rows; list the document's codelist values and metadata
1.22026-09-29yamaa docs buildClassify ADaM copies from a declared input as Predecessor and recodes as Derived, and SDTM recodes of locally derived columns as Derived
1.12026-09-29yamaa docs buildResolve lookups into the donor record they select, and give every derivation shape a plain-language rule instead of its raw YAML
1.0yamaa docs buildInitial generation from spec.yaml

Agent prompt

The request an agent receives with the input files; each tier states no more than the one above

prompts/adam-advs-orthostatic-criteria/full.md

Edit
33 lines

Following 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

Edit
18 lines

Following 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

Edit
8 lines

Following 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.

yamaa code

Public calls generated from benchmark.yaml; results must match the expected output

R

Edit
3 lines
library(yamaa)yamaa_spec("spec.yaml")$run()$output

Python

Edit
3 lines
import yamaayamaa.spec("spec.yaml").run().output

Solution without yamaa

Written from the full prompt and the inputs alone; CI checks it reproduces the expected output

solutions/adam-advs-orthostatic-criteria/result.R

Edit
112 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

Edit
136 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

Edit
75 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;