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: keep every blood pressure reading taken at a visit and add the protocol's visit value beside them: one record per reading with its replicate number, plus one record per test and visit holding the mean of the readings actually taken, marked as a derived record.
Input: long-form Operational Data Model (ODM) rows, one row per collected item, with the collected entry in the value field. Each replicate of a blood pressure reading is one repeat of the vital-signs item group, numbered in the item-group repeat key; the visit rides in the study event.
Variables:
VSTESTCDis the test code of the collected item:SYSBPorDIABP.VSTESTis the test name of the collected item.VSREPNUMis the item-group repeat key: it numbers the readings of one test at one visit, and stays blank on the derived mean record.VSORRESis the reading written as text from its numeric value, so trailing zeros are dropped (a collected82.50reads82.5); on the mean record it carries the mean.VSORRESUismmHgfor every record.VSSTRESNis the numeric result: the reading itself on a reading record, the mean of the readings actually taken on the mean record.VSSTRESCis the same value written as text, so it always agrees with the numeric result.VSDRVFLmarks the mean record withYand stays blank on the reading records.VSSEQnumbers every record of a subject in one sequence, by visit name, then test code (DIABPbeforeSYSBP): each test's readings in replicate order, then its mean record.
Note: a reading that was not taken, whether its record is absent or its value is blank, gives no reading record, and the visit mean is taken over the readings present.
Inputs
Under review1 source fileinput/odm.csv
Edit23 rows| StudyOID | MetaDataVersionOID | SubjectKey | StudyEventOID | StudyEventRepeatKey | ItemGroupOID | ItemGroupRepeatKey | ItemOID | Value |
|---|---|---|---|---|---|---|---|---|
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT1 | 1 | IG.VS | 1 | IT.VS.SYSBP | 120 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT1 | 1 | IG.VS | 1 | IT.VS.DIABP | 80 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT1 | 1 | IG.VS | 2 | IT.VS.SYSBP | 122 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT1 | 1 | IG.VS | 2 | IT.VS.DIABP | 78 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT1 | 1 | IG.VS | 3 | IT.VS.SYSBP | 118 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT1 | 1 | IG.VS | 3 | IT.VS.DIABP | 82 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT2 | 1 | IG.VS | 1 | IT.VS.SYSBP | 116 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT2 | 1 | IG.VS | 1 | IT.VS.DIABP | 76 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT2 | 1 | IG.VS | 2 | IT.VS.SYSBP | 114 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT2 | 1 | IG.VS | 2 | IT.VS.DIABP | 78 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT2 | 1 | IG.VS | 3 | IT.VS.SYSBP | 118 |
| YAMAA-01 | MDV.1 | YAMAA-01-001 | SE.VISIT2 | 1 | IG.VS | 3 | IT.VS.DIABP | 74 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT1 | 1 | IG.VS | 1 | IT.VS.SYSBP | 130 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT1 | 1 | IG.VS | 1 | IT.VS.DIABP | 86 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT1 | 1 | IG.VS | 2 | IT.VS.SYSBP | 132 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT1 | 1 | IG.VS | 2 | IT.VS.DIABP | 84 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT1 | 1 | IG.VS | 3 | IT.VS.SYSBP | 128 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT1 | 1 | IG.VS | 3 | IT.VS.DIABP | 88 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT2 | 1 | IG.VS | 1 | IT.VS.SYSBP | 124 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT2 | 1 | IG.VS | 1 | IT.VS.DIABP | 82 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT2 | 1 | IG.VS | 2 | IT.VS.SYSBP | 126 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT2 | 1 | IG.VS | 2 | IT.VS.DIABP | 80 |
| YAMAA-01 | MDV.1 | YAMAA-01-002 | SE.VISIT2 | 1 | IG.VS | 3 | IT.VS.DIABP | 84 |
Expected output
Under review31 expected rowsexpected/vs.csv
Edit31 rows| DOMAIN | STUDYID | USUBJID | VSSEQ | VISIT | VSTESTCD | VSTEST | VSREPNUM | VSORRES | VSORRESU | VSSTRESN | VSSTRESC | VSDRVFL |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| VS | YAMAA-01 | 1 | VISIT 1 | DIABP | Diastolic Blood Pressure | 1 | 80 | mmHg | 80 | 80 | — | |
| VS | YAMAA-01 | 2 | VISIT 1 | DIABP | Diastolic Blood Pressure | 2 | 78 | mmHg | 78 | 78 | — | |
| VS | YAMAA-01 | 3 | VISIT 1 | DIABP | Diastolic Blood Pressure | 3 | 82 | mmHg | 82 | 82 | — | |
| VS | YAMAA-01 | 4 | VISIT 1 | DIABP | Diastolic Blood Pressure | — | 80 | mmHg | 80 | 80 | Y | |
| VS | YAMAA-01 | 5 | VISIT 1 | SYSBP | Systolic Blood Pressure | 1 | 120 | mmHg | 120 | 120 | — | |
| VS | YAMAA-01 | 6 | VISIT 1 | SYSBP | Systolic Blood Pressure | 2 | 122 | mmHg | 122 | 122 | — | |
| VS | YAMAA-01 | 7 | VISIT 1 | SYSBP | Systolic Blood Pressure | 3 | 118 | mmHg | 118 | 118 | — | |
| VS | YAMAA-01 | 8 | VISIT 1 | SYSBP | Systolic Blood Pressure | — | 120 | mmHg | 120 | 120 | Y | |
| VS | YAMAA-01 | 9 | VISIT 2 | DIABP | Diastolic Blood Pressure | 1 | 76 | mmHg | 76 | 76 | — | |
| VS | YAMAA-01 | 10 | VISIT 2 | DIABP | Diastolic Blood Pressure | 2 | 78 | mmHg | 78 | 78 | — | |
| VS | YAMAA-01 | 11 | VISIT 2 | DIABP | Diastolic Blood Pressure | 3 | 74 | mmHg | 74 | 74 | — | |
| VS | YAMAA-01 | 12 | VISIT 2 | DIABP | Diastolic Blood Pressure | — | 76 | mmHg | 76 | 76 | Y | |
| VS | YAMAA-01 | 13 | VISIT 2 | SYSBP | Systolic Blood Pressure | 1 | 116 | mmHg | 116 | 116 | — | |
| VS | YAMAA-01 | 14 | VISIT 2 | SYSBP | Systolic Blood Pressure | 2 | 114 | mmHg | 114 | 114 | — | |
| VS | YAMAA-01 | 15 | VISIT 2 | SYSBP | Systolic Blood Pressure | 3 | 118 | mmHg | 118 | 118 | — | |
| VS | YAMAA-01 | 16 | VISIT 2 | SYSBP | Systolic Blood Pressure | — | 116 | mmHg | 116 | 116 | Y | |
| VS | YAMAA-01 | 1 | VISIT 1 | DIABP | Diastolic Blood Pressure | 1 | 86 | mmHg | 86 | 86 | — | |
| VS | YAMAA-01 | 2 | VISIT 1 | DIABP | Diastolic Blood Pressure | 2 | 84 | mmHg | 84 | 84 | — | |
| VS | YAMAA-01 | 3 | VISIT 1 | DIABP | Diastolic Blood Pressure | 3 | 88 | mmHg | 88 | 88 | — | |
| VS | YAMAA-01 | 4 | VISIT 1 | DIABP | Diastolic Blood Pressure | — | 86 | mmHg | 86 | 86 | Y | |
| VS | YAMAA-01 | 5 | VISIT 1 | SYSBP | Systolic Blood Pressure | 1 | 130 | mmHg | 130 | 130 | — | |
| VS | YAMAA-01 | 6 | VISIT 1 | SYSBP | Systolic Blood Pressure | 2 | 132 | mmHg | 132 | 132 | — | |
| VS | YAMAA-01 | 7 | VISIT 1 | SYSBP | Systolic Blood Pressure | 3 | 128 | mmHg | 128 | 128 | — | |
| VS | YAMAA-01 | 8 | VISIT 1 | SYSBP | Systolic Blood Pressure | — | 130 | mmHg | 130 | 130 | Y | |
| VS | YAMAA-01 | 9 | VISIT 2 | DIABP | Diastolic Blood Pressure | 1 | 82 | mmHg | 82 | 82 | — | |
| VS | YAMAA-01 | 10 | VISIT 2 | DIABP | Diastolic Blood Pressure | 2 | 80 | mmHg | 80 | 80 | — | |
| VS | YAMAA-01 | 11 | VISIT 2 | DIABP | Diastolic Blood Pressure | 3 | 84 | mmHg | 84 | 84 | — | |
| VS | YAMAA-01 | 12 | VISIT 2 | DIABP | Diastolic Blood Pressure | — | 82 | mmHg | 82 | 82 | Y | |
| VS | YAMAA-01 | 13 | VISIT 2 | SYSBP | Systolic Blood Pressure | 1 | 124 | mmHg | 124 | 124 | — | |
| VS | YAMAA-01 | 14 | VISIT 2 | SYSBP | Systolic Blood Pressure | 2 | 126 | mmHg | 126 | 126 | — | |
| VS | YAMAA-01 | 15 | VISIT 2 | SYSBP | Systolic Blood Pressure | — | 125 | mmHg | 125 | 125 | Y |
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 "VS". | 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 | ||||
| VISIT | Visit Name | Char | Collected | Recode ODM.StudyEventOID: "SE.VISIT1" → "VISIT 1", "SE.VISIT2" → "VISIT 2"; missing or unlisted values are errors. | SDTM | 4 | ||||
| VSTESTCD | Vital Signs Test Short Name | Char | SYSBP, DIABP | Collected | Recode ODM.ItemOID: "IT.VS.SYSBP" → "SYSBP", "IT.VS.DIABP" → "DIABP"; missing or unlisted values are errors. | SDTM | 5 | |||
| VSTEST | Vital Signs Test Name | Char | Collected | Recode ODM.ItemOID: "IT.VS.SYSBP" → "Systolic Blood Pressure", "IT.VS.DIABP" → "Diastolic Blood Pressure"; missing or unlisted values are errors. | SDTM | 6 | ||||
| VSREPNUM | Replicate Number | Num | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 7 | ||||
| VSSTRESN | Numeric Result/Finding in Standard Units | Num | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 8 | ||||
| VSSTRESC | Character Result/Finding in Std Format | Char | Derived | Copy value from VSSTRESN. | SDTM | 9 | ||||
| VSORRES | Result or Finding in Original Units | Char | Derived | Copy value from VSSTRESN. | SDTM | 10 | ||||
| VSORRESU | Original Units | Char | mmHg | Assigned | Set constant value "mmHg". | SDTM | 11 | |||
| VSDRVFL | Derived Record Flag | Char | Y | Derived | Set per constructed row; see the Row construction sheet. | SDTM | 12 | |||
| VSSEQ | Sequence Number | Num | Derived | Row number within each group of STUDYID, USUBJID, ordered by VISIT then VSTESTCD then ORD then VSREPNUM. | SDTM | 13 |
| Template | Include when | ORD | VSREPNUM | VSSTRESN | VSDRVFL |
|---|---|---|---|---|---|
| systolic | VSSTRESN IS NOT NULL | Constant "1" | Aggregate ONLY(ODM.ItemGroupRepeatKey) over records matching on the shared output keys | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.VS.SYSBP' | Constant "None" |
| diastolic | VSSTRESN IS NOT NULL | Constant "1" | Aggregate ONLY(ODM.ItemGroupRepeatKey) over records matching on the shared output keys | Aggregate ONLY(ODM.Value) over records matching on the shared output keys, where ODM.ItemOID = 'IT.VS.DIABP' | Constant "None" |
| means | Constant "2" | Constant "None" | Aggregate MEAN(ODM.Value) over records matching on the shared output keys | Constant "Y" |
| Variable | Permitted values |
|---|---|
| VSTESTCD | SYSBP, DIABP |
| VSORRESU | mmHg |
| VSDRVFL | Y |
| 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-vs-replicates/full.md
Edit32 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create a VS dataset with one record per blood pressure reading and one mean record per test and visit.
The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, VSSEQ, VISIT, VSTESTCD, VSTEST, VSREPNUM, VSORRES, VSORRESU, VSSTRESN, VSSTRESC, VSDRVFL
STUDYID is the ODM StudyOID and USUBJID is the SubjectKey, each as given.
VISIT is VISIT 1 for study event SE.VISIT1 and VISIT 2 for SE.VISIT2. VSTESTCD and VSTEST are SYSBP and Systolic Blood Pressure, or DIABP and Diastolic Blood Pressure, from the collected item. VSSEQ numbers every record of a subject from 1, by visit name, then test code (DIABP before SYSBP): each test's readings in replicate order, then its mean record. VSREPNUM is the item-group repeat key numbering the readings of one test at one visit, and has no value on the mean record.
VSORRES is the reading written as text, and the mean on the mean record; a whole number is written without a decimal point. VSORRESU is mmHg for every record. VSSTRESN is the reading itself on a reading record, and the mean of the readings actually taken on the mean record. VSSTRESC is the same value written as text, so it always agrees with the numeric result. VSDRVFL marks the mean record with Y and has no value on the reading records.
A reading that was not taken, whether its record is absent or its value is blank, gives no reading record, and the visit mean is taken over the readings present.
Read the source datasets from /app/input and save the completed dataset as /app/output/vs.csv.
prompts/sdtm-vs-replicates/conventions.md
Edit17 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create a VS dataset with one record per blood pressure reading and one mean record per test and visit.
The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, VSSEQ, VISIT, VSTESTCD, VSTEST, VSREPNUM, VSORRES, VSORRESU, VSSTRESN, VSSTRESC, VSDRVFL
VISIT is VISIT 1 for study event SE.VISIT1 and VISIT 2 for SE.VISIT2. VSTESTCD and VSTEST are SYSBP and Systolic Blood Pressure, or DIABP and Diastolic Blood Pressure, from the collected item.
VSORRES is written as text; a whole number is written without a decimal point. VSDRVFL is Y or has no value.
Read the source datasets from /app/input and save the completed dataset as /app/output/vs.csv.
prompts/sdtm-vs-replicates/brief.md
Edit10 linesFollowing CDISC SDTM standards, use the provided ODM dataset to create a VS dataset with one record per blood pressure reading and one mean record per test and visit.
The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, VSSEQ, VISIT, VSTESTCD, VSTEST, VSREPNUM, VSORRES, VSORRESU, VSSTRESN, VSSTRESC, VSDRVFL
Read the source datasets from /app/input and save the completed dataset as /app/output/vs.csv.
run.R
Edit4 lineslibrary(yamaa)vs <- yamaa_domain("spec.yaml")$outputvsrun.py
Edit4 linesimport yamaavs = yamaa.yamaa_domain("spec.yaml").outputvssolutions/sdtm-vs-replicates/result.R
Edit93 lines# Reference solution for the yamaa benchmark sdtm-vs-replicates (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)fmt_text <- function(x) { if (is.na(x)) { return(NA_character_) } if (x == floor(x)) { formatC(x, format = "f", digits = 0) } else { format(x, scientific = FALSE, trim = TRUE, digits = 15) }}odm <- read_csv( "/app/input/odm.csv", col_types = cols(.default = col_character()))readings <- odm |> filter( ItemOID %in% c("IT.VS.SYSBP", "IT.VS.DIABP"), StudyEventOID %in% c("SE.VISIT1", "SE.VISIT2"), !is.na(Value) & Value != "" ) |> mutate( VISIT = case_when( StudyEventOID == "SE.VISIT1" ~ "VISIT 1", .default = "VISIT 2" ), VSTESTCD = case_when( ItemOID == "IT.VS.DIABP" ~ "DIABP", .default = "SYSBP" ), VSTEST = case_when( ItemOID == "IT.VS.DIABP" ~ "Diastolic Blood Pressure", .default = "Systolic Blood Pressure" ), VSREPNUM = suppressWarnings(as.integer(ItemGroupRepeatKey)), val = suppressWarnings(as.numeric(Value)), STUDYID = StudyOID, USUBJID = SubjectKey ) |> filter(!is.na(val), !is.na(VSREPNUM)) |> select(STUDYID, USUBJID, VISIT, VSTESTCD, VSTEST, VSREPNUM, val)mean_records <- readings |> group_by(STUDYID, USUBJID, VISIT, VSTESTCD, VSTEST) |> summarise(mean_val = mean(val), .groups = "drop")vs <- bind_rows( readings |> transmute( DOMAIN = "VS", STUDYID, USUBJID, VISIT, VSTESTCD, VSTEST, VSREPNUM, VSORRES = vapply(val, fmt_text, character(1)), VSORRESU = "mmHg", VSSTRESN = val, VSSTRESC = VSORRES, VSDRVFL = NA_character_ ), mean_records |> transmute( DOMAIN = "VS", STUDYID, USUBJID, VISIT, VSTESTCD, VSTEST, VSREPNUM = NA_integer_, VSORRES = vapply(mean_val, fmt_text, character(1)), VSORRESU = "mmHg", VSSTRESN = mean_val, VSSTRESC = VSORRES, VSDRVFL = "Y" )) |> arrange(USUBJID, VISIT, VSTESTCD, is.na(VSREPNUM), VSREPNUM) |> group_by(USUBJID) |> mutate(VSSEQ = row_number()) |> ungroup() |> arrange(USUBJID, VSSEQ) |> select( DOMAIN, STUDYID, USUBJID, VSSEQ, VISIT, VSTESTCD, VSTEST, VSREPNUM, VSORRES, VSORRESU, VSSTRESN, VSSTRESC, VSDRVFL )dir.create("/app/output", showWarnings = FALSE)write_csv(vs, "/app/output/vs.csv", na = "")solutions/sdtm-vs-replicates/result.py
Edit134 lines# Reference solution for the yamaa benchmark sdtm-vs-replicates (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 fmt_text(x: float | None) -> str | None: if x is None: return None import math if isinstance(x, float) and (math.isnan(x) or math.isinf(x)): return None if float(x).is_integer(): return str(int(float(x))) return f"{float(x):.15g}"odm = pl.read_csv("/app/input/odm.csv", infer_schema=False)test_name = { "IT.VS.SYSBP": ("SYSBP", "Systolic Blood Pressure"), "IT.VS.DIABP": ("DIABP", "Diastolic Blood Pressure"),}visit_name = {"SE.VISIT1": "VISIT 1", "SE.VISIT2": "VISIT 2"}# Collected readings: one per subject, visit, test, and replicate. A blank# value or an absent record gives no reading record.readings: dict[tuple[str, str, str, str, str], float] = {}studies: dict[str, str] = {}for row in odm.to_dicts(): if row["ItemOID"] not in test_name or row["StudyEventOID"] not in visit_name: continue value = row["Value"] if value is None or value == "": continue studies[row["SubjectKey"]] = row["StudyOID"] key = ( row["SubjectKey"], row["StudyEventOID"], row["ItemOID"], row["ItemGroupRepeatKey"], ) readings[key] = float(value) testcd, _ = test_name[row["ItemOID"]] _ = testcdrecords = []# By visit name, then DIABP before SYSBP; each test's readings in replicate# order, then its mean record.for subject in sorted(studies): for event in sorted(visit_name, key=lambda e: visit_name[e]): visit = visit_name[event] for item in ("IT.VS.DIABP", "IT.VS.SYSBP"): testcd, test = test_name[item] reps = sorted( (rep, val) for (s, e, i, rep), val in readings.items() if s == subject and e == event and i == item ) if not reps: continue for rep, val in reps: records.append( { "DOMAIN": "VS", "STUDYID": studies[subject], "USUBJID": subject, "VISIT": visit, "VSTESTCD": testcd, "VSTEST": test, "VSREPNUM": int(rep), "VSORRES": fmt_text(val), "VSORRESU": "mmHg", "VSSTRESN": val, "VSSTRESC": fmt_text(val), "VSDRVFL": None, "_visit_ord": visit, "_test_ord": testcd, "_rep_ord": int(rep), "_mean_last": 0, } ) mean = sum(val for _, val in reps) / len(reps) records.append( { "DOMAIN": "VS", "STUDYID": studies[subject], "USUBJID": subject, "VISIT": visit, "VSTESTCD": testcd, "VSTEST": test, "VSREPNUM": None, "VSORRES": fmt_text(mean), "VSORRESU": "mmHg", "VSSTRESN": mean, "VSSTRESC": fmt_text(mean), "VSDRVFL": "Y", "_visit_ord": visit, "_test_ord": testcd, "_rep_ord": 999, "_mean_last": 1, } )vs = ( pl.DataFrame(records) .sort(["USUBJID", "_visit_ord", "_test_ord", "_mean_last", "_rep_ord"]) .with_columns(VSSEQ=pl.int_range(1, pl.len() + 1).over("USUBJID")) .sort(["USUBJID", "VSSEQ"]) .select( "DOMAIN", "STUDYID", "USUBJID", "VSSEQ", "VISIT", "VSTESTCD", "VSTEST", "VSREPNUM", "VSORRES", "VSORRESU", "VSSTRESN", "VSSTRESC", "VSDRVFL", ))Path("/app/output").mkdir(exist_ok=True)vs.write_csv("/app/output/vs.csv")solutions/sdtm-vs-replicates/result.sas
Edit25 lines/* opensas reference solution for the yamaa benchmark sdtm-vs-replicates. 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;data readings; set odm; where ItemOID in ('IT.VS.SYSBP','IT.VS.DIABP') and not missing(Value); length STUDYID USUBJID VISIT VSTESTCD $1024;STUDYID=StudyOID; USUBJID=SubjectKey; VISIT=catx(' ','VISIT',scan(StudyEventOID,-1,'T')); if StudyEventOID='SE.VISIT1' then VISIT='VISIT 1'; if StudyEventOID='SE.VISIT2' then VISIT='VISIT 2'; VSTESTCD=scan(ItemOID,-1,'.'); VSREPNUM=input(ItemGroupRepeatKey,best32.); VSSTRESN=input(Value,best32.); MEANORD=0; run;proc sql; create table means as select STUDYID,USUBJID,VISIT,VSTESTCD,mean(VSSTRESN) as VSSTRESN from readings group by STUDYID,USUBJID,VISIT,VSTESTCD; quit;data meanout; set means; VSREPNUM=.; MEANORD=1; run;data prepared; set readings meanout; length DOMAIN $2 VSTEST VSORRES VSORRESU VSSTRESC VSDRVFL $1024; DOMAIN='VS'; VSTEST='Diastolic Blood Pressure'; if VSTESTCD='SYSBP' then VSTEST='Systolic Blood Pressure'; VSORRES=strip(put(VSSTRESN,best32.)); VSSTRESC=VSORRES; VSORRESU='mmHg'; VSDRVFL=''; if MEANORD=1 then VSDRVFL='Y'; run;proc sort data=prepared; by STUDYID USUBJID VISIT VSTESTCD MEANORD VSREPNUM; run;data result; set prepared; by STUDYID USUBJID; retain VSSEQ; if first.USUBJID then VSSEQ=0; VSSEQ+1;run;proc sql; create table final as select DOMAIN, STUDYID, USUBJID, VSSEQ, VISIT, VSTESTCD, VSTEST, VSREPNUM, VSORRES, VSORRESU, VSSTRESN, VSSTRESC, VSDRVFL from result;quit;proc export data=final outfile="/app/output/vs.csv" dbms=csv replace; run;
yamaa
Comments
Signed in with GitHub; saved in repository Discussions