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: assign each systolic blood pressure (SYSBP) record to
its analysis window, adding the analysis visit (AVISIT), its
numeric order (AVISITN), and ANL01FL; add an expected record
for each planned visit whose window holds no measurement.
Input: SDTM vital signs records (VS) carrying the test code
(VSTESTCD), the collected visit (VISIT, VISITNUM), the
collection date (VSDTC), the study day (VSDY), and the numeric
result (VSSTRESN); and SDTM subject visits (SV) listing every
planned visit of every subject, including planned visits that did
not take place, alongside the unscheduled visits.
Variables:
ADTis the analysis date, carried from the SDTM collection date (VSDTC);ADYis the analysis relative day, carried from the SDTM study day (VSDY);AVALis the analysis value, carried from the SDTM numeric result (VSSTRESN).PARAMCDmirrors the SDTM test code (VSTESTCD).AVISITis the analysis visit whose window holds the record's study day:SCREENINGbefore day 0,BASELINEon day 1 (study days skip from day -1 to day 1),WEEK 2on days 2 through 21,WEEK 4on days 22 through 42, andPOST-TREATMENTon day 43 onward with no upper bound. It is missing when the study day is missing, so such a record belongs to no window.AVISITNis the numeric order of the analysis visit:-1forSCREENING,0forBASELINE,2forWEEK 2,4forWEEK 4, and99forPOST-TREATMENT; missing when there is no window.ANL01FLisYon the record that represents its study, subject, parameter, and analysis visit: the earliest by study day, with the lower sequence number breaking a tie on the same day. It is blank on every other record, including any record with no study day; an expected record never takes the flag, even when it is the only record in its window.
Note: windows follow the study day rather than the collected visit name, so a record the site left unscheduled still belongs to whichever window its day falls in, and a record on or past day 43 falls in the open-ended final window. Each window starts with its first day and ends before the next window's first day, so day 22 opens Week 4 and day 43 opens post-treatment. A planned screening, baseline, week 2, or week 4 visit whose window holds no measured study day still appears as an expected record carrying the planned visit and window and a sequence number continuing past the subject's measurements, but no date, day, or value, so summaries see a complete visit spine. Unscheduled visits and planned visits after week 4 never get one.
Inputs
Under review2 source filesinput/sv.csv
Edit18 rows| STUDYID | USUBJID | VISITNUM | VISIT | SVPRESP | SVOCCUR | SVSTDTC |
|---|---|---|---|---|---|---|
| YAMAA-01 | 1 | SCREENING | Y | Y | 2025-01-02 | |
| YAMAA-01 | 2 | BASELINE | Y | Y | 2025-01-08 | |
| YAMAA-01 | — | UNSCHEDULED | — | Y | 2025-01-09 | |
| YAMAA-01 | — | UNSCHEDULED | — | Y | 2025-01-15 | |
| YAMAA-01 | 3 | WEEK 2 | Y | Y | 2025-01-22 | |
| YAMAA-01 | 4 | WEEK 4 | Y | Y | 2025-01-29 | |
| YAMAA-01 | 5 | WEEK 8 | Y | Y | 2025-03-08 | |
| YAMAA-01 | 1 | SCREENING | Y | Y | 2025-02-01 | |
| YAMAA-01 | 2 | BASELINE | Y | Y | 2025-02-08 | |
| YAMAA-01 | 3 | WEEK 2 | Y | Y | 2025-02-21 | |
| YAMAA-01 | — | UNSCHEDULED | — | Y | 2025-02-21 | |
| YAMAA-01 | 4 | WEEK 4 | Y | Y | 2025-03-01 | |
| YAMAA-01 | 6 | FOLLOW-UP | Y | Y | 2025-03-22 | |
| YAMAA-01 | 1 | SCREENING | Y | Y | 2025-03-01 | |
| YAMAA-01 | 2 | BASELINE | Y | Y | 2025-03-08 | |
| YAMAA-01 | 3 | WEEK 2 | Y | N | — | |
| YAMAA-01 | 4 | WEEK 4 | Y | N | — | |
| YAMAA-01 | 5 | WEEK 8 | Y | N | — |
input/vs.csv
Edit15 rows| STUDYID | USUBJID | VSTESTCD | VSSEQ | VISIT | VISITNUM | VSDTC | VSDY | VSSTRESN |
|---|---|---|---|---|---|---|---|---|
| YAMAA-01 | SYSBP | 1 | SCREENING | 1 | 2025-01-02 | -6 | 128 | |
| YAMAA-01 | SYSBP | 2 | BASELINE | 2 | 2025-01-08 | 1 | 132 | |
| YAMAA-01 | SYSBP | 3 | UNSCHEDULED | — | 2025-01-15 | 8 | 145 | |
| YAMAA-01 | SYSBP | 4 | WEEK 2 | 3 | 2025-01-22 | 15 | 138 | |
| YAMAA-01 | SYSBP | 5 | WEEK 4 | 4 | 2025-02-05 | 29 | 130 | |
| YAMAA-01 | SYSBP | 6 | WEEK 8 | 5 | 2025-03-08 | 60 | 126 | |
| YAMAA-01 | SYSBP | 7 | UNSCHEDULED | — | 2025-01-09 | 2 | 134 | |
| YAMAA-01 | SYSBP | 8 | WEEK 4 | 4 | 2025-01-29 | 22 | 131 | |
| YAMAA-01 | SYSBP | 1 | BASELINE | 2 | 2025-02-08 | 1 | 118 | |
| YAMAA-01 | SYSBP | 2 | WEEK 2 | 3 | 2025-02-21 | 14 | 122 | |
| YAMAA-01 | SYSBP | 3 | WEEK 4 | 4 | — | — | 120 | |
| YAMAA-01 | SYSBP | 4 | UNSCHEDULED | — | 2025-02-21 | 14 | 119 | |
| YAMAA-01 | SYSBP | 5 | WEEK 4 | 4 | 2025-03-01 | 22 | 124 | |
| YAMAA-01 | SYSBP | 6 | FOLLOW-UP | 6 | 2025-03-22 | 43 | 117 | |
| YAMAA-01 | SYSBP | 1 | BASELINE | 2 | 2025-03-08 | 1 | 121 |
Expected output
Under review19 expected rowsexpected/advs.csv
Edit19 rows| STUDYID | USUBJID | PARAMCD | VSSEQ | VISIT | VISITNUM | ADT | ADY | AVAL | AVISIT | AVISITN | ANL01FL |
|---|---|---|---|---|---|---|---|---|---|---|---|
| YAMAA-01 | SYSBP | 1 | SCREENING | 1 | 2025-01-02 | -6 | 128 | SCREENING | -1 | Y | |
| YAMAA-01 | SYSBP | 2 | BASELINE | 2 | 2025-01-08 | 1 | 132 | BASELINE | 0 | Y | |
| YAMAA-01 | SYSBP | 3 | UNSCHEDULED | — | 2025-01-15 | 8 | 145 | WEEK 2 | 2 | — | |
| YAMAA-01 | SYSBP | 4 | WEEK 2 | 3 | 2025-01-22 | 15 | 138 | WEEK 2 | 2 | — | |
| YAMAA-01 | SYSBP | 5 | WEEK 4 | 4 | 2025-02-05 | 29 | 130 | WEEK 4 | 4 | — | |
| YAMAA-01 | SYSBP | 6 | WEEK 8 | 5 | 2025-03-08 | 60 | 126 | POST-TREATMENT | 99 | Y | |
| YAMAA-01 | SYSBP | 7 | UNSCHEDULED | — | 2025-01-09 | 2 | 134 | WEEK 2 | 2 | Y | |
| YAMAA-01 | SYSBP | 8 | WEEK 4 | 4 | 2025-01-29 | 22 | 131 | WEEK 4 | 4 | Y | |
| YAMAA-01 | SYSBP | 1 | BASELINE | 2 | 2025-02-08 | 1 | 118 | BASELINE | 0 | Y | |
| YAMAA-01 | SYSBP | 2 | WEEK 2 | 3 | 2025-02-21 | 14 | 122 | WEEK 2 | 2 | Y | |
| YAMAA-01 | SYSBP | 3 | WEEK 4 | 4 | — | — | 120 | — | — | — | |
| YAMAA-01 | SYSBP | 4 | UNSCHEDULED | — | 2025-02-21 | 14 | 119 | WEEK 2 | 2 | — | |
| YAMAA-01 | SYSBP | 5 | WEEK 4 | 4 | 2025-03-01 | 22 | 124 | WEEK 4 | 4 | Y | |
| YAMAA-01 | SYSBP | 6 | FOLLOW-UP | 6 | 2025-03-22 | 43 | 117 | POST-TREATMENT | 99 | Y | |
| YAMAA-01 | SYSBP | 1 | BASELINE | 2 | 2025-03-08 | 1 | 121 | BASELINE | 0 | Y | |
| YAMAA-01 | SYSBP | 7 | SCREENING | 1 | — | — | — | SCREENING | -1 | — | |
| YAMAA-01 | SYSBP | 2 | SCREENING | 1 | — | — | — | SCREENING | -1 | — | |
| YAMAA-01 | SYSBP | 3 | WEEK 2 | 3 | — | — | — | WEEK 2 | 2 | — | |
| YAMAA-01 | SYSBP | 4 | WEEK 4 | 4 | — | — | — | WEEK 4 | 4 | — |
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 | PARAMCD | Parameter Code | character | Copy value from VS.VSTESTCD. | Predecessor | ||
| ADVS | VSSEQ | Sequence Number | numeric | Copy value from VS.VSSEQ. | Predecessor | ||
| ADVS | VISIT | Visit Name | character | Copy value from VS.VISIT. | Predecessor | ||
| ADVS | VISITNUM | Visit Number | numeric | Copy value from VS.VISITNUM. | Predecessor | ||
| ADVS | ADT | Analysis Date | numeric | ISO 8601 | Copy value from VS.VSDTC. | Predecessor | |
| ADVS | ADY | Analysis Relative Day | numeric | Copy value from VS.VSDY. | Predecessor | ||
| ADVS | AVAL | Analysis Value | numeric | Copy value from VS.VSSTRESN. | Predecessor | ||
| ADVS | AVISIT | Analysis Visit | character | SCREENING, BASELINE, WEEK 2, WEEK 4, POST-TREATMENT | Band ADY at 0, 2, 22, 43 into "SCREENING", "BASELINE", "WEEK 2", "WEEK 4" and "POST-TREATMENT", intervals closed on the left. | Derived | |
| ADVS | AVISITN | Analysis Visit (N) | numeric | Recode AVISIT: "SCREENING" → "-1", "BASELINE" → "0", "WEEK 2" → "2", "WEEK 4" → "4", "POST-TREATMENT" → "99"; missing values stay missing; unlisted values are errors. | Derived | ||
| ADVS | ANL01FL | Analysis Record Flag 01 | character | "Y" when AWRANK = 1 AND ADY IS NOT NULL; blank otherwise. | Derived |
| Template | Include when | EXPECTED_ORDER | STUDYID | USUBJID | PARAMCD | VISIT | VISITNUM | ADT | ADY | AVAL | AVISIT | VSSEQ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| collected | Constant "None" | None | None | None | None | None | None | None | None | None | None | |
| expected | AVISIT IS NOT NULL AND WINDOW_COVER.VSSEQ IS NULL | Row number within each group of STUDYID, USUBJID, PARAMCD, ordered by SV.VISITNUM | Copy SV.STUDYID | Copy SV.USUBJID | Constant "SYSBP" | Copy SV.VISIT | Copy SV.VISITNUM | Constant "None" | Constant "None" | Constant "None" | Recode SV.VISIT: "SCREENING" → "SCREENING", "BASELINE" → "BASELINE", "WEEK 2" → "WEEK 2", "WEEK 4" → "WEEK 4"; missing or unlisted values stay missing | Compute PRIOR_MAX.VSSEQ + EXPECTED_ORDER |
| Variable | Permitted values |
|---|---|
| AVISIT | SCREENING, BASELINE, WEEK 2, WEEK 4, POST-TREATMENT |
| 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-windows/full.md
Edit37 linesFollowing CDISC ADaM standards, use the provided SV and VS datasets to create an ADVS dataset with one record per vital signs record, plus an expected record for each planned visit whose window holds no measurement.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL
PARAMCD is the test code from VS, ADT is the collection date, ADY is the study day, and AVAL is the numeric result. AVISIT is the analysis visit whose window holds the record's study day: "SCREENING" before day 0, "BASELINE" on day 1, "WEEK 2" on days 2 through 21, "WEEK 4" on days 22 through 42, and "POST-TREATMENT" on day 43 onward with no upper bound. AVISIT has no value when the study day has no value, so such a record belongs to no window. Windows follow the study day rather than the collected visit name, so a record the site left unscheduled still belongs to whichever window its day falls in. AVISITN is -1 for "SCREENING", 0 for "BASELINE", 2 for "WEEK 2", 4 for "WEEK 4", and 99 for "POST-TREATMENT", and has no value when there is no window. ANL01FL is "Y" on the record that represents its study, subject, parameter, and analysis visit: the earliest by study day, with the lower sequence number breaking a tie on the same day. ANL01FL has no value on every other record, including any record with no study day, and an expected record never takes the flag, even when it is the only record in its window. Add an expected record for each planned visit named "SCREENING", "BASELINE", "WEEK 2", or "WEEK 4" whose window holds no measured study day for the subject, whether or not the visit took place. Unscheduled visits and planned visits after "WEEK 4" never get an expected record. An expected record carries the planned visit and its number as VISIT and VISITNUM, "SYSBP" as PARAMCD, and the analysis visit of the same name as AVISIT with its AVISITN, but no date, day, or value. An expected record's VSSEQ is the subject's largest collected VSSEQ plus its place among the subject's expected records in planned visit number order, counting from 1.
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
prompts/adam-advs-windows/conventions.md
Edit14 linesFollowing CDISC ADaM standards, use the provided SV and VS datasets to create an ADVS dataset with one record per vital signs record, plus an expected record for each planned visit whose window holds no measurement.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL
AVISITN is -1 for "SCREENING", 0 for "BASELINE", 2 for "WEEK 2", 4 for "WEEK 4", and 99 for "POST-TREATMENT", or has no value. ANL01FL is "Y" or has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
prompts/adam-advs-windows/brief.md
Edit10 linesFollowing CDISC ADaM standards, use the provided SV and VS datasets to create an ADVS dataset with one record per vital signs record, plus an expected record for each planned visit whose window holds no measurement.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL
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-windows/result.R
Edit107 lines# Reference solution for the yamaa benchmark adam-advs-windows (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)# SDTM VS staged as the ADaM input; rename to the analysis names the# rest of the solution works with.raw <- read_csv( "/app/input/vs.csv", col_types = cols( VSSEQ = col_integer(), VISITNUM = col_double(), VSDTC = col_date(), VSDY = col_integer(), VSSTRESN = col_double(), .default = col_character() )) |> rename(PARAMCD = VSTESTCD, ADT = VSDTC, ADY = VSDY, AVAL = VSSTRESN)# Windows follow the study day: screening before day 0, baseline on day# 1, weeks 2 and 4 on days 2-21 and 22-42, and post-treatment from day# 43 on with no upper bound. No study day means no window.framed <- raw |> mutate( AVISIT = case_when( is.na(ADY) ~ NA_character_, ADY < 0 ~ "SCREENING", ADY < 2 ~ "BASELINE", ADY < 22 ~ "WEEK 2", ADY < 43 ~ "WEEK 4", .default = "POST-TREATMENT" ), AVISITN = case_when( AVISIT %in% "SCREENING" ~ -1L, AVISIT %in% "BASELINE" ~ 0L, AVISIT %in% "WEEK 2" ~ 2L, AVISIT %in% "WEEK 4" ~ 4L, AVISIT %in% "POST-TREATMENT" ~ 99L ) )# SV lists every planned visit of every subject, including those that did# not take place, and the unscheduled visits.sv <- read_csv( "/app/input/sv.csv", col_types = cols(VISITNUM = col_double(), .default = col_character()))# Each planned SCREENING, BASELINE, WEEK 2, or WEEK 4 visit gets one SYSBP# expected record when no collected record's study day falls in the# analysis window of that name: the planned visit name and number and the# window, and no date, study day, or value. No other visit gets one.# Expected records continue the subject's sequence numbering after the# highest collected VSSEQ, in VISITNUM order.windows <- c("SCREENING" = -1L, "BASELINE" = 0L, "WEEK 2" = 2L, "WEEK 4" = 4L)top <- framed |> group_by(STUDYID, USUBJID) |> summarise(top_seq = max(VSSEQ), .groups = "drop")expected <- sv |> filter(VISIT %in% names(windows)) |> mutate( PARAMCD = "SYSBP", AVISIT = VISIT, AVISITN = unname(windows[VISIT]) ) |> anti_join( filter(framed, !is.na(AVISIT)), by = c("STUDYID", "USUBJID", "PARAMCD", "AVISIT") ) |> left_join(top, by = c("STUDYID", "USUBJID")) |> group_by(STUDYID, USUBJID, PARAMCD) |> arrange(VISITNUM, .by_group = TRUE) |> mutate( VSSEQ = coalesce(top_seq, 0L) + row_number(), ADT = as.Date(NA), ADY = NA_integer_, AVAL = NA_real_ ) |> ungroup() |> select( STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN )framed <- bind_rows(framed, expected)# The earliest record by study day in each study, subject, parameter,# and visit; the lower sequence number breaks a same-day tie. Expected# records have no study day and never take the flag.flagged <- framed |> filter(!is.na(AVISIT), !is.na(ADY)) |> arrange(ADY, VSSEQ) |> distinct(STUDYID, USUBJID, PARAMCD, AVISIT, .keep_all = TRUE) |> select(STUDYID, USUBJID, PARAMCD, AVISIT, VSSEQ) |> mutate(ANL01FL = "Y")advs <- framed |> left_join(flagged, by = c("STUDYID", "USUBJID", "PARAMCD", "AVISIT", "VSSEQ")) |> arrange(STUDYID, USUBJID, VSSEQ) |> select( STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL )dir.create("/app/output", showWarnings = FALSE)write_csv(advs, "/app/output/advs.csv", na = "")solutions/adam-advs-windows/result.py
Edit175 lines# Reference solution for the yamaa benchmark adam-advs-windows (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 csvfrom collections import OrderedDictINPUT_DIR = "/app/input"OUTPUT_PATH = "/app/output/advs.csv"COLUMNS = [ "STUDYID", "USUBJID", "PARAMCD", "VSSEQ", "VISIT", "VISITNUM", "ADT", "ADY", "AVAL", "AVISIT", "AVISITN", "ANL01FL",]AVISITN = { "SCREENING": -1, "BASELINE": 0, "WEEK 2": 2, "WEEK 4": 4, "POST-TREATMENT": 99,}EXPECTED_VISITS = ["SCREENING", "BASELINE", "WEEK 2", "WEEK 4"]def window_for(ady): """Analysis visit whose window holds the study day, or None.""" if ady is None: return None if ady < 0: return "SCREENING" if ady == 1: return "BASELINE" if 2 <= ady <= 21: return "WEEK 2" if 22 <= ady <= 42: return "WEEK 4" if ady >= 43: return "POST-TREATMENT" return Nonedef to_int(text): text = (text or "").strip() if text == "": return None return int(float(text))def to_num_text(text): text = (text or "").strip() if text == "": return "" value = float(text) if value == int(value): return str(int(value)) return repr(value)def read_csv(path): with open(path, newline="") as handle: return list(csv.DictReader(handle))def main(): sv_rows = read_csv(INPUT_DIR + "/sv.csv") vs_rows = read_csv(INPUT_DIR + "/vs.csv") # Planned visits per subject from SV (visit name -> visit number). planned = OrderedDict() for row in sv_rows: subject = row["USUBJID"] planned.setdefault(subject, OrderedDict()) if row["VISIT"] in EXPECTED_VISITS: planned[subject][row["VISIT"]] = to_int(row["VISITNUM"]) records = [] subjects = OrderedDict() # subject -> {"max_seq": int, "windows": set} for row in vs_rows: subject = row["USUBJID"] ady = to_int(row["VSDY"]) avisit = window_for(ady) info = subjects.setdefault(subject, {"max_seq": 0, "windows": set()}) seq = to_int(row["VSSEQ"]) info["max_seq"] = max(info["max_seq"], seq) if avisit is not None: info["windows"].add(avisit) records.append(OrderedDict([ ("STUDYID", row["STUDYID"]), ("USUBJID", subject), ("PARAMCD", row["VSTESTCD"]), ("VSSEQ", seq), ("VISIT", row["VISIT"]), ("VISITNUM", to_int(row["VISITNUM"])), ("ADT", (row["VSDTC"] or "").strip()), ("ADY", ady), ("AVAL", to_num_text(row["VSSTRESN"])), ("AVISIT", avisit or ""), ("AVISITN", AVISITN[avisit] if avisit else None), ("ANL01FL", ""), ("_expected", False), ])) # ANL01FL: earliest by study day, lower VSSEQ breaks a tie, per # study/subject/parameter/analysis visit. Records with no study day # (hence no window) never take the flag. best = {} for rec in records: if rec["ADY"] is None or rec["AVISIT"] == "": continue key = (rec["STUDYID"], rec["USUBJID"], rec["PARAMCD"], rec["AVISIT"]) rank = (rec["ADY"], rec["VSSEQ"]) if key not in best or rank < best[key][0]: best[key] = (rank, rec) for _, rec in best.values(): rec["ANL01FL"] = "Y" # Expected records for planned visits whose window holds no measured # study day for the subject. expected_by_subject = OrderedDict() for subject, visits in planned.items(): info = subjects.get(subject, {"max_seq": 0, "windows": set()}) missing = [ (num, name) for name, num in visits.items() if name not in info["windows"] ] missing.sort(key=lambda item: (item[0] is None, item[0])) expected = [] for place, (num, name) in enumerate(missing, start=1): expected.append(OrderedDict([ ("STUDYID", next( r["STUDYID"] for r in sv_rows if r["USUBJID"] == subject)), ("USUBJID", subject), ("PARAMCD", "SYSBP"), ("VSSEQ", info["max_seq"] + place), ("VISIT", name), ("VISITNUM", num), ("ADT", ""), ("ADY", None), ("AVAL", ""), ("AVISIT", name), ("AVISITN", AVISITN[name]), ("ANL01FL", ""), ("_expected", True), ])) expected_by_subject[subject] = expected # Emit collected records in input order, with each subject's expected # records (VSSEQ continuing the subject's sequence) after them. last_index = {} for i, rec in enumerate(records): last_index[rec["USUBJID"]] = i output = [] for i, rec in enumerate(records): output.append(rec) if last_index[rec["USUBJID"]] == i: output.extend(expected_by_subject.get(rec["USUBJID"], [])) for subject, expected in expected_by_subject.items(): if subject not in last_index: output.extend(expected) with open(OUTPUT_PATH, "w", newline="") as handle: writer = csv.writer(handle) writer.writerow(COLUMNS) for rec in output: writer.writerow([ "" if rec[col] is None else rec[col] for col in COLUMNS ])if __name__ == "__main__": main()solutions/adam-advs-windows/result.sas
Edit50 lines/* opensas reference solution for the yamaa benchmark adam-advs-windows. Reads the benchmark inputs and derives the requested output. Execute with the existing opensas runtime: opensas /app/output/result.sas. */data sv; length STUDYID USUBJID VISIT SVPRESP SVOCCUR SVSTDTC $1024; infile "/app/input/sv.csv" dsd dlm="," firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. VISITNUM VISIT : $char1024. SVPRESP : $char1024. SVOCCUR : $char1024. SVSTDTC : $char1024.;run;data vs; length STUDYID USUBJID VSTESTCD VISIT VSDTC VSDY $1024; infile "/app/input/vs.csv" dsd dlm="," firstobs=2 truncover lrecl=32767; input STUDYID : $char1024. USUBJID : $char1024. VSTESTCD : $char1024. VSSEQ VISIT : $char1024. VISITNUM VSDTC : $char1024. VSDY : $char1024. VSSTRESN;run;data collected; length PARAMCD $16 ADT $10 AVISIT $20 ANL01FL $1; set vs; PARAMCD=VSTESTCD; ADT=VSDTC; ADY=input(VSDY,best32.); AVAL=VSSTRESN; if not missing(ADY) then do; if ADY<0 then do; AVISIT='SCREENING'; AVISITN=-1; end; else if ADY=1 then do; AVISIT='BASELINE'; AVISITN=0; end; else if ADY>=2 and ADY<=21 then do; AVISIT='WEEK 2'; AVISITN=2; end; else if ADY>=22 and ADY<=42 then do; AVISIT='WEEK 4'; AVISITN=4; end; else if ADY>=43 then do; AVISIT='POST-TREATMENT'; AVISITN=99; end; end;run;proc sort data=collected; by STUDYID USUBJID PARAMCD AVISITN ADY VSSEQ; run;data flagged; set collected; by STUDYID USUBJID PARAMCD AVISITN; if first.AVISITN and not missing(AVISITN) then ANL01FL='Y'; run;proc sql; create table maxima as select STUDYID,USUBJID,max(VSSEQ) as maximum from collected group by STUDYID,USUBJID; create table absent as select a.*,b.maximum from sv as a left join maxima as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID where a.VISIT in ('SCREENING','BASELINE','WEEK 2','WEEK 4') and not exists(select * from collected as c where a.STUDYID=c.STUDYID and a.USUBJID=c.USUBJID and c.PARAMCD='SYSBP' and a.VISIT=c.AVISIT);quit;proc sort data=absent; by STUDYID USUBJID VISITNUM; run;data expected; length PARAMCD $16 ADT $10 AVISIT $20 ANL01FL $1; set absent; by STUDYID USUBJID; if first.USUBJID then counter=coalesce(maximum,0); counter+1; VSSEQ=counter; PARAMCD='SYSBP'; AVISIT=VISIT; select(VISIT); when('SCREENING') AVISITN=-1; when('BASELINE') AVISITN=0; when('WEEK 2') AVISITN=2; when('WEEK 4') AVISITN=4; otherwise; end; ADY=.; AVAL=.;run;data result; set flagged expected; run;proc sql; create table final as select STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL from result;quit;proc export data=final outfile="/app/output/advs.csv" dbms=csv replace; run;
yamaa