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: carry LBORRES into a standardized LBSTRESC, populate
LBSTRESN for true numerics only, and state LBNRIND for results
at the quantification limits.
Input: long-form Operational Data Model (ODM) data with one row per
recorded item. Each laboratory result is one form occurrence carrying the
reported result (IT.LB.RESULT), the collection date (IT.LB.LBDTC), and
the reported unit (IT.LB.LBORRESU); the collection form names the test. A
repeated form occurrence keeps a second result for the same test and visit
separate.
Variables:
LBSEQnumbers the records in the documented collection order within each subject (protein, creatine kinase, glucose, ketones, creatinine), then by form repeat.LBTESTCDis the test short name for the collection form:PROT(protein),GLUC(glucose),KETON(ketones),CREAT(creatinine), orCK(creatine kinase).LBTESTis the test name for the collection form.LBORRESis the result as collected: a dipstick grade such asNeg,tr, or1 plus, or a censored value such as<0.1.LBORRESUis the unit as reported on the collection form; empty when the form records no unit.LBSTRESCis the standardized character result: known dipstick spellings, in any letter case, fold toNEGATIVE,TRACE,1+, or2+; anything else is kept as collected.LBSTRESNis the standardized numeric result. It holds a number only for a true numeric such as0.9; it stays empty for grades and for censored values.LBSTRESUis the standard unit, carried from the reported unit.LBNRINDis the reference range indicator:LOWfor a result below the quantification limit,HIGHfor one above it, empty otherwise.LBDTCis the specimen collection date from the same form occurrence.
Note: a grade spelling outside the known spellings is kept as collected rather than dropped, so a new spelling shows up in the output instead of silently disappearing. No demographics input is needed: the subject identifier comes from the ODM subject key.
Inputs
Under review1 source fileinput/odm.csv
Edit51 rows| StudyOID | MetaDataVersionOID | SubjectKey | StudyEventOID | StudyEventRepeatKey | FormOID | FormRepeatKey | ItemGroupOID | ItemGroupRepeatKey | ItemOID | Value |
|---|---|---|---|---|---|---|---|---|---|---|
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.RESULT | NEGATIVE |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-01 |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.RESULT | Neg |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-01 |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.RESULT | TRACE |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-01 |
| STUDY01 | MDV.1 | STUDY01-101 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.RESULT | neg |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-03 |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.RESULT | tr |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-03 |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.RESULT | Trace |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-03 |
| STUDY01 | MDV.1 | STUDY01-102 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.RESULT | 1+ |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-05 |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.RESULT | +1 |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-05 |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.RESULT | 1 plus |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-05 |
| STUDY01 | MDV.1 | STUDY01-103 | V1 | 1 | FO.LB_KETON | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.RESULT | 2+ |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-07 |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_CREAT | 1 | IG.LB | 1 | IT.LB.RESULT | <0.1 |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_CREAT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-07 |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_CREAT | 1 | IG.LB | 1 | IT.LB.LBORRESU | mg/dL |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_CREAT | 2 | IG.LB | 1 | IT.LB.RESULT | 0.9 |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_CREAT | 2 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-07 |
| STUDY01 | MDV.1 | STUDY01-104 | V1 | 1 | FO.LB_CREAT | 2 | IG.LB | 1 | IT.LB.LBORRESU | mg/dL |
| STUDY01 | MDV.1 | STUDY01-105 | V1 | 1 | FO.LB_CK | 1 | IG.LB | 1 | IT.LB.RESULT | >500 |
| STUDY01 | MDV.1 | STUDY01-105 | V1 | 1 | FO.LB_CK | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-09 |
| STUDY01 | MDV.1 | STUDY01-105 | V1 | 1 | FO.LB_CK | 1 | IG.LB | 1 | IT.LB.LBORRESU | U/L |
| STUDY01 | MDV.1 | STUDY01-105 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.RESULT | +2 |
| STUDY01 | MDV.1 | STUDY01-105 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-09 |
| STUDY01 | MDV.1 | STUDY01-105 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-106 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.RESULT | nEg |
| STUDY01 | MDV.1 | STUDY01-106 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-11 |
| STUDY01 | MDV.1 | STUDY01-106 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-106 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.RESULT | 1 Plus |
| STUDY01 | MDV.1 | STUDY01-106 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-11 |
| STUDY01 | MDV.1 | STUDY01-106 | V1 | 1 | FO.LB_GLUC | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
| STUDY01 | MDV.1 | STUDY01-107 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.RESULT | POSITIVE |
| STUDY01 | MDV.1 | STUDY01-107 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBDTC | 2026-08-12 |
| STUDY01 | MDV.1 | STUDY01-107 | V1 | 1 | FO.LB_PROT | 1 | IG.LB | 1 | IT.LB.LBORRESU | — |
Expected output
Under review17 expected rowsexpected/lb.csv
Edit17 rows| DOMAIN | STUDYID | USUBJID | LBSEQ | LBTESTCD | LBTEST | LBORRES | LBORRESU | LBSTRESC | LBSTRESN | LBSTRESU | LBNRIND | LBDTC |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LB | STUDY01 | 1 | PROT | Protein | NEGATIVE | — | NEGATIVE | — | — | — | 2026-08-01 | |
| LB | STUDY01 | 2 | GLUC | Glucose | Neg | — | NEGATIVE | — | — | — | 2026-08-01 | |
| LB | STUDY01 | 3 | KETON | Ketones | TRACE | — | TRACE | — | — | — | 2026-08-01 | |
| LB | STUDY01 | 1 | PROT | Protein | neg | — | NEGATIVE | — | — | — | 2026-08-03 | |
| LB | STUDY01 | 2 | GLUC | Glucose | tr | — | TRACE | — | — | — | 2026-08-03 | |
| LB | STUDY01 | 3 | KETON | Ketones | Trace | — | TRACE | — | — | — | 2026-08-03 | |
| LB | STUDY01 | 1 | PROT | Protein | 1+ | — | 1+ | — | — | — | 2026-08-05 | |
| LB | STUDY01 | 2 | GLUC | Glucose | +1 | — | 1+ | — | — | — | 2026-08-05 | |
| LB | STUDY01 | 3 | KETON | Ketones | 1 plus | — | 1+ | — | — | — | 2026-08-05 | |
| LB | STUDY01 | 1 | PROT | Protein | 2+ | — | 2+ | — | — | — | 2026-08-07 | |
| LB | STUDY01 | 2 | CREAT | Creatinine | <0.1 | mg/dL | <0.1 | — | mg/dL | LOW | 2026-08-07 | |
| LB | STUDY01 | 3 | CREAT | Creatinine | 0.9 | mg/dL | 0.9 | 0.9 | mg/dL | — | 2026-08-07 | |
| LB | STUDY01 | 1 | CK | Creatine Kinase | >500 | U/L | >500 | — | U/L | HIGH | 2026-08-09 | |
| LB | STUDY01 | 2 | GLUC | Glucose | +2 | — | 2+ | — | — | — | 2026-08-09 | |
| LB | STUDY01 | 1 | PROT | Protein | nEg | — | NEGATIVE | — | — | — | 2026-08-11 | |
| LB | STUDY01 | 2 | GLUC | Glucose | 1 Plus | — | 1+ | — | — | — | 2026-08-11 | |
| LB | STUDY01 | 1 | PROT | Protein | POSITIVE | — | POSITIVE | — | — | — | 2026-08-12 |
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 |
|---|---|---|---|---|---|---|---|---|---|---|
| DOMAIN | Domain Abbreviation | Char | Assigned | Set constant value "LB". | SDTM | 1 | ||||
| STUDYID | Study Identifier | Char | Collected | Copy value from ODM.StudyOID. | SDTM | 2 | ||||
| USUBJID | Unique Subject Identifier | Char | Collected | Copy value from ODM.SubjectKey. | SDTM | 3 | ||||
| LBSEQ | Sequence Number | Num | Derived | Row number within each group of STUDYID, USUBJID, ordered by FORMORD then FORMRPT. | SDTM | 4 | ||||
| LBTESTCD | Lab Test or Examination Short Name | Char | Collected | Recode ODM.FormOID: "FO.LB_PROT" → "PROT", "FO.LB_GLUC" → "GLUC", "FO.LB_KETON" → "KETON", "FO.LB_CREAT" → "CREAT", "FO.LB_CK" → "CK"; missing or unlisted values are errors. | SDTM | 5 | ||||
| LBTEST | Lab Test or Examination Name | Char | Collected | Recode ODM.FormOID: "FO.LB_PROT" → "Protein", "FO.LB_GLUC" → "Glucose", "FO.LB_KETON" → "Ketones", "FO.LB_CREAT" → "Creatinine", "FO.LB_CK" → "Creatine Kinase"; missing or unlisted values are errors. | SDTM | 6 | ||||
| LBORRES | Result or Finding in Original Units | Char | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 7 | ||||
| LBORRESU | Original Units | Char | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 8 | ||||
| LBSTRESC | Character Result/Finding in Standard Units | Char | Derived | If LBORRES_U IN ('NEGATIVE','NEG','TRACE','TR','1+','+1','1 PLUS','2+','+2') then recode LBORRES: "NEGATIVE" → "NEGATIVE", "NEG" → "NEGATIVE", "TRACE" → "TRACE", "TR" → "TRACE", "1+" → "1+", "+1" → "1+", "1 PLUS" → "1+", "2+" → "2+", "+2" → "2+"; missing values stay missing; unlisted values are errors; matching ignores letter case; otherwise "LBORRES". | SDTM | 9 | ||||
| LBSTRESN | Numeric Result/Finding in Standard Units | Num | Derived | Copy value from LBSTRESC; a value that cannot be converted → blank. | SDTM | 10 | ||||
| LBSTRESU | Standard Units | Char | Derived | Copy value from LBORRESU. | SDTM | 11 | ||||
| LBNRIND | Reference Range Indicator | Char | Derived | If LBSTRESC LIKE '<%' then "LOW"; If LBSTRESC LIKE '>%' then "HIGH"; otherwise blank. | SDTM | 12 | ||||
| LBDTC | Date/Time of Specimen Collection | Char | ISO 8601 | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 13 |
| Template | Include when | LBORRES | LBORRESU | LBDTC |
|---|---|---|---|---|
| lab-result | LBORRES IS NOT NULL | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.LB.RESULT' | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.LB.LBORRESU' | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.LB.LBDTC' |
| 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-lb-character-results/full.md
Edit30 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create an LB dataset with one record per collected laboratory result.
The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, LBSEQ, LBTESTCD, LBTEST, LBORRES, LBORRESU, LBSTRESC, LBSTRESN, LBSTRESU, LBNRIND, LBDTC
STUDYID is the ODM StudyOID and USUBJID is the SubjectKey, each as given.
LBSEQ numbers each subject's records in collection order (protein, creatine kinase, glucose, ketones, creatinine), then by form repeat. The test code and name come from the collection form: PROT and Protein, GLUC and Glucose, KETON and Ketones, CREAT and Creatinine, or CK and Creatine Kinase.
LBORRES is the result as collected. LBORRESU is the reported unit, and has no value when the form records no unit. LBSTRESC folds known dipstick spellings, in any letter case, to NEGATIVE, TRACE, 1+, or 2+; anything else is kept as collected. LBSTRESN holds a number only for a true numeric result, and has no value for grades and censored values. LBSTRESU repeats the reported unit. LBNRIND is LOW for a result below the quantification limit and HIGH for one above it, and has no value otherwise. LBDTC is the collection date from the same form occurrence.
A form with no reported result produces no record; a repeated form occurrence keeps a second result for the same test and visit separate. A grade spelling outside the known spellings is kept as collected.
Read the source datasets from /app/input and save the completed dataset as /app/output/lb.csv.
prompts/sdtm-lb-character-results/conventions.md
Edit15 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create an LB dataset with one record per collected laboratory result.
The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, LBSEQ, LBTESTCD, LBTEST, LBORRES, LBORRESU, LBSTRESC, LBSTRESN, LBSTRESU, LBNRIND, LBDTC
The test code and name are PROT and Protein, GLUC and Glucose, KETON and Ketones, CREAT and Creatinine, or CK and Creatine Kinase.
LBSTRESC folds known dipstick spellings to NEGATIVE, TRACE, 1+, or 2+. LBNRIND is LOW, HIGH, or has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/lb.csv.
prompts/sdtm-lb-character-results/brief.md
Edit9 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create an LB dataset with one record per collected laboratory result.
The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, LBSEQ, LBTESTCD, LBTEST, LBORRES, LBORRESU, LBSTRESC, LBSTRESN, LBSTRESU, LBNRIND, LBDTC
Read the source datasets from /app/input and save the completed dataset as /app/output/lb.csv.
run.R
Edit4 lineslibrary(yamaa)lb <- yamaa_domain("spec.yaml")$outputlbrun.py
Edit4 linesimport yamaalb = yamaa.yamaa_domain("spec.yaml").outputlbsolutions/sdtm-lb-character-results/result.R
Edit106 lines# Reference solution for the yamaa benchmark sdtm-lb-character-results (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(purrr)library(stringr)odm <- read_csv( "/app/input/odm.csv", col_types = cols(.default = col_character())) |> mutate(Value = na_if(Value, ""))form_order <- c( "FO.LB_PROT" = 0L, "FO.LB_CK" = 1L, "FO.LB_GLUC" = 2L, "FO.LB_KETON" = 3L, "FO.LB_CREAT" = 4L)form_test <- c( "FO.LB_PROT" = "PROT", "FO.LB_CK" = "CK", "FO.LB_GLUC" = "GLUC", "FO.LB_KETON" = "KETON", "FO.LB_CREAT" = "CREAT")test_name <- c( PROT = "Protein", CK = "Creatine Kinase", GLUC = "Glucose", KETON = "Ketones", CREAT = "Creatinine")standardize <- function(raw) { if (is.na(raw)) return(NA_character_) low <- str_to_lower(str_replace_all(str_trim(raw), " ", "")) if (low %in% c("negative", "neg")) return("NEGATIVE") if (low %in% c("trace", "tr")) return("TRACE") if (low %in% c("1+", "+1", "1plus")) return("1+") if (low %in% c("2+", "+2", "2plus")) return("2+") raw}forms <- odm |> distinct(StudyOID, SubjectKey, FormOID, FormRepeatKey) |> filter(FormOID %in% names(form_order))one_form <- function(study, subj, formoid, formrep) { sub <- odm |> filter( SubjectKey == subj, FormOID == formoid, FormRepeatKey == formrep ) get <- function(oid) { hit <- sub |> filter(ItemOID == oid) if (nrow(hit) == 0) return(NA_character_) hit$Value[[1]] } raw <- get("IT.LB.RESULT") if (is.na(raw)) return(tibble()) code <- form_test[[formoid]] stresc <- standardize(raw) stresn <- suppressWarnings(as.numeric(raw)) if (!is.na(stresc) && stresc %in% c("NEGATIVE", "TRACE", "1+", "2+")) { stresn <- NA_real_ } if (str_starts(str_trim(raw), "<") || str_starts(str_trim(raw), ">")) { stresn <- NA_real_ } nrind <- if (str_starts(str_trim(raw), "<")) { "LOW" } else if (str_starts(str_trim(raw), ">")) { "HIGH" } else { NA_character_ } unit <- get("IT.LB.LBORRESU") tibble( DOMAIN = "LB", STUDYID = study, USUBJID = subj, ORDER = form_order[[formoid]], REP = as.integer(formrep), LBTESTCD = code, LBTEST = test_name[[code]], LBORRES = raw, LBORRESU = unit, LBSTRESC = stresc, LBSTRESN = stresn, LBSTRESU = unit, LBNRIND = nrind, LBDTC = get("IT.LB.LBDTC") )}lb <- pmap_dfr( list(forms$StudyOID, forms$SubjectKey, forms$FormOID, forms$FormRepeatKey), one_form) |> arrange(STUDYID, USUBJID, ORDER, REP) |> group_by(STUDYID, USUBJID) |> mutate(LBSEQ = row_number()) |> ungroup() |> select( DOMAIN, STUDYID, USUBJID, LBSEQ, LBTESTCD, LBTEST, LBORRES, LBORRESU, LBSTRESC, LBSTRESN, LBSTRESU, LBNRIND, LBDTC )dir.create("/app/output", showWarnings = FALSE)write_csv(lb, "/app/output/lb.csv", na = "")solutions/sdtm-lb-character-results/result.py
Edit138 lines# Reference solution for the yamaa benchmark sdtm-lb-character-results (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 plodm = pl.read_csv("/app/input/odm.csv", infer_schema=False)forms = {}study_of = {}for r in odm.to_dicts(): study_of[r["SubjectKey"]] = r["StudyOID"] key = (r["SubjectKey"], r["FormOID"], r["FormRepeatKey"]) forms.setdefault(key, {})[r["ItemOID"]] = r["Value"]form_info = { "FO.LB_PROT": ("PROT", "Protein", 0), "FO.LB_CK": ("CK", "Creatine Kinase", 1), "FO.LB_GLUC": ("GLUC", "Glucose", 2), "FO.LB_KETON": ("KETON", "Ketones", 3), "FO.LB_CREAT": ("CREAT", "Creatinine", 4),}def standardize(raw): if raw is None: return None t = raw.strip() low = t.lower().replace(" ", "") if low in ("negative", "neg"): return "NEGATIVE" if low in ("trace", "tr"): return "TRACE" if low in ("1+", "+1", "1plus"): return "1+" if low in ("2+", "+2", "2plus"): return "2+" return rawdef as_number(text): if text is None or text == "": return None try: return float(text) except ValueError: return Nonerows = []for (subj, formoid, formrep), items in forms.items(): if formoid not in form_info: continue code, name, order = form_info[formoid] raw = items.get("IT.LB.RESULT") if raw is None or raw == "": continue lbdtc = items.get("IT.LB.LBDTC") unit = items.get("IT.LB.LBORRESU") unit = unit if unit not in (None, "") else None stresc = standardize(raw) # A true numeric result only: grades and censored values have no number. stresn = as_number(raw) if stresc in ("NEGATIVE", "TRACE", "1+", "2+"): stresn = None if raw.strip().startswith("<") or raw.strip().startswith(">"): stresn = None nrind = None if raw.strip().startswith("<"): nrind = "LOW" elif raw.strip().startswith(">"): nrind = "HIGH" rows.append( { "DOMAIN": "LB", "STUDYID": study_of[subj], "USUBJID": subj, "ORDER": order, "REP": int(formrep), "LBTESTCD": code, "LBTEST": name, "LBORRES": raw, "LBORRESU": unit, "LBSTRESC": stresc, "LBSTRESN": stresn, "LBSTRESU": unit, "LBNRIND": nrind, "LBDTC": lbdtc, } )lb = ( pl.DataFrame( rows, schema={ "DOMAIN": pl.String, "STUDYID": pl.String, "USUBJID": pl.String, "ORDER": pl.Int64, "REP": pl.Int64, "LBTESTCD": pl.String, "LBTEST": pl.String, "LBORRES": pl.String, "LBORRESU": pl.String, "LBSTRESC": pl.String, "LBSTRESN": pl.Float64, "LBSTRESU": pl.String, "LBNRIND": pl.String, "LBDTC": pl.String, }, ) .sort(["STUDYID", "USUBJID", "ORDER", "REP"]) .with_columns( pl.int_range(1, pl.len() + 1).over(["STUDYID", "USUBJID"]).alias("LBSEQ") ) .select( "DOMAIN", "STUDYID", "USUBJID", "LBSEQ", "LBTESTCD", "LBTEST", "LBORRES", "LBORRESU", "LBSTRESC", "LBSTRESN", "LBSTRESU", "LBNRIND", "LBDTC", ))Path("/app/output").mkdir(parents=True, exist_ok=True)lb.write_csv("/app/output/lb.csv")solutions/sdtm-lb-character-results/result.sas
Edit46 lines/* opensas reference solution for the yamaa benchmark sdtm-lb-character-results. 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 FormOID FormRepeatKey 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. FormOID : $char1024. FormRepeatKey : $char1024. ItemGroupOID : $char1024. ItemGroupRepeatKey : $char1024. ItemOID : $char1024. Value : $char1024.;run;proc sort data=odm out=ordered; by StudyOID SubjectKey FormOID FormRepeatKey; run;data wide; length LBORRES LBORRESU LBDTC $1024; retain LBORRES LBORRESU LBDTC; set ordered; by StudyOID SubjectKey FormOID FormRepeatKey; if first.FormRepeatKey then do; LBORRES=''; LBORRESU=''; LBDTC=''; end; if ItemOID='IT.LB.RESULT' then LBORRES=Value; if ItemOID='IT.LB.LBORRESU' then LBORRESU=Value; if ItemOID='IT.LB.LBDTC' then LBDTC=Value; if last.FormRepeatKey then output;run;data prepared; set wide; if not missing(LBORRES); length DOMAIN $2 STUDYID USUBJID LBTESTCD LBTEST LBSTRESC LBSTRESU LBNRIND TOKEN $1024;DOMAIN='LB'; STUDYID=StudyOID; USUBJID=SubjectKey; LBSTRESU=LBORRESU; LBSTRESC=LBORRES; LBNRIND=''; LBSTRESN=.; TOKEN=lowcase(compress(LBORRES,' '));if TOKEN in ('negative','neg') then LBSTRESC='NEGATIVE'; if TOKEN in ('trace','tr') then LBSTRESC='TRACE'; if TOKEN in ('1+','+1','1plus') then LBSTRESC='1+'; if TOKEN in ('2+','+2','2plus') then LBSTRESC='2+';if prxmatch('/^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/',strip(LBORRES)) and not (LBSTRESC in ('NEGATIVE','TRACE','1+','2+')) then LBSTRESN=input(LBORRES,best32.);if substr(strip(LBORRES),1,1)='<' then LBNRIND='LOW'; if substr(strip(LBORRES),1,1)='>' then LBNRIND='HIGH';if FormOID='FO.LB_PROT' then do; LBTESTCD='PROT'; LBTEST='Protein'; TESTORD=1; end;else if FormOID='FO.LB_CK' then do; LBTESTCD='CK'; LBTEST='Creatine Kinase'; TESTORD=2; end;else if FormOID='FO.LB_GLUC' then do; LBTESTCD='GLUC'; LBTEST='Glucose'; TESTORD=3; end;else if FormOID='FO.LB_KETON' then do; LBTESTCD='KETON'; LBTEST='Ketones'; TESTORD=4; end;else if FormOID='FO.LB_CREAT' then do; LBTESTCD='CREAT'; LBTEST='Creatinine'; TESTORD=5; end; else delete;REP=input(FormRepeatKey,best32.); run;proc sort data=prepared; by STUDYID USUBJID TESTORD REP; run;data result; set prepared; by STUDYID USUBJID; retain LBSEQ; if first.USUBJID then LBSEQ=0; LBSEQ+1;run;proc sql; create table final as select DOMAIN, STUDYID, USUBJID, LBSEQ, LBTESTCD, LBTEST, LBORRES, LBORRESU, LBSTRESC, LBSTRESN, LBSTRESU, LBNRIND, LBDTC from result;quit;proc export data=final outfile="/app/output/lb.csv" dbms=csv replace; run;
yamaa
Comments
Signed in with GitHub; saved in repository Discussions