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: derive ANRIND, BASE, BNRIND, SHIFT1, R2BASE,
CRIT1, CRIT1FL, CRIT2, and CRIT2FL: mark where each analysis
value sits against its normal range, how that mark moved since
baseline, and whether the record met a high-result criterion or a
low-result criterion.
Input: laboratory records carrying the analysis value AVAL, the
normal range limits ANRLO and ANRHI, and the baseline flag
ABLFL (Y on the record taken as the baseline for the subject
and parameter).
Variables:
-
ANRINDis the record's own mark:LOWbelowANRLO,HIGHaboveANRHI, andNORMALbetween them, limits included, so a result exactly at a limit readsNORMAL; empty whenAVAL,ANRLO, orANRHIis missing, since one missing limit makes the mark unclassifiable. -
BASErepeats the baseline record'sAVALon every record of the subject and parameter; empty when no record carries the flag. -
BNRINDrepeats the baseline record'sANRINDthe same way; empty with no flagged baseline, or when the baseline record itself could not be marked. -
SHIFT1joins the baseline mark and the record's own mark, baseline first, so a result that stayed normal readsNORMAL to NORMALand one that moved out of range readsNORMAL to HIGH; empty when either mark is missing - the record's own or the baseline's. -
R2BASEdividesAVALbyBASE, so the baseline record itself reads 1 when the ratio can be computed; empty whenAVALis missing, when there is no baseline, and when the baseline is zero since the multiple is not defined there. -
CRIT1states the criterion the record was assessed against, a result greater than three times the upper limit of normal (ULN):Result greater than 3 x ULN; empty whenAVALorANRHIis missing, since the comparison cannot be made. -
CRIT1FLsays whether the record met it,YorN; empty where it could not be assessed, which differs from assessed and not met. A result exactly at three times the limit does not meet it - the comparison is strictly greater than. -
CRIT2states the second criterion the record was assessed against, a result less than the lower limit of normal (LLN):Result less than LLN; empty whenAVALorANRLOis missing, since the comparison cannot be made. It is assessed independently of the first: a record whose upper limit is missing can still meet the low criterion. -
CRIT2FLsays whether the record met it,YorN; empty where it could not be assessed. A result exactly at the lower limit does not meet it - the comparison is strictly less than.
Note: the shift joins the baseline mark with the record's own mark and the ratio rests on the flagged baseline value, while the mark and the criteria rest on the record's own value and limits; each criterion text and its flag always arrive together, as do the mark and the shift. A record that breaks these pairings stops the run, and no output is written.
Inputs
Under review1 source fileinput/adlb_raw.csv
Edit17 rows| STUDYID | USUBJID | PARAMCD | PARAM | ASEQ | AVISIT | AVAL | ANRLO | ANRHI | ABLFL |
|---|---|---|---|---|---|---|---|---|---|
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 1 | BASELINE | 30 | 0 | 40 | Y | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 2 | WEEK 2 | 60 | 0 | 40 | — | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 3 | WEEK 4 | 150 | 0 | 40 | — | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 4 | WEEK 8 | 40 | 0 | 40 | — | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 1 | BASELINE | 45 | 0 | 40 | Y | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 2 | WEEK 2 | 18 | 0 | 40 | — | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 3 | WEEK 4 | — | 0 | 40 | — | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 4 | WEEK 8 | 120 | 0 | 40 | — | |
| YAMAA-01 | EOS | Eosinophils (%) | 1 | BASELINE | 0 | 1 | 6 | Y | |
| YAMAA-01 | EOS | Eosinophils (%) | 2 | WEEK 2 | 4 | 1 | 6 | — | |
| YAMAA-01 | EOS | Eosinophils (%) | 3 | WEEK 4 | 1 | 1 | 6 | — | |
| YAMAA-01 | LDH | Lactate Dehydrogenase (U/L) | 3 | BASELINE | 200 | — | — | Y | |
| YAMAA-01 | LDH | Lactate Dehydrogenase (U/L) | 4 | WEEK 2 | 260 | — | — | — | |
| YAMAA-01 | GGT | Gamma Glutamyl Transferase (U/L) | 5 | BASELINE | 55 | 10 | — | Y | |
| YAMAA-01 | GGT | Gamma Glutamyl Transferase (U/L) | 6 | WEEK 2 | 70 | 10 | — | — | |
| YAMAA-01 | EOS | Eosinophils (%) | 4 | WEEK 8 | 0.5 | 1 | 6 | — | |
| YAMAA-01 | GGT | Gamma Glutamyl Transferase (U/L) | 7 | WEEK 4 | 5 | 10 | — | — |
Expected output
Under review17 expected rowsexpected/adlb.csv
Edit17 rows| STUDYID | USUBJID | PARAMCD | PARAM | ASEQ | AVISIT | AVAL | ANRLO | ANRHI | ANRIND | ABLFL | BASE | BNRIND | SHIFT1 | R2BASE | CRIT1 | CRIT1FL | CRIT2 | CRIT2FL |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 1 | BASELINE | 30 | 0 | 40 | NORMAL | Y | 30 | NORMAL | NORMAL to NORMAL | 1 | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 2 | WEEK 2 | 60 | 0 | 40 | HIGH | — | 30 | NORMAL | NORMAL to HIGH | 2 | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 3 | WEEK 4 | 150 | 0 | 40 | HIGH | — | 30 | NORMAL | NORMAL to HIGH | 5 | Result greater than 3 x ULN | Y | Result less than LLN | N | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 4 | WEEK 8 | 40 | 0 | 40 | NORMAL | — | 30 | NORMAL | NORMAL to NORMAL | 1.3333333333333333 | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 1 | BASELINE | 45 | 0 | 40 | HIGH | Y | 45 | HIGH | HIGH to HIGH | 1 | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 2 | WEEK 2 | 18 | 0 | 40 | NORMAL | — | 45 | HIGH | HIGH to NORMAL | 0.4 | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 3 | WEEK 4 | — | 0 | 40 | — | — | 45 | HIGH | — | — | — | — | — | — | |
| YAMAA-01 | ALT | Alanine Aminotransferase (U/L) | 4 | WEEK 8 | 120 | 0 | 40 | HIGH | — | 45 | HIGH | HIGH to HIGH | 2.6666666666666665 | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | EOS | Eosinophils (%) | 1 | BASELINE | 0 | 1 | 6 | LOW | Y | 0 | LOW | LOW to LOW | — | Result greater than 3 x ULN | N | Result less than LLN | Y | |
| YAMAA-01 | EOS | Eosinophils (%) | 2 | WEEK 2 | 4 | 1 | 6 | NORMAL | — | 0 | LOW | LOW to NORMAL | — | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | EOS | Eosinophils (%) | 3 | WEEK 4 | 1 | 1 | 6 | NORMAL | — | 0 | LOW | LOW to NORMAL | — | Result greater than 3 x ULN | N | Result less than LLN | N | |
| YAMAA-01 | LDH | Lactate Dehydrogenase (U/L) | 3 | BASELINE | 200 | — | — | — | Y | 200 | — | — | 1 | — | — | — | — | |
| YAMAA-01 | LDH | Lactate Dehydrogenase (U/L) | 4 | WEEK 2 | 260 | — | — | — | — | 200 | — | — | 1.3 | — | — | — | — | |
| YAMAA-01 | GGT | Gamma Glutamyl Transferase (U/L) | 5 | BASELINE | 55 | 10 | — | — | Y | 55 | — | — | 1 | — | — | Result less than LLN | N | |
| YAMAA-01 | GGT | Gamma Glutamyl Transferase (U/L) | 6 | WEEK 2 | 70 | 10 | — | — | — | 55 | — | — | 1.2727272727272727 | — | — | Result less than LLN | N | |
| YAMAA-01 | EOS | Eosinophils (%) | 4 | WEEK 8 | 0.5 | 1 | 6 | LOW | — | 0 | LOW | LOW to LOW | — | Result greater than 3 x ULN | N | Result less than LLN | Y | |
| YAMAA-01 | GGT | Gamma Glutamyl Transferase (U/L) | 7 | WEEK 4 | 5 | 10 | — | — | — | 55 | — | — | 0.09090909090909091 | — | — | Result less than LLN | Y |
Human review and assessment
| Dataset Name | Variable Name | Variable Label | Type | Codelist/Controlled Terms | Core | Computational Method | Origin |
|---|---|---|---|---|---|---|---|
| ADLB | STUDYID | Study Identifier | character | Copy value from ADLB_RAW.STUDYID. | Predecessor | ||
| ADLB | USUBJID | Unique Subject Identifier | character | Copy value from ADLB_RAW.USUBJID. | Predecessor | ||
| ADLB | PARAMCD | Parameter Code | character | Copy value from ADLB_RAW.PARAMCD. | Predecessor | ||
| ADLB | PARAM | Parameter | character | Copy value from ADLB_RAW.PARAM. | Predecessor | ||
| ADLB | ASEQ | Analysis Sequence Number | numeric | Copy value from ADLB_RAW.ASEQ. | Predecessor | ||
| ADLB | AVISIT | Analysis Visit | character | Copy value from ADLB_RAW.AVISIT. | Predecessor | ||
| ADLB | AVAL | Analysis Value | numeric | Copy value from ADLB_RAW.AVAL. | Predecessor | ||
| ADLB | ANRLO | Analysis Normal Range Lower Limit | numeric | Copy value from ADLB_RAW.ANRLO. | Predecessor | ||
| ADLB | ANRHI | Analysis Normal Range Upper Limit | numeric | Copy value from ADLB_RAW.ANRHI. | Predecessor | ||
| ADLB | ANRIND | Analysis Reference Range Indicator | character | LOW, NORMAL, HIGH | If AVAL IS NULL OR ANRLO IS NULL OR ANRHI IS NULL then "None"; If AVAL < ANRLO then "LOW"; If AVAL > ANRHI then "HIGH"; otherwise "NORMAL". | Derived | |
| ADLB | ABLFL | Baseline Record Flag | character | Y | Copy value from ADLB_RAW.ABLFL. | Predecessor | |
| ADLB | BASE | Baseline Value | numeric | Aggregate ONLY(AVAL) over records grouped by STUDYID, USUBJID, PARAMCD, matching on the shared output keys, where ABLFL = 'Y'. | Derived | ||
| ADLB | BNRIND | Baseline Reference Range Indicator | character | LOW, NORMAL, HIGH | Aggregate ONLY(ANRIND) over records grouped by STUDYID, USUBJID, PARAMCD, matching on the shared output keys, where ABLFL = 'Y'. | Derived | |
| ADLB | SHIFT1 | Shift 1 | character | Fill the template "{BNRIND} to {ANRIND}"; a missing field → blank. | Derived | ||
| ADLB | R2BASE | Ratio to Baseline | numeric | Compute AVAL / NULLIF(BASE, 0). | Derived | ||
| ADLB | CRIT1 | Analysis Criterion 1 | character | If AVAL IS NOT NULL AND CRITLIM IS NOT NULL then "Result greater than 3 x ULN"; otherwise blank. | Derived | ||
| ADLB | CRIT1FL | Criterion 1 Evaluation Result Flag | character | Y, N | If AVAL IS NULL OR CRITLIM IS NULL then "None"; If AVAL > CRITLIM then "Y"; otherwise "N". | Derived | |
| ADLB | CRIT2 | Analysis Criterion 2 | character | If AVAL IS NOT NULL AND ANRLO IS NOT NULL then "Result less than LLN"; otherwise blank. | Derived | ||
| ADLB | CRIT2FL | Criterion 2 Evaluation Result Flag | character | Y, N | If AVAL IS NULL OR ANRLO IS NULL then "None"; If AVAL < ANRLO then "Y"; otherwise "N". | Derived |
| Variable | Permitted values |
|---|---|
| ANRIND | LOW, NORMAL, HIGH |
| ABLFL | Y |
| BNRIND | LOW, NORMAL, HIGH |
| CRIT1FL | Y, N |
| CRIT2FL | 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-adlb-shift-criteria/full.md
Edit44 linesFollowing CDISC ADaM standards, use the provided ADLB_RAW dataset to create an ADLB dataset with one record per laboratory record.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, PARAM, ASEQ, AVISIT, AVAL, ANRLO, ANRHI, ANRIND, ABLFL, BASE, BNRIND, SHIFT1, R2BASE, CRIT1, CRIT1FL, CRIT2, CRIT2FL
- ANRIND is "LOW" when AVAL is below ANRLO, "HIGH" when AVAL is above ANRHI, and "NORMAL" when AVAL is between ANRLO and ANRHI, limits included, so a result exactly at a limit is "NORMAL".
- ANRIND has no value when AVAL, ANRLO, or ANRHI has no value.
- BASE repeats the baseline record's AVAL on every record of the subject and parameter, where the baseline record is the one with ABLFL "Y".
- BASE has no value when no record of the subject and parameter has ABLFL "Y".
- BNRIND repeats the baseline record's ANRIND on every record of the subject and parameter.
- BNRIND has no value when there is no baseline record, or when the baseline record's own ANRIND has no value.
- SHIFT1 is the baseline mark and the record's own mark joined by " to ", baseline first, so a record that stayed normal reads "NORMAL to NORMAL" and one that moved out of range reads "NORMAL to HIGH".
- SHIFT1 has no value when either ANRIND or BNRIND has no value.
- R2BASE is AVAL divided by BASE, so the baseline record itself reads 1 when the ratio can be computed.
- R2BASE has no value when AVAL has no value, when there is no baseline, or when BASE is zero.
- R2BASE is not rounded.
- CRIT1 is "Result greater than 3 x ULN" when AVAL and ANRHI have values, and has no value when AVAL or ANRHI has no value.
- CRIT1FL is "Y" when AVAL is greater than three times ANRHI and "N" when it is not, and a result exactly at three times ANRHI does not meet the criterion.
- CRIT1FL has no value when AVAL or ANRHI has no value.
- CRIT2 is "Result less than LLN" when AVAL and ANRLO have values, and has no value when AVAL or ANRLO has no value.
- CRIT2 is assessed independently of CRIT1, so a record whose ANRHI has no value can still meet the low criterion.
- CRIT2FL is "Y" when AVAL is less than ANRLO and "N" when it is not, and a result exactly at ANRLO does not meet the criterion.
- CRIT2FL has no value when AVAL or ANRLO has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/adlb.csv.
prompts/adam-adlb-shift-criteria/conventions.md
Edit16 linesFollowing CDISC ADaM standards, use the provided ADLB_RAW dataset to create an ADLB dataset with one record per laboratory record.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, PARAM, ASEQ, AVISIT, AVAL, ANRLO, ANRHI, ANRIND, ABLFL, BASE, BNRIND, SHIFT1, R2BASE, CRIT1, CRIT1FL, CRIT2, CRIT2FL
ANRIND is "LOW", "HIGH", or "NORMAL", or has no value. SHIFT1 is the baseline mark and the record's own mark joined by " to ", or has no value. R2BASE is not rounded. CRIT1 is "Result greater than 3 x ULN" or has no value, and CRIT1FL is "Y" or "N", or has no value. CRIT2 is "Result less than LLN" or has no value, and CRIT2FL is "Y" or "N", or has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/adlb.csv.
prompts/adam-adlb-shift-criteria/brief.md
Edit9 linesFollowing CDISC ADaM standards, use the provided ADLB_RAW dataset to create an ADLB dataset with one record per laboratory record.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, PARAM, ASEQ, AVISIT, AVAL, ANRLO, ANRHI, ANRIND, ABLFL, BASE, BNRIND, SHIFT1, R2BASE, CRIT1, CRIT1FL, CRIT2, CRIT2FL
Read the source datasets from /app/input and save the completed dataset as /app/output/adlb.csv.
R
Edit3 lineslibrary(yamaa)yamaa_spec("spec.yaml")$run()$outputPython
Edit3 linesimport yamaayamaa.spec("spec.yaml").run().outputsolutions/adam-adlb-shift-criteria/result.R
Edit88 lines# Reference solution for the yamaa benchmark adam-adlb-shift-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)raw <- read_csv( "/app/input/adlb_raw.csv", col_types = cols( ASEQ = col_integer(), AVAL = col_double(), ANRLO = col_double(), ANRHI = col_double(), .default = col_character() ))# The record's own mark: LOW below the lower limit, HIGH above the upper# limit, NORMAL between them limits included. No value when the result or# either limit is missing.based <- raw |> mutate( ANRIND = case_when( is.na(AVAL) | is.na(ANRLO) | is.na(ANRHI) ~ NA_character_, AVAL < ANRLO ~ "LOW", AVAL > ANRHI ~ "HIGH", .default = "NORMAL" ) )# BASE repeats the flagged baseline record's value; BNRIND repeats its# mark. Both have no value when no record carries the flag.baselines <- based |> filter(ABLFL %in% "Y") |> select(STUDYID, USUBJID, PARAMCD, BASE = AVAL, BNRIND = ANRIND)with_base <- based |> left_join(baselines, by = c("STUDYID", "USUBJID", "PARAMCD"))# SHIFT1 joins the baseline mark and the record's own mark; R2BASE is the# record as a multiple of the baseline; CRIT1 assesses greater than three# times the upper limit; CRIT2 assesses less than the lower limit.adlb <- with_base |> mutate( SHIFT1 = if_else( is.na(BNRIND) | is.na(ANRIND), NA_character_, paste(BNRIND, "to", ANRIND) ), R2BASE = if_else( is.na(AVAL) | is.na(BASE) | BASE == 0, NA_real_, AVAL / BASE ), CRITLIM = 3 * ANRHI, CRIT1 = if_else( !is.na(AVAL) & !is.na(CRITLIM), "Result greater than 3 x ULN", NA_character_ ), CRIT1FL = case_when( is.na(AVAL) | is.na(CRITLIM) ~ NA_character_, AVAL > CRITLIM ~ "Y", .default = "N" ), CRIT2 = if_else( !is.na(AVAL) & !is.na(ANRLO), "Result less than LLN", NA_character_ ), CRIT2FL = case_when( is.na(AVAL) | is.na(ANRLO) ~ NA_character_, AVAL < ANRLO ~ "Y", .default = "N" ) ) |> arrange(USUBJID, ASEQ) |> select( STUDYID, USUBJID, PARAMCD, PARAM, ASEQ, AVISIT, AVAL, ANRLO, ANRHI, ANRIND, ABLFL, BASE, BNRIND, SHIFT1, R2BASE, CRIT1, CRIT1FL, CRIT2, CRIT2FL )dir.create("/app/output", showWarnings = FALSE)write_csv(adlb, "/app/output/adlb.csv", na = "")solutions/adam-adlb-shift-criteria/result.py
Edit129 lines# Reference solution for the yamaa benchmark adam-adlb-shift-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.import csvimport osINPUT_DIR = "/app/input"OUTPUT_DIR = "/app/output"def to_float(value): if value is None: return None value = value.strip() if value == "": return None return float(value)def fmt_number(x): if x == int(x): return str(int(x)) return repr(x)def main(): with open(os.path.join(INPUT_DIR, "adlb_raw.csv"), newline="") as f: rows = list(csv.DictReader(f)) # Per-record ANRIND for row in rows: aval = to_float(row["AVAL"]) anrlo = to_float(row["ANRLO"]) anrhi = to_float(row["ANRHI"]) if aval is None or anrlo is None or anrhi is None: row["_ANRIND"] = "" elif aval < anrlo: row["_ANRIND"] = "LOW" elif aval > anrhi: row["_ANRIND"] = "HIGH" else: row["_ANRIND"] = "NORMAL" # Baseline values per subject and parameter baselines = {} for row in rows: if row["ABLFL"].strip() == "Y": baselines[(row["USUBJID"], row["PARAMCD"])] = row out_rows = [] for row in rows: aval = to_float(row["AVAL"]) anrlo = to_float(row["ANRLO"]) anrhi = to_float(row["ANRHI"]) anrind = row["_ANRIND"] base_row = baselines.get((row["USUBJID"], row["PARAMCD"])) if base_row is None: base_txt = "" base_val = None bnrind = "" else: base_txt = base_row["AVAL"] base_val = to_float(base_row["AVAL"]) bnrind = base_row["_ANRIND"] if anrind == "" or bnrind == "": shift1 = "" else: shift1 = bnrind + " to " + anrind if aval is None or base_val is None or base_val == 0: r2base = "" else: r2base = fmt_number(aval / base_val) if aval is not None and anrhi is not None: crit1 = "Result greater than 3 x ULN" crit1fl = "Y" if aval > 3 * anrhi else "N" else: crit1 = "" crit1fl = "" if aval is not None and anrlo is not None: crit2 = "Result less than LLN" crit2fl = "Y" if aval < anrlo else "N" else: crit2 = "" crit2fl = "" out_rows.append({ "STUDYID": row["STUDYID"], "USUBJID": row["USUBJID"], "PARAMCD": row["PARAMCD"], "PARAM": row["PARAM"], "ASEQ": row["ASEQ"], "AVISIT": row["AVISIT"], "AVAL": row["AVAL"], "ANRLO": row["ANRLO"], "ANRHI": row["ANRHI"], "ANRIND": anrind, "ABLFL": row["ABLFL"], "BASE": base_txt, "BNRIND": bnrind, "SHIFT1": shift1, "R2BASE": r2base, "CRIT1": crit1, "CRIT1FL": crit1fl, "CRIT2": crit2, "CRIT2FL": crit2fl, }) fieldnames = [ "STUDYID", "USUBJID", "PARAMCD", "PARAM", "ASEQ", "AVISIT", "AVAL", "ANRLO", "ANRHI", "ANRIND", "ABLFL", "BASE", "BNRIND", "SHIFT1", "R2BASE", "CRIT1", "CRIT1FL", "CRIT2", "CRIT2FL", ] os.makedirs(OUTPUT_DIR, exist_ok=True) with open(os.path.join(OUTPUT_DIR, "adlb.csv"), "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(out_rows)if __name__ == "__main__": main()solutions/adam-adlb-shift-criteria/result.sas
Edit35 lines/* opensas reference solution for the yamaa benchmark adam-adlb-shift-criteria. Reads the benchmark inputs and derives the requested output. Execute with the existing opensas runtime: opensas /app/output/result.sas. */data adlb_raw; length STUDYID USUBJID PARAMCD PARAM AVISIT ABLFL $1024; infile "/app/input/adlb_raw.csv" dsd dlm="," firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. PARAMCD : $char1024. PARAM : $char1024. ASEQ AVISIT : $char1024. AVAL ANRLO ANRHI ABLFL : $char1024.;run;data marked; length ANRIND $6; set adlb_raw; if not missing(AVAL) and not missing(ANRLO) and not missing(ANRHI) then do; if AVAL<ANRLO then ANRIND='LOW'; else if AVAL>ANRHI then ANRIND='HIGH'; else ANRIND='NORMAL'; end;run;proc sql; create table combined as select a.*,b.AVAL as BASE,b.ANRIND as BNRIND from marked as a left join marked as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID and a.PARAMCD=b.PARAMCD and b.ABLFL='Y'; quit;data result; length SHIFT1 $20 CRIT1 $30 CRIT2 $30 CRIT1FL CRIT2FL $1; set combined; if not missing(ANRIND) and not missing(BNRIND) then SHIFT1=catx(' to ',BNRIND,ANRIND); if not missing(AVAL) and not missing(BASE) and BASE ne 0 then R2BASE=AVAL/BASE; if not missing(AVAL) and not missing(ANRHI) then do; CRIT1='Result greater than 3 x ULN'; CRIT1FL='N'; if AVAL>3*ANRHI then CRIT1FL='Y'; end; if not missing(AVAL) and not missing(ANRLO) then do; CRIT2='Result less than LLN'; CRIT2FL='N'; if AVAL<ANRLO then CRIT2FL='Y'; end;run;proc sql; create table final as select STUDYID, USUBJID, PARAMCD, PARAM, ASEQ, AVISIT, AVAL, ANRLO, ANRHI, ANRIND, ABLFL, BASE, BNRIND, SHIFT1, R2BASE, CRIT1, CRIT1FL, CRIT2, CRIT2FL from result;quit;proc export data=final outfile="/app/output/adlb.csv" dbms=csv replace; run;
yamaa