As a clinical trial statistician or programmer, challenge anything in this benchmark: describe a problem in Comments, or propose a fix with the Edit button on any source file.
- Task: Would a real study need this derivation, specified this way? Does it follow CDISC ADaM: variable names, controlled terms, record structure? Flag any rule that is ambiguous or that a sponsor would handle differently.
- Inputs: Do they look like data collected in a real trial, and do they include the situations you would expect to meet in one?
- Expected output: Would independent QC programming reproduce every value from these inputs and rules?
The other tabs beside Comments are background for assessment, not under review.
Summary
README.mdGoal: 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 | — |
Comments and assessment materials
| 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; a missing source → blank. | 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.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
Edit47 linesFollowing CDISC ADaM standards, use the provided SDTM VS and SV datasets to create an ADVS dataset with one record per measurement, plus one expected record for each planned visit whose window holds no measurement. Derive PARAMCD from VSTESTCD, ADT from VSDTC, ADY from VSDY, and AVAL from VSSTRESN; then window on ADY as specified below.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL
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. It has no value when the study day is missing, so such a record belongs to no window. Study days skip from day -1 to day 1.
AVISITN is the numeric order of the analysis visit: -1 for SCREENING, 0 for BASELINE, 2 for WEEK 2, 4 for WEEK 4, and 99 for POST-TREATMENT; it 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. It has no value on every other record, including any record with no study day.
A planned visit whose window holds no measurement still appears as an expected record, so summaries see a complete visit spine. SV lists each subject's planned visits, including those that did not take place, and the unscheduled visits. 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; no other visit gets one. An expected record carries the planned visit name and number and the window's AVISIT and AVISITN, has no date, study day, or value, and never takes ANL01FL, even when it is the only record in its window. Expected records continue the subject's sequence numbering after the highest collected VSSEQ, in VISITNUM order.
Windows follow the study day rather than the collected visit name, so a record left unscheduled still belongs to whichever window its day falls in. 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.
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
prompts/adam-advs-windows/conventions.md
Edit20 linesFollowing CDISC ADaM standards, use the provided SDTM VS and SV datasets to create an ADVS dataset with one record per measurement, plus one expected record for each planned visit whose window holds no measurement. Derive PARAMCD from VSTESTCD, ADT from VSDTC, ADY from VSDY, and AVAL from VSSTRESN; then window on ADY as specified below.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, PARAMCD, VSSEQ, VISIT, VISITNUM, ADT, ADY, AVAL, AVISIT, AVISITN, ANL01FL
AVISIT is SCREENING, BASELINE, WEEK 2, WEEK 4, or POST-TREATMENT, or has no value. AVISITN is -1, 0, 2, 4, or 99 in that order. ANL01FL is Y or has no value.
An expected record carries the planned visit name and number, the window's AVISIT and AVISITN, a continued VSSEQ, and no date, day, or value; it never takes ANL01FL. POST-TREATMENT never gets one.
Read the source datasets from /app/input and save the completed dataset as /app/output/advs.csv.
prompts/adam-advs-windows/brief.md
Edit12 linesFollowing CDISC ADaM standards, use the provided SDTM VS and SV datasets to create an ADVS dataset with one record per measurement, plus one expected record for each planned visit whose window holds no measurement. Derive PARAMCD from VSTESTCD, ADT from VSDTC, ADY from VSDY, and AVAL from VSSTRESN; then window on ADY as specified below.
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.
run.R
Edit4 lineslibrary(yamaa)advs <- yamaa_domain("spec.yaml")$outputadvsrun.py
Edit4 linesimport yamaaadvs = yamaa.yamaa_domain("spec.yaml").outputadvssolutions/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
Edit122 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.from pathlib import Pathimport polars as pl# SDTM VS staged as the ADaM input; rename to the analysis names the# rest of the solution works with.raw = ( pl.read_csv("/app/input/vs.csv", infer_schema=False) .rename( { "VSTESTCD": "PARAMCD", "VSDTC": "ADT", "VSDY": "ADY", "VSSTRESN": "AVAL", } ) .with_columns( pl.col("VSSEQ").cast(pl.Int64, strict=False), pl.col("VISITNUM").cast(pl.Float64, strict=False), pl.col("ADT").str.to_date(strict=False), pl.col("ADY").cast(pl.Int64, strict=False), pl.col("AVAL").cast(pl.Float64, strict=False), ))def visit(day: int | None) -> tuple[str | None, int | None]: if day is None: return None, None if day < 0: return "SCREENING", -1 if day < 2: return "BASELINE", 0 if day < 22: return "WEEK 2", 2 if day < 43: return "WEEK 4", 4 return "POST-TREATMENT", 99framed = raw.with_columns( pl.col("ADY") .map_elements(lambda d: visit(d)[0], return_dtype=pl.String) .alias("AVISIT"), pl.col("ADY") .map_elements(lambda d: visit(d)[1], return_dtype=pl.Int64) .alias("AVISITN"),)# SV lists every planned visit of every subject, including those that did# not take place, and the unscheduled visits.sv = pl.read_csv("/app/input/sv.csv", infer_schema=False).with_columns( pl.col("VISITNUM").cast(pl.Float64, strict=False))# 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 = {"SCREENING": -1, "BASELINE": 0, "WEEK 2": 2, "WEEK 4": 4}keys = ["STUDYID", "USUBJID", "PARAMCD"]covered = framed.select(*keys, "AVISIT").drop_nulls().unique()top = framed.group_by("STUDYID", "USUBJID").agg(pl.col("VSSEQ").max().alias("TOP"))expected = ( sv.filter(pl.col("VISIT").is_in(list(windows))) .with_columns( PARAMCD=pl.lit("SYSBP"), AVISIT=pl.col("VISIT"), AVISITN=pl.col("VISIT").replace_strict(windows, return_dtype=pl.Int64), ) .join(covered, on=[*keys, "AVISIT"], how="anti") .join(top, on=["STUDYID", "USUBJID"], how="left") .sort([*keys, "VISITNUM"]) .with_columns( VSSEQ=pl.col("TOP").fill_null(0) + pl.int_range(1, pl.len() + 1, dtype=pl.Int64).over(keys), ADT=pl.lit(None, dtype=pl.Date), ADY=pl.lit(None, dtype=pl.Int64), AVAL=pl.lit(None, dtype=pl.Float64), ) .select( *keys, "VSSEQ", "VISIT", "VISITNUM", "ADT", "ADY", "AVAL", "AVISIT", "AVISITN", ))framed = pl.concat([framed, expected], how="vertical")# 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(pl.col("AVISIT").is_not_null() & pl.col("ADY").is_not_null()) .sort(["ADY", "VSSEQ"]) .unique(["STUDYID", "USUBJID", "PARAMCD", "AVISIT"], keep="first", maintain_order=True) .select("STUDYID", "USUBJID", "PARAMCD", "AVISIT", "VSSEQ") .with_columns(ANL01FL=pl.lit("Y")))advs = ( framed.join( flagged, on=["STUDYID", "USUBJID", "PARAMCD", "AVISIT", "VSSEQ"], how="left", ) .sort(["STUDYID", "USUBJID", "VSSEQ"]) .select( "STUDYID", "USUBJID", "PARAMCD", "VSSEQ", "VISIT", "VISITNUM", "ADT", "ADY", "AVAL", "AVISIT", "AVISITN", "ANL01FL", ))Path("/app/output").mkdir(parents=True, exist_ok=True)advs.write_csv("/app/output/advs.csv")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
Comments
Signed in with GitHub; saved in repository Discussions