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 SDTM: 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: build one RS record per subject and scheduled tumor
assessment holding the visit order (AVISITN), the assessment date
(ADT), a per-subject record number (RSSEQ), the response test
(RSTESTCD/RSTEST), the response (RSSTRESC), and the completion
status (RSSTAT).
Input: long-form Operational Data Model (ODM) item data. Each
scheduled tumor assessment (IG.VISIT) carries its visit name, visit
order, and date. Each lesion measured at an assessment is a repeated
item group, IG.TRTARGET for a target lesion and IG.TRNT for a
non-target one, carrying the lesion link and the longest diameter. The
lesions chosen at study entry are listed in IG.TUTARGET and
IG.TUNT.
Variables:
AVISITNis the numeric order of the assessment, carried from the scheduled assessment; it orders the assessments of a subject.ADTis the date of the assessment, carried from the scheduled assessment.RSSEQnumbers a subject's response records in visit order, starting at 1.RSTESTCDisTRGRESPandRSTESTisTimepoint Responseon every record.RSSTRESCis the response at the assessment:NE(not evaluable) at baseline, when fewer target lesions were measured than were chosen, when the subject has non-target disease only, or when no percent change can be computed (for example a zero or missing baseline sum);CR(complete response) when every target lesion has disappeared;PR(partial response) when the target sum shrank at least 30% from baseline;PD(progressive disease) when it grew at least 20% from baseline;SD(stable disease) otherwise. It stays blank when the assessment was not done.RSSTATisNOT DONEfor a scheduled assessment with no tumor measurement records at all; blank otherwise.
Note: a baseline assessment is never compared against itself, so
its response is NE whenever it was done. An assessment with some but
not all chosen target lesions measured is still done, and its response
is NE rather than a guess from partial data.
Inputs
Under review1 source fileinput/odm.csv
Edit66 rows| StudyOID | MetaDataVersionOID | SubjectKey | StudyEventOID | StudyEventRepeatKey | ItemGroupOID | ItemGroupRepeatKey | ItemOID | Value |
|---|---|---|---|---|---|---|---|---|
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | BASELINE |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 0 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-01-05 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | WEEK 8 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 8 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-03-02 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 1 | IT.TR.TRLNKID | L1 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 1 | IT.TR.LDIAM | 40 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 1 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 2 | IT.TR.TRLNKID | L2 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 2 | IT.TR.LDIAM | 25 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 2 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 3 | IT.TR.TRLNKID | L3 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 3 | IT.TR.LDIAM | 15 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TRTARGET | 3 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 1 | IT.TR.TRLNKID | L1 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 1 | IT.TR.LDIAM | 30 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 1 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 2 | IT.TR.TRLNKID | L2 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 2 | IT.TR.LDIAM | 20 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 2 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 3 | IT.TR.TRLNKID | L3 |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 3 | IT.TR.LDIAM | — |
| PILOT7 | MDV.1 | P7-921 | WEEK8 | 1 | IG.TRTARGET | 3 | IT.TR.TRSTAT | NOT DONE |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TUTARGET | 1 | IT.TU.TULNKID | L1 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TUTARGET | 2 | IT.TU.TULNKID | L2 |
| PILOT7 | MDV.1 | P7-921 | BASELINE | 1 | IG.TUTARGET | 3 | IT.TU.TULNKID | L3 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | BASELINE |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 0 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-01-12 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | WEEK 8 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 8 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-03-09 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TRTARGET | 1 | IT.TR.TRLNKID | L1 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TRTARGET | 1 | IT.TR.LDIAM | 22 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TRTARGET | 1 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TRTARGET | 2 | IT.TR.TRLNKID | L2 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TRTARGET | 2 | IT.TR.LDIAM | 18 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TRTARGET | 2 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.TRTARGET | 1 | IT.TR.TRLNKID | L1 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.TRTARGET | 1 | IT.TR.LDIAM | 12 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.TRTARGET | 1 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.TRTARGET | 2 | IT.TR.TRLNKID | L2 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.TRTARGET | 2 | IT.TR.LDIAM | 10 |
| PILOT7 | MDV.1 | P7-922 | WEEK8 | 1 | IG.TRTARGET | 2 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TUTARGET | 1 | IT.TU.TULNKID | L1 |
| PILOT7 | MDV.1 | P7-922 | BASELINE | 1 | IG.TUTARGET | 2 | IT.TU.TULNKID | L2 |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | BASELINE |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 0 |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-01-19 |
| PILOT7 | MDV.1 | P7-923 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | WEEK 8 |
| PILOT7 | MDV.1 | P7-923 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 8 |
| PILOT7 | MDV.1 | P7-923 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-03-16 |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.TRNT | 1 | IT.TR.TRLNKID | L1 |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.TRNT | 1 | IT.TR.LDIAM | 20 |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.TRNT | 1 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-923 | WEEK8 | 1 | IG.TRNT | 1 | IT.TR.TRLNKID | L1 |
| PILOT7 | MDV.1 | P7-923 | WEEK8 | 1 | IG.TRNT | 1 | IT.TR.LDIAM | 22 |
| PILOT7 | MDV.1 | P7-923 | WEEK8 | 1 | IG.TRNT | 1 | IT.TR.TRSTAT | — |
| PILOT7 | MDV.1 | P7-923 | BASELINE | 1 | IG.TUNT | 1 | IT.TU.TULNKID | L1 |
| PILOT7 | MDV.1 | P7-924 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | BASELINE |
| PILOT7 | MDV.1 | P7-924 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 0 |
| PILOT7 | MDV.1 | P7-924 | BASELINE | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-02-02 |
| PILOT7 | MDV.1 | P7-924 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISIT | WEEK 8 |
| PILOT7 | MDV.1 | P7-924 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.AVISITN | 8 |
| PILOT7 | MDV.1 | P7-924 | WEEK8 | 1 | IG.VISIT | 1 | IT.VISIT.ADT | 2025-03-30 |
Expected output
Under review8 expected rowsexpected/rs.csv
Edit8 rows| STUDYID | USUBJID | AVISIT | AVISITN | ADT | RSSEQ | RSTESTCD | RSTEST | RSSTRESC | RSSTAT |
|---|---|---|---|---|---|---|---|---|---|
| PILOT7 | BASELINE | 0 | 2025-01-05 | 1 | TRGRESP | Timepoint Response | NE | — | |
| PILOT7 | WEEK 8 | 8 | 2025-03-02 | 2 | TRGRESP | Timepoint Response | NE | — | |
| PILOT7 | BASELINE | 0 | 2025-01-12 | 1 | TRGRESP | Timepoint Response | NE | — | |
| PILOT7 | WEEK 8 | 8 | 2025-03-09 | 2 | TRGRESP | Timepoint Response | PR | — | |
| PILOT7 | BASELINE | 0 | 2025-01-19 | 1 | TRGRESP | Timepoint Response | NE | — | |
| PILOT7 | WEEK 8 | 8 | 2025-03-16 | 2 | TRGRESP | Timepoint Response | NE | — | |
| PILOT7 | BASELINE | 0 | 2025-02-02 | 1 | TRGRESP | Timepoint Response | — | NOT DONE | |
| PILOT7 | WEEK 8 | 8 | 2025-03-30 | 2 | TRGRESP | Timepoint Response | — | NOT DONE |
Comments and assessment materials
| Variable Name | Variable Label | Type | Length | Controlled Terms or Format | Origin | Core | Conversion Definition | Variable Type | Variable Order | Comments for Define |
|---|---|---|---|---|---|---|---|---|---|---|
| STUDYID | Study Identifier | Char | Collected | Copy value from ODM.StudyOID. | SDTM | 1 | ||||
| USUBJID | Unique Subject Identifier | Char | Collected | Copy value from ODM.SubjectKey. | SDTM | 2 | ||||
| AVISIT | Analysis Visit | Char | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 3 | ||||
| AVISITN | Analysis Visit (N) | Num | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 4 | ||||
| ADT | Analysis Date | Char | ISO 8601 | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 5 | |||
| RSSEQ | Sequence Number | Num | Derived | Row number within each group of STUDYID, USUBJID, ordered by AVISITN. | SDTM | 6 | ||||
| RSTESTCD | Response Test Short Name | Char | Assigned | Set constant value "TRGRESP". | SDTM | 7 | ||||
| RSTEST | Response Test Name | Char | Assigned | Set constant value "Timepoint Response". | SDTM | 8 | ||||
| RSSTAT | Completion Status | Char | Derived | If NTR IS NULL OR NTR = 0 then "NOT DONE"; otherwise blank. | SDTM | 9 | ||||
| RSSTRESC | Result or Finding in Standard Format | Char | CR, PR, SD, PD, NE | Derived | If RSSTAT = 'NOT DONE' then "None"; If AVISIT = 'BASELINE' then "NE"; If NTARGET IS NULL OR NTARGET = 0 then "NE"; If NMEAS IS NULL OR NMEAS < NTARGET then "NE"; If PCHG IS NULL then "NE"; If SUMV = 0 then "CR"; If PCHG <= -30 then "PR"; If PCHG >= 20 then "PD"; otherwise "SD". | SDTM | 10 |
| Template | Include when | AVISIT | AVISITN | ADT |
|---|---|---|---|---|
| visit | AVISITN IS NOT NULL | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.VISIT.AVISIT' | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.VISIT.AVISITN' | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.VISIT.ADT' |
| Variable | Permitted values |
|---|---|
| RSSTRESC | CR, PR, SD, PD, NE |
| 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/sdtm-rs-timepoint-response/full.md
Edit28 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create an RS dataset with one record per subject and scheduled tumor assessment.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, AVISIT, AVISITN, ADT, RSSEQ, RSTESTCD, RSTEST, RSSTRESC, RSSTAT
STUDYID is the ODM StudyOID and USUBJID is the SubjectKey, each as given.
AVISITN is the numeric order of the assessment, ADT its date, and RSSEQ numbers a subject's response records in visit order, starting at 1. RSTESTCD is TRGRESP and RSTEST is Timepoint Response on every record.
RSSTRESC is NE at baseline, when fewer target lesions were measured than were chosen, when the subject has non-target disease only, or when no percent change can be computed (for example a zero or missing baseline sum); CR when every target lesion has disappeared; PR when the target sum shrank at least 30% from baseline; PD when it grew at least 20% from baseline; and SD otherwise. It has no value when the assessment was not done. RSSTAT is NOT DONE for a scheduled assessment with no tumor measurement records at all, and has no value otherwise.
A baseline assessment is never compared against itself, so its response is NE whenever it was done. An assessment with some but not all chosen target lesions measured is still done, and its response is NE.
Read the source datasets from /app/input and save the completed dataset as /app/output/rs.csv.
prompts/sdtm-rs-timepoint-response/conventions.md
Edit14 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create an RS dataset with one record per subject and scheduled tumor assessment.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, AVISIT, AVISITN, ADT, RSSEQ, RSTESTCD, RSTEST, RSSTRESC, RSSTAT
RSTESTCD is TRGRESP and RSTEST is Timepoint Response on every record.
RSSTRESC is NE, CR, PR, PD, or SD, or has no value. RSSTAT is NOT DONE or has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/rs.csv.
prompts/sdtm-rs-timepoint-response/brief.md
Edit9 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create an RS dataset with one record per subject and scheduled tumor assessment.
The output dataset should contain the following columns in this order: STUDYID, USUBJID, AVISIT, AVISITN, ADT, RSSEQ, RSTESTCD, RSTEST, RSSTRESC, RSSTAT
Read the source datasets from /app/input and save the completed dataset as /app/output/rs.csv.
run.R
Edit4 lineslibrary(yamaa)rs <- yamaa_domain("spec.yaml")$outputrsrun.py
Edit4 linesimport yamaars = yamaa.yamaa_domain("spec.yaml").outputrssolutions/sdtm-rs-timepoint-response/result.R
Edit136 lines# Reference solution for the yamaa benchmark sdtm-rs-timepoint-response (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)library(tidyr)odm <- read_csv( "/app/input/odm.csv", col_types = cols(.default = col_character()))visits <- odm |> filter(ItemGroupOID == "IG.VISIT") |> pivot_wider( id_cols = c(StudyOID, SubjectKey, StudyEventOID), names_from = ItemOID, values_from = Value, values_fn = function(x) x[[1]] )tr_target <- odm |> filter(grepl("TARGET", ItemGroupOID, fixed = TRUE), startsWith(ItemGroupOID, "IG.TR")) |> pivot_wider( id_cols = c(StudyOID, SubjectKey, StudyEventOID, ItemGroupRepeatKey), names_from = ItemOID, values_from = Value, values_fn = function(x) x[[1]] )tr_any <- odm |> filter(startsWith(ItemGroupOID, "IG.TR")) |> count(SubjectKey, StudyEventOID, name = "n_tr")tu_target <- odm |> filter(grepl("TARGET", ItemGroupOID, fixed = TRUE), startsWith(ItemGroupOID, "IG.TU"), StudyEventOID == "BASELINE", ItemOID == "IT.TU.TULNKID", !is.na(Value) & Value != "") |> distinct(SubjectKey, Value)response_one <- function(subj, event, avisitn, base_sum, n_chosen, post_diams, has_records) { if (!has_records) { return(list(rsstresc = NA_character_, rsstat = "NOT DONE")) } if (event == "BASELINE") { return(list(rsstresc = "NE", rsstat = NA_character_)) } if (n_chosen == 0) { return(list(rsstresc = "NE", rsstat = NA_character_)) } measured <- post_diams[!is.na(post_diams) & post_diams != ""] if (length(measured) < n_chosen) { return(list(rsstresc = "NE", rsstat = NA_character_)) } if (is.na(base_sum) || base_sum == 0) { return(list(rsstresc = "NE", rsstat = NA_character_)) } post <- sum(suppressWarnings(as.numeric(measured))) if (all(suppressWarnings(as.numeric(measured)) == 0)) { return(list(rsstresc = "CR", rsstat = NA_character_)) } if ((base_sum - post) / base_sum >= 0.30) { return(list(rsstresc = "PR", rsstat = NA_character_)) } if ((post - base_sum) / base_sum >= 0.20) { return(list(rsstresc = "PD", rsstat = NA_character_)) } list(rsstresc = "SD", rsstat = NA_character_)}subjects <- unique(visits$SubjectKey)out <- list()for (subj in subjects) { chosen <- nrow(tu_target |> filter(SubjectKey == subj)) if (chosen == 0) { chosen <- nrow(tr_target |> filter(SubjectKey == subj, StudyEventOID == "BASELINE")) } base_rows <- tr_target |> filter(SubjectKey == subj, StudyEventOID == "BASELINE") base_diams <- base_rows$IT.TR.LDIAM base_sum <- if (chosen == 0) { NA_real_ } else if (any(is.na(base_diams) | base_diams == "")) { NA_real_ } else { sum(suppressWarnings(as.numeric(base_diams))) } subj_visits <- visits |> filter(SubjectKey == subj) |> arrange(suppressWarnings(as.integer(IT.VISIT.AVISITN))) seq <- 0L for (i in seq_len(nrow(subj_visits))) { seq <- seq + 1L event <- subj_visits$StudyEventOID[[i]] n_rec <- tr_any |> filter(SubjectKey == subj, StudyEventOID == event) |> pull(n_tr) has_records <- length(n_rec) > 0 && n_rec[[1]] > 0 post_diams <- tr_target |> filter(SubjectKey == subj, StudyEventOID == event) |> pull(IT.TR.LDIAM) resp <- response_one( subj, event, subj_visits$IT.VISIT.AVISITN[[i]], base_sum, chosen, post_diams, has_records ) out[[length(out) + 1]] <- tibble( STUDYID = subj_visits$StudyOID[[i]], USUBJID = subj, AVISIT = subj_visits$IT.VISIT.AVISIT[[i]], AVISITN = subj_visits$IT.VISIT.AVISITN[[i]], ADT = subj_visits$IT.VISIT.ADT[[i]], RSSEQ = seq, RSTESTCD = "TRGRESP", RSTEST = "Timepoint Response", RSSTRESC = resp$rsstresc, RSSTAT = resp$rsstat ) }}rs <- bind_rows(out) |> arrange(USUBJID, suppressWarnings(as.integer(AVISITN))) |> select( STUDYID, USUBJID, AVISIT, AVISITN, ADT, RSSEQ, RSTESTCD, RSTEST, RSSTRESC, RSSTAT )dir.create("/app/output", showWarnings = FALSE)write_csv(rs, "/app/output/rs.csv", na = "")solutions/sdtm-rs-timepoint-response/result.py
Edit182 lines# Reference solution for the yamaa benchmark sdtm-rs-timepoint-response (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 pldef _present(value) -> bool: return value is not None and str(value).strip() != ""odm = pl.read_csv("/app/input/odm.csv", infer_schema=False)visits: dict[tuple, dict] = {}tr_target: dict[tuple, list] = {}tr_any: dict[tuple, int] = {}tu_target_ids: dict[str, set] = {}baseline_target_diams: dict[str, list] = {}for row in odm.to_dicts(): subj, event = str(row["SubjectKey"]), str(row["StudyEventOID"]) group, oid = str(row["ItemGroupOID"]), str(row["ItemOID"]) value = row["Value"] key = (subj, event) if group == "IG.VISIT": visits.setdefault( key, {"studyid": str(row["StudyOID"]), "usubjid": subj} )[oid] = str(value) if _present(value) else None elif "TARGET" in group and group.startswith("IG.TR"): # Target tumor measurements at this visit. rep = str(row["ItemGroupRepeatKey"]) tr_target.setdefault((subj, event, rep), {})[oid] = ( str(value) if _present(value) else None ) tr_any[key] = tr_any.get(key, 0) + 0 elif group.startswith("IG.TR"): # Non-target measurements still count as done. tr_any[key] = tr_any.get(key, 0) + 1 elif ( "TARGET" in group and group.startswith("IG.TU") and event == "BASELINE" and oid == "IT.TU.TULNKID" and _present(value) ): tu_target_ids.setdefault(subj, set()).add(str(value).strip())# Any TR row (target or not) means the assessment has measurement records.for (subj, event, _rep) in list(tr_target.keys()): tr_any[(subj, event)] = tr_any.get((subj, event), 0) + 1# Chosen target lesions from the baseline tumor identification, else the# baseline target measurements; none means non-target disease only.chosen: dict[str, int] = {}for subj in {s for s, _e in visits}: if subj in tu_target_ids: chosen[subj] = len(tu_target_ids[subj]) else: baseline_reps = {rep for (s, e, rep) in tr_target if s == subj and e == "BASELINE"} chosen[subj] = len(baseline_reps)baseline_sum: dict[str, float | None] = {}for subj in {s for s, _e in visits}: diams = [] missing = False for (s, e, _rep), vals in tr_target.items(): if s != subj or e != "BASELINE": continue diam = vals.get("IT.TR.LDIAM") if not _present(diam): missing = True else: try: diams.append(float(str(diam))) except ValueError: missing = True if missing or not diams: # No percent change can be computed from a missing baseline sum. # An empty baseline (non-target only) is handled as NE elsewhere. baseline_sum[subj] = None if (missing or not diams) and chosen.get(subj, 0) else 0.0 if chosen.get(subj, 0) == 0: baseline_sum[subj] = None elif not missing and diams: baseline_sum[subj] = sum(diams) else: baseline_sum[subj] = sum(diams)rows = []by_subject: dict[str, list] = {}for (subj, event), visit in visits.items(): by_subject.setdefault(subj, []).append((event, visit))for subj, items in by_subject.items(): items.sort(key=lambda kv: int(kv[1].get("IT.VISIT.AVISITN") or 0)) for seq, (event, visit) in enumerate(items, start=1): avisit = visit.get("IT.VISIT.AVISIT") avisitn = visit.get("IT.VISIT.AVISITN") adt = visit.get("IT.VISIT.ADT") has_records = tr_any.get((subj, event), 0) > 0 if not has_records: # A scheduled assessment with no tumor measurement records. rsstresc, rsstat = None, "NOT DONE" elif event == "BASELINE": # A baseline assessment is never compared against itself. rsstresc, rsstat = "NE", None elif chosen.get(subj, 0) == 0: rsstresc, rsstat = "NE", None else: post_vals = [ vals.get("IT.TR.LDIAM") for (s, e, _r), vals in tr_target.items() if s == subj and e == event ] measured = [v for v in post_vals if _present(v)] if len(measured) < chosen[subj]: rsstresc, rsstat = "NE", None else: base = baseline_sum.get(subj) if base is None or base == 0: rsstresc, rsstat = "NE", None else: try: post = sum(float(str(v)) for v in measured) except ValueError: rsstresc, rsstat = "NE", None else: if all(float(str(v)) == 0 for v in measured): rsstresc = "CR" elif (base - post) / base >= 0.30: rsstresc = "PR" elif (post - base) / base >= 0.20: rsstresc = "PD" else: rsstresc = "SD" rsstat = None rows.append( { "STUDYID": visit["studyid"], "USUBJID": visit["usubjid"], "AVISIT": avisit, "AVISITN": avisitn, "ADT": adt, "RSSEQ": str(seq), "RSTESTCD": "TRGRESP", "RSTEST": "Timepoint Response", "RSSTRESC": rsstresc, "RSSTAT": rsstat, } )rs = ( pl.DataFrame( rows, schema={ "STUDYID": pl.String, "USUBJID": pl.String, "AVISIT": pl.String, "AVISITN": pl.String, "ADT": pl.String, "RSSEQ": pl.String, "RSTESTCD": pl.String, "RSTEST": pl.String, "RSSTRESC": pl.String, "RSSTAT": pl.String, }, ) .with_columns( pl.col("RSSEQ").cast(pl.Int64).alias("_seq"), pl.col("AVISITN").cast(pl.Int64).alias("_visit"), ) .sort(["USUBJID", "_visit"]) .select( "STUDYID", "USUBJID", "AVISIT", "AVISITN", "ADT", "RSSEQ", "RSTESTCD", "RSTEST", "RSSTRESC", "RSSTAT", ))Path("/app/output").mkdir(exist_ok=True)rs.write_csv("/app/output/rs.csv")solutions/sdtm-rs-timepoint-response/result.sas
Edit59 lines/* opensas reference solution for the yamaa benchmark sdtm-rs-timepoint-response. Reads the benchmark inputs and derives the requested output. Execute with the existing opensas runtime: opensas /app/output/result.sas. */data odm; length StudyOID MetaDataVersionOID SubjectKey StudyEventOID StudyEventRepeatKey ItemGroupOID ItemGroupRepeatKey ItemOID Value $1024; infile "/app/input/odm.csv" dsd dlm="," firstobs=2 truncover lrecl=32767; input StudyOID : $char1024. MetaDataVersionOID : $char1024. SubjectKey : $char1024. StudyEventOID : $char1024. StudyEventRepeatKey : $char1024. ItemGroupOID : $char1024. ItemGroupRepeatKey : $char1024. ItemOID : $char1024. Value : $char1024.;run;proc sort data=odm out=ordered; by StudyOID SubjectKey StudyEventOID; run;data visits; length AVISIT VISITORDER ADT $1024; retain AVISIT VISITORDER ADT; set ordered; where ItemGroupOID='IG.VISIT'; by StudyOID SubjectKey StudyEventOID; if first.StudyEventOID then do; AVISIT=''; VISITORDER=''; ADT=''; end; if ItemOID='IT.VISIT.AVISIT' then AVISIT=Value; if ItemOID='IT.VISIT.AVISITN' then VISITORDER=Value; if ItemOID='IT.VISIT.ADT' then ADT=Value; if last.StudyEventOID then output;run;proc sort data=odm out=ordered; by StudyOID SubjectKey StudyEventOID ItemGroupRepeatKey; run;data targetforms; length DIAM $1024; retain DIAM; set ordered; where ItemGroupOID='IG.TRTARGET'; by StudyOID SubjectKey StudyEventOID ItemGroupRepeatKey; if first.ItemGroupRepeatKey then do; DIAM=''; end; if ItemOID='IT.TR.LDIAM' then DIAM=Value; if last.ItemGroupRepeatKey then output;run;data targets; set targetforms; DIAMETER=input(DIAM,?? best32.); run;proc sql;create table chosen as select StudyOID,SubjectKey,count(distinct Value) as NCHOSEN from odm where ItemGroupOID='IG.TUTARGET' and StudyEventOID='BASELINE' and ItemOID='IT.TU.TULNKID' and not missing(Value) group by StudyOID,SubjectKey;create table baseline as select StudyOID,SubjectKey,count(*) as NBASE,count(DIAMETER) as NBASEDONE,sum(DIAMETER) as BASE from targets where StudyEventOID='BASELINE' group by StudyOID,SubjectKey;create table measures as select StudyOID,SubjectKey,StudyEventOID,count(DIAMETER) as NMEAS,sum(DIAMETER) as TOTAL,max(DIAMETER) as MAXDIAM from targets group by StudyOID,SubjectKey,StudyEventOID;create table done as select distinct StudyOID,SubjectKey,StudyEventOID from odm where ItemGroupOID in ('IG.TRTARGET','IG.TRNT');create table joined as select a.*,b.NCHOSEN,c.NBASE,c.NBASEDONE,c.BASE,d.NMEAS,d.TOTAL,d.MAXDIAM,e.StudyEventOID as DONEEVENT from visits a left join chosen b on a.StudyOID=b.StudyOID and a.SubjectKey=b.SubjectKey left join baseline c on a.StudyOID=c.StudyOID and a.SubjectKey=c.SubjectKey left join measures d on a.StudyOID=d.StudyOID and a.SubjectKey=d.SubjectKey and a.StudyEventOID=d.StudyEventOID left join done e on a.StudyOID=e.StudyOID and a.SubjectKey=e.SubjectKey and a.StudyEventOID=e.StudyEventOID; quit;data prepared; set joined; length STUDYID USUBJID RSTESTCD RSTEST RSSTRESC RSSTAT $1024; STUDYID=StudyOID; USUBJID=SubjectKey; AVISITN=input(VISITORDER,best32.); RSTESTCD='TRGRESP'; RSTEST='Timepoint Response'; RSSTRESC='NE'; RSSTAT=''; NSELECTED=coalesce(NCHOSEN,NBASE,0);if missing(DONEEVENT) then do; RSSTRESC=''; RSSTAT='NOT DONE'; end;else if StudyEventOID ne 'BASELINE' and NSELECTED>0 and NMEAS>=NSELECTED and NBASEDONE=NBASE and not missing(BASE) and BASE ne 0 then do;if MAXDIAM=0 then RSSTRESC='CR'; else if (BASE-TOTAL)/BASE>=0.30 then RSSTRESC='PR'; else if (TOTAL-BASE)/BASE>=0.20 then RSSTRESC='PD'; else RSSTRESC='SD'; end; run;proc sort data=prepared; by STUDYID USUBJID AVISITN; run;data result; set prepared; by STUDYID USUBJID; retain RSSEQ; if first.USUBJID then RSSEQ=0; RSSEQ+1;run;proc sql; create table final as select STUDYID, USUBJID, AVISIT, AVISITN, ADT, RSSEQ, RSTESTCD, RSTEST, RSSTRESC, RSSTAT from result;quit;proc export data=final outfile="/app/output/rs.csv" dbms=csv replace; run;
yamaa
Comments
Signed in with GitHub; saved in repository Discussions