Review ask

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.

  1. 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.
  2. Inputs: Do they look like data collected in a real trial, and do they include the situations you would expect to meet in one?
  3. 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

Lifecycle: draftEditUnder review
What this benchmark means
README.md

Goal: build one Demographics (DM) record per subject carrying race (RACE) and ethnicity (ETHNIC), and one supplemental Demographics (SUPPDM) record per reported race for each subject who marked several.

Input: electronic data capture (EDC) output in long form, one row per collected item; each race option a subject marks contributes one race row, and ethnicity contributes its own row. A race marked twice counts once.

Variables:

  • RACE (DM): reported race in controlled terms: WHITE, ASIAN, BLACK OR AFRICAN AMERICAN, AMERICAN INDIAN OR ALASKA NATIVE, NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER, MULTIPLE when several races were marked, OTHER for a listed free-text answer that fits none of the named races, UNKNOWN for a refused answer, and NOT REPORTED for a recorded non-answer; blank when no race item was marked or a single answer is not in the sponsor's list.
  • ETHNIC (DM): reported ethnicity in controlled terms: HISPANIC OR LATINO, NOT HISPANIC OR LATINO, NOT REPORTED, or UNKNOWN; blank when no ethnicity item was collected or its answer is not in the sponsor's list.
  • IDVARVAL (SUPPDM): the subject identifier, linking the record to its DM row through IDVAR = USUBJID.
  • QNAM / QLABEL (SUPPDM): RACE1 / Race 1, RACE2 / Race 2, and so on, one per distinct race the subject marked, numbered in alphabetical order of the collected answer because the input carries no report order.
  • QVAL (SUPPDM): that race in controlled terms, as in RACE.
  • QORIG (SUPPDM): the origin, always CRF; QEVAL is blank.

Note: SUPPDM carries race records exactly for the subjects whose DM record says MULTIPLE, however many races they marked.

Inputs

Under review
1 source file

input/odm.csv

Edit
30 rows
input/odm.csv
StudyOIDMetaDataVersionOIDSubjectKeyStudyEventOIDStudyEventRepeatKeyItemGroupOIDItemGroupRepeatKeyItemOIDValue
YAMAA-01MDV.1YAMAA-01-101SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-101SCREENING1IG.DM1IT.DM.ETHNICNot Hispanic or Latino
YAMAA-01MDV.1YAMAA-01-102SCREENING1IG.DM1IT.DM.RACEAsian
YAMAA-01MDV.1YAMAA-01-102SCREENING1IG.DM1IT.DM.RACEBlack or African American
YAMAA-01MDV.1YAMAA-01-102SCREENING1IG.DM1IT.DM.ETHNICHispanic or Latino
YAMAA-01MDV.1YAMAA-01-103SCREENING1IG.DM1IT.DM.ETHNICNot Hispanic or Latino
YAMAA-01MDV.1YAMAA-01-104SCREENING1IG.DM1IT.DM.RACEAmerican Indian or Alaska Native
YAMAA-01MDV.1YAMAA-01-104SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-104SCREENING1IG.DM1IT.DM.ETHNICNot reported
YAMAA-01MDV.1YAMAA-01-105SCREENING1IG.DM1IT.DM.RACEOther, specify: Fijian
YAMAA-01MDV.1YAMAA-01-105SCREENING1IG.DM1IT.DM.ETHNICUnknown
YAMAA-01MDV.1YAMAA-01-106SCREENING1IG.DM1IT.DM.RACESubject refused
YAMAA-01MDV.1YAMAA-01-106SCREENING1IG.DM1IT.DM.ETHNICHispanic or Latino
YAMAA-01MDV.1YAMAA-01-107SCREENING1IG.DM1IT.DM.RACEAsian
YAMAA-01MDV.1YAMAA-01-107SCREENING1IG.DM1IT.DM.RACEBlack or African American
YAMAA-01MDV.1YAMAA-01-107SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-107SCREENING1IG.DM1IT.DM.ETHNICNot Hispanic or Latino
YAMAA-01MDV.1YAMAA-01-108SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-108SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-108SCREENING1IG.DM1IT.DM.ETHNICNot Hispanic or Latino
YAMAA-01MDV.1YAMAA-01-109SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-109SCREENING1IG.DM1IT.DM.RACEAsian
YAMAA-01MDV.1YAMAA-01-109SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-109SCREENING1IG.DM1IT.DM.ETHNICNot Hispanic or Latino
YAMAA-01MDV.1YAMAA-01-110SCREENING1IG.DM1IT.DM.RACENot reported
YAMAA-01MDV.1YAMAA-01-111SCREENING1IG.DM1IT.DM.RACEPacific Islander
YAMAA-01MDV.1YAMAA-01-111SCREENING1IG.DM1IT.DM.ETHNICPrefer not to answer
YAMAA-01MDV.1YAMAA-01-112SCREENING1IG.DM1IT.DM.RACENot reported
YAMAA-01MDV.1YAMAA-01-112SCREENING1IG.DM1IT.DM.RACEWhite
YAMAA-01MDV.1YAMAA-01-112SCREENING1IG.DM1IT.DM.ETHNICNot Hispanic or Latino

Expected output

Under review
23 expected rows

expected/dm.csv

Edit
12 rows
expected/dm.csv
DOMAINSTUDYIDUSUBJIDSUBJIDRACEETHNIC
DMYAMAA-01YAMAA-01-101WHITENOT HISPANIC OR LATINO
DMYAMAA-01YAMAA-01-102MULTIPLEHISPANIC OR LATINO
DMYAMAA-01YAMAA-01-103—NOT HISPANIC OR LATINO
DMYAMAA-01YAMAA-01-104MULTIPLENOT REPORTED
DMYAMAA-01YAMAA-01-105OTHERUNKNOWN
DMYAMAA-01YAMAA-01-106UNKNOWNHISPANIC OR LATINO
DMYAMAA-01YAMAA-01-107MULTIPLENOT HISPANIC OR LATINO
DMYAMAA-01YAMAA-01-108WHITENOT HISPANIC OR LATINO
DMYAMAA-01YAMAA-01-109MULTIPLENOT HISPANIC OR LATINO
DMYAMAA-01YAMAA-01-110NOT REPORTED—
DMYAMAA-01YAMAA-01-111——
DMYAMAA-01YAMAA-01-112MULTIPLENOT HISPANIC OR LATINO

expected/suppdm.csv

Edit
11 rows
expected/suppdm.csv
STUDYIDRDOMAINUSUBJIDIDVARIDVARVALQNAMQLABELQVALQORIGQEVAL
YAMAA-01DMUSUBJIDYAMAA-01-102RACE1Race 1ASIANCRF—
YAMAA-01DMUSUBJIDYAMAA-01-102RACE2Race 2BLACK OR AFRICAN AMERICANCRF—
YAMAA-01DMUSUBJIDYAMAA-01-104RACE1Race 1AMERICAN INDIAN OR ALASKA NATIVECRF—
YAMAA-01DMUSUBJIDYAMAA-01-104RACE2Race 2WHITECRF—
YAMAA-01DMUSUBJIDYAMAA-01-107RACE1Race 1ASIANCRF—
YAMAA-01DMUSUBJIDYAMAA-01-107RACE2Race 2BLACK OR AFRICAN AMERICANCRF—
YAMAA-01DMUSUBJIDYAMAA-01-107RACE3Race 3WHITECRF—
YAMAA-01DMUSUBJIDYAMAA-01-109RACE1Race 1ASIANCRF—
YAMAA-01DMUSUBJIDYAMAA-01-109RACE2Race 2WHITECRF—
YAMAA-01DMUSUBJIDYAMAA-01-112RACE1Race 1NOT REPORTEDCRF—
YAMAA-01DMUSUBJIDYAMAA-01-112RACE2Race 2WHITECRF—
Shaded columns are derived— = missing value

Comments and assessment materials

Comments

Signed in with GitHub; saved in repository Discussions

Mapping spec

Generated from the benchmark YAML; do not edit by hand

Variable NameVariable LabelTypeLengthControlled Terms or FormatOriginCoreConversion DefinitionVariable TypeVariable OrderComments for Define
STUDYIDStudy IdentifierCharDerivedSet per constructed row; see the Row construction sheet.SUPP1
RDOMAINRelated Domain AbbreviationCharAssignedSet constant value "DM".SUPP2
USUBJIDUnique Subject IdentifierCharDerivedSet per constructed row; see the Row construction sheet.SUPP3
IDVARIdentifying VariableCharAssignedSet constant value "USUBJID".SUPP4
IDVARVALIdentifying Variable ValueCharDerivedCopy value from USUBJID.SUPP5
QNAMQualifier Variable NameCharDerivedFill the template "RACE{RACENUMC}".SUPP6
QLABELQualifier LabelCharDerivedFill the template "Race {RACENUMC}".SUPP7
QVALData ValueCharAMERICAN INDIAN OR ALASKA NATIVE, ASIAN, BLACK OR AFRICAN AMERICAN, NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER, WHITE, OTHER, NOT REPORTED, UNKNOWNDerivedRecode QVALRAW: "American Indian or Alaska Native" → "AMERICAN INDIAN OR ALASKA NATIVE", "Asian" → "ASIAN", "Black or African American" → "BLACK OR AFRICAN AMERICAN", "Native Hawaiian or Other Pacific Islander" → "NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER", "White" → "WHITE", "Other, specify: Fijian" → "OTHER", "Not reported" → "NOT REPORTED", "Subject refused" → "UNKNOWN"; missing values stay missing; unlisted values are errors.SUPP8
QORIGOriginCharAssignedSet constant value "CRF".SUPP9
QEVALEvaluatorCharAssignedSet constant value "None".SUPP10
TemplateInclude whenSTUDYIDUSUBJIDITEMOIDQVALRAWDMRACE
reported_raceITEMOID = 'IT.DM.RACE' AND DMRACE = 'MULTIPLE'Copy ODM.StudyOIDCopy ODM.SubjectKeyCopy ODM.ItemOIDCopy ODM.ValueCopy RACE from the DM record whose STUDYID equals ODM.StudyOID and USUBJID equals ODM.SubjectKey, and a row with no match is an error
VariablePermitted values
QVALAMERICAN INDIAN OR ALASKA NATIVE, ASIAN, BLACK OR AFRICAN AMERICAN, NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER, WHITE, OTHER, NOT REPORTED, UNKNOWN
VersionDateAuthorDescriptionReviewerSign-off
1.32026-09-29yamaa docs buildShow study codelist names, external dictionaries, and ISO 8601 formats in variable rows; list the document's codelist values and metadata
1.22026-09-29yamaa docs buildClassify ADaM copies from a declared input as Predecessor and recodes as Derived, and SDTM recodes of locally derived columns as Derived
1.12026-09-29yamaa docs buildResolve lookups into the donor record they select, and give every derivation shape a plain-language rule instead of its raw YAML
1.0yamaa docs buildInitial generation from spec.yaml

Agent prompt

The request an agent receives with the input files; each tier states no more than the one above

prompts/sdtm-dm-race-ethnicity/full.md

Edit
42 lines

Following CDISC SDTM standards, use the provided ODM dataset to create a DM dataset with one record per subject and a SUPPDM dataset with one record per reported race for each subject who marked several.

The DM dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, SUBJID, RACE, ETHNIC The SUPPDM dataset should contain the following columns in this order: STUDYID, RDOMAIN, USUBJID, IDVAR, IDVARVAL, QNAM, QLABEL, QVAL, QORIG, QEVAL

STUDYID is the ODM StudyOID and USUBJID is the SubjectKey, each as given.

Each collected race answer maps to a controlled term:

  • "White", "Asian", "Black or African American", "American Indian or Alaska Native", and "Native Hawaiian or Other Pacific Islander" give the same name in upper case;
  • "Other, specify: Fijian" gives OTHER;
  • "Subject refused" gives UNKNOWN;
  • "Not reported" gives NOT REPORTED;
  • any other answer is not in the list and gives no value.

Every distinct answer a subject gave counts as one race, a non-answer such as "Not reported" included, and a race marked twice counts once. RACE is MULTIPLE when a subject has two or more races, and otherwise the mapped term of the single answer; it has no value when no race was marked or the single answer is not in the list. ETHNIC maps the collected answer: "Hispanic or Latino" gives HISPANIC OR LATINO, "Not Hispanic or Latino" gives NOT HISPANIC OR LATINO, "Not reported" gives NOT REPORTED, and "Unknown" gives UNKNOWN. ETHNIC has no value when no ethnicity was collected or its answer is not in the list. SUBJID repeats USUBJID.

SUPPDM carries records exactly for the subjects whose DM record says MULTIPLE, one per race. RDOMAIN is DM, IDVAR is USUBJID, and IDVARVAL is the subject identifier. QNAM is RACE1, RACE2, and so on, with QLABEL Race 1, Race 2, and so on, numbered in alphabetical order of the collected answer. QVAL maps the race as RACE does. QORIG is always CRF, and QEVAL has no value.

Read the source datasets from /app/input and save the completed DM dataset as /app/output/dm.csv and the completed SUPPDM dataset as /app/output/suppdm.csv.

prompts/sdtm-dm-race-ethnicity/conventions.md

Edit
20 lines

Following CDISC SDTM standards, use the provided ODM dataset to create a DM dataset with one record per subject and a SUPPDM dataset with one record per reported race for each subject who marked several.

The DM dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, SUBJID, RACE, ETHNIC The SUPPDM dataset should contain the following columns in this order: STUDYID, RDOMAIN, USUBJID, IDVAR, IDVARVAL, QNAM, QLABEL, QVAL, QORIG, QEVAL

Each collected race answer gives the same name in upper case, except that "Other, specify: Fijian" gives OTHER and "Subject refused" gives UNKNOWN; ETHNIC maps the collected answer to the same name in upper case. In SUPPDM, IDVAR is USUBJID; QNAM and QLABEL are RACE1 and Race 1, RACE2 and Race 2, and so on, in alphabetical order of the collected answer; QVAL maps the race as RACE does; and QORIG is CRF.

Read the source datasets from /app/input and save the completed DM dataset as /app/output/dm.csv and the completed SUPPDM dataset as /app/output/suppdm.csv.

prompts/sdtm-dm-race-ethnicity/brief.md

Edit
13 lines

Following CDISC SDTM standards, use the provided ODM dataset to create a DM dataset with one record per subject and a SUPPDM dataset with one record per reported race for each subject who marked several.

The DM dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, SUBJID, RACE, ETHNIC The SUPPDM dataset should contain the following columns in this order: STUDYID, RDOMAIN, USUBJID, IDVAR, IDVARVAL, QNAM, QLABEL, QVAL, QORIG, QEVAL

Read the source datasets from /app/input and save the completed DM dataset as /app/output/dm.csv and the completed SUPPDM dataset as /app/output/suppdm.csv.

yamaa code

Runs the yamaa specification; its result must match the expected output

run.R

Edit
5 lines
library(yamaa)dm <- yamaa_domain("spec_dm.yaml")$outputsuppdm <- yamaa_domain("spec_suppdm.yaml")$outputlist(dm = dm, suppdm = suppdm)

run.py

Edit
5 lines
import yamaadm = yamaa.yamaa_domain("spec_dm.yaml").outputsuppdm = yamaa.yamaa_domain("spec_suppdm.yaml").outputdm, suppdm

Solution without yamaa

Written from the full prompt and the inputs alone; CI checks it reproduces the expected output

solutions/sdtm-dm-race-ethnicity/result.R

Edit
118 lines
# Reference solution for the yamaa benchmark sdtm-dm-race-ethnicity (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)library(stringr)library(purrr)odm <- read_csv(  "/app/input/odm.csv",  col_types = cols(.default = col_character()))race_map <- c(  "White" = "WHITE",  "Asian" = "ASIAN",  "Black or African American" = "BLACK OR AFRICAN AMERICAN",  "American Indian or Alaska Native" = "AMERICAN INDIAN OR ALASKA NATIVE",  "Native Hawaiian or Other Pacific Islander" = "NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER",  "Other, specify: Fijian" = "OTHER",  "Subject refused" = "UNKNOWN",  "Not reported" = "NOT REPORTED")ethnic_map <- c(  "Hispanic or Latino" = "HISPANIC OR LATINO",  "Not Hispanic or Latino" = "NOT HISPANIC OR LATINO",  "Not reported" = "NOT REPORTED",  "Unknown" = "UNKNOWN")map_term <- function(x, lut) {  out <- unname(lut[x])  out[is.na(out)] <- NA_character_  out}subjects <- odm |>  distinct(StudyOID, SubjectKey) |>  mutate(    STUDYID = StudyOID,    USUBJID = SubjectKey  )race_distinct <- odm |>  filter(ItemOID == "IT.DM.RACE", Value != "", !is.na(Value)) |>  distinct(StudyOID, SubjectKey, Value)race_per_subject <- race_distinct |>  group_by(StudyOID, SubjectKey) |>  summarise(answers = list(sort(unique(Value))), .groups = "drop")ethnic_per_subject <- odm |>  filter(ItemOID == "IT.DM.ETHNIC", Value != "", !is.na(Value)) |>  group_by(StudyOID, SubjectKey) |>  summarise(ethnic_answer = first(Value), .groups = "drop")dm <- subjects |>  left_join(race_per_subject, by = c("StudyOID", "SubjectKey")) |>  left_join(ethnic_per_subject, by = c("StudyOID", "SubjectKey")) |>  rowwise() |>  mutate(    DOMAIN = "DM",    SUBJID = USUBJID,    RACE = if (is.null(answers) || length(answers) == 0 || all(is.na(answers))) {      NA_character_    } else if (length(answers) >= 2) {      "MULTIPLE"    } else {      map_term(answers[[1]], race_map)    },    ETHNIC = map_term(ethnic_answer, ethnic_map)  ) |>  ungroup() |>  select(STUDYID, USUBJID, DOMAIN, SUBJID, RACE, ETHNIC, StudyOID, SubjectKey) |>  arrange(USUBJID)multi <- dm |> filter(RACE == "MULTIPLE")suppdm <- race_distinct |>  inner_join(    multi |> select(StudyOID, SubjectKey),    by = c("StudyOID", "SubjectKey")  ) |>  left_join(    subjects |> select(StudyOID, SubjectKey, STUDYID, USUBJID),    by = c("StudyOID", "SubjectKey")  ) |>  arrange(USUBJID, Value) |>  group_by(STUDYID, USUBJID) |>  mutate(    n = row_number(),    QNAM = paste0("RACE", n),    QLABEL = paste("Race", n)  ) |>  ungroup() |>  mutate(    RDOMAIN = "DM",    IDVAR = "USUBJID",    IDVARVAL = USUBJID,    QVAL = map_term(Value, race_map),    QORIG = "CRF",    QEVAL = NA_character_  ) |>  select(STUDYID, RDOMAIN, USUBJID, IDVAR, IDVARVAL, QNAM, QLABEL, QVAL, QORIG, QEVAL) |>  arrange(USUBJID, QNAM)dir.create("/app/output", showWarnings = FALSE)write_csv(  dm |> select(DOMAIN, STUDYID, USUBJID, SUBJID, RACE, ETHNIC),  "/app/output/dm.csv",  na = "")write_csv(suppdm, "/app/output/suppdm.csv", na = "")

solutions/sdtm-dm-race-ethnicity/result.py

Edit
157 lines
# Reference solution for the yamaa benchmark sdtm-dm-race-ethnicity (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)RACE_MAP = {    "White": "WHITE",    "Asian": "ASIAN",    "Black or African American": "BLACK OR AFRICAN AMERICAN",    "American Indian or Alaska Native": "AMERICAN INDIAN OR ALASKA NATIVE",    "Native Hawaiian or Other Pacific Islander": "NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER",    "Other, specify: Fijian": "OTHER",    "Subject refused": "UNKNOWN",    "Not reported": "NOT REPORTED",}ETHNIC_MAP = {    "Hispanic or Latino": "HISPANIC OR LATINO",    "Not Hispanic or Latino": "NOT HISPANIC OR LATINO",    "Not reported": "NOT REPORTED",    "Unknown": "UNKNOWN",}# Distinct collected answers per subject.race_rows = odm.filter(pl.col("ItemOID") == "IT.DM.RACE", pl.col("Value") != "")ethnic_rows = odm.filter(pl.col("ItemOID") == "IT.DM.ETHNIC", pl.col("Value") != "")subjects = (    odm.select("StudyOID", "SubjectKey")    .unique()    .with_columns(        STUDYID=pl.col("StudyOID"),        USUBJID=pl.col("SubjectKey"),    ))race_distinct = (    race_rows.select("StudyOID", "SubjectKey", "Value")    .unique()    .group_by("StudyOID", "SubjectKey")    .agg(pl.col("Value").alias("answers")))ethnic_one = (    ethnic_rows.select("StudyOID", "SubjectKey", "Value")    .group_by("StudyOID", "SubjectKey")    .agg(pl.col("Value").first().alias("ethnic_answer")))dm = (    subjects.join(race_distinct, on=["StudyOID", "SubjectKey"], how="left")    .join(ethnic_one, on=["StudyOID", "SubjectKey"], how="left")    .with_columns(        DOMAIN=pl.lit("DM"),        SUBJID=pl.col("USUBJID"),        RACE=pl.col("answers").map_elements(            lambda ans: (                None                if ans is None or len(ans) == 0                else (                    "MULTIPLE"                    if len(ans) >= 2                    else RACE_MAP.get(ans[0])                )            ),            return_dtype=pl.String,        ),        ETHNIC=pl.col("ethnic_answer").map_elements(            lambda v: ETHNIC_MAP.get(v) if v is not None else None,            return_dtype=pl.String,        ),    )    .select("DOMAIN", "STUDYID", "USUBJID", "SUBJID", "RACE", "ETHNIC")    .sort("USUBJID"))# SUPPDM: one record per race for MULTIPLE subjects, alphabetical by answer.multi = (    subjects.join(race_distinct, on=["StudyOID", "SubjectKey"], how="left")    .with_columns(        RACE_TMP=pl.col("answers").map_elements(            lambda ans: (                None                if ans is None or len(ans) == 0                else ("MULTIPLE" if len(ans) >= 2 else RACE_MAP.get(ans[0]))            ),            return_dtype=pl.String,        )    )    .filter(pl.col("RACE_TMP") == "MULTIPLE"))supp_rows: list[dict] = []for row in multi.to_dicts():    studyid = row["StudyOID"]    usubjid_val = row["USUBJID"]    answers = sorted(row["answers"])    for i, ans in enumerate(answers, start=1):        supp_rows.append(            {                "STUDYID": studyid,                "RDOMAIN": "DM",                "USUBJID": usubjid_val,                "IDVAR": "USUBJID",                "IDVARVAL": usubjid_val,                "QNAM": f"RACE{i}",                "QLABEL": f"Race {i}",                "QVAL": RACE_MAP.get(ans),                "QORIG": "CRF",                "QEVAL": None,            }        )if supp_rows:    suppdm = pl.DataFrame(        supp_rows,        schema={            "STUDYID": pl.String,            "RDOMAIN": pl.String,            "USUBJID": pl.String,            "IDVAR": pl.String,            "IDVARVAL": pl.String,            "QNAM": pl.String,            "QLABEL": pl.String,            "QVAL": pl.String,            "QORIG": pl.String,            "QEVAL": pl.String,        },    ).sort(["USUBJID", "QNAM"])else:    suppdm = pl.DataFrame(        [],        schema={            "STUDYID": pl.String,            "RDOMAIN": pl.String,            "USUBJID": pl.String,            "IDVAR": pl.String,            "IDVARVAL": pl.String,            "QNAM": pl.String,            "QLABEL": pl.String,            "QVAL": pl.String,            "QORIG": pl.String,            "QEVAL": pl.String,        },    )Path("/app/output").mkdir(exist_ok=True)dm.write_csv("/app/output/dm.csv")suppdm.write_csv("/app/output/suppdm.csv")

solutions/sdtm-dm-race-ethnicity/result.sas

Edit
47 lines
/* opensas reference solution for the yamaa benchmark sdtm-dm-race-ethnicity.   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 sql;create table subjects as select distinct StudyOID as STUDYID,SubjectKey as USUBJID from odm;create table races as select distinct StudyOID as STUDYID,SubjectKey as USUBJID,Value from odm where ItemOID='IT.DM.RACE' and not missing(Value);quit;data mapped; set races; length QVAL $1024; if Value in ('White','Asian','Black or African American','American Indian or Alaska Native','Native Hawaiian or Other Pacific Islander') then QVAL=upcase(Value);else if Value='Other, specify: Fijian' then QVAL='OTHER'; else if Value='Subject refused' then QVAL='UNKNOWN'; else if Value='Not reported' then QVAL='NOT REPORTED'; run;proc sql; create table racecounts as select STUDYID,USUBJID,count(*) as NRACE from mapped group by STUDYID,USUBJID; quit;proc sort data=odm out=ordered; by StudyOID SubjectKey; run;data ethnicity;  length ETHNIC $1024;  retain ETHNIC;  set ordered;  by StudyOID SubjectKey;  if first.SubjectKey then do;    ETHNIC='';  end;    if ItemOID='IT.DM.ETHNIC' then ETHNIC=Value;  if last.SubjectKey then output;run;data ethnic; set ethnicity; length STUDYID USUBJID $1024; STUDYID=StudyOID; USUBJID=SubjectKey;if ETHNIC in ('Hispanic or Latino','Not Hispanic or Latino','Not reported','Unknown') then ETHNIC=upcase(ETHNIC); else ETHNIC=''; run;proc sql;create table dmjoined as select a.*,b.NRACE,c.QVAL,d.ETHNIC from subjects a left join racecounts b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID left join mapped c on a.STUDYID=c.STUDYID and a.USUBJID=c.USUBJID and b.NRACE=1 left join ethnic d on a.STUDYID=d.STUDYID and a.USUBJID=d.USUBJID;create table multirace as select a.* from mapped a inner join racecounts b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID where b.NRACE>1;quit;data dmout; set dmjoined; length DOMAIN $2 SUBJID RACE $1024; DOMAIN='DM'; SUBJID=USUBJID; RACE=QVAL; if NRACE>1 then RACE='MULTIPLE'; keep DOMAIN STUDYID USUBJID SUBJID RACE ETHNIC; run;proc sort data=multirace; by STUDYID USUBJID Value; run;data suppout; set multirace; by STUDYID USUBJID; length RDOMAIN $2 IDVAR IDVARVAL QNAM QLABEL QORIG QEVAL $1024; retain N;if first.USUBJID then N=0; N+1; RDOMAIN='DM'; IDVAR='USUBJID'; IDVARVAL=USUBJID; QNAM=cats('RACE',put(N,best32.)); QLABEL=catx(' ','Race',strip(put(N,best32.))); QORIG='CRF'; QEVAL=''; run;/* KEEP drops variables but does not set their export order. */proc sql;create table dmexport as select DOMAIN,STUDYID,USUBJID,SUBJID,RACE,ETHNIC from dmout;create table suppdmout as select STUDYID,RDOMAIN,USUBJID,IDVAR,IDVARVAL,QNAM,QLABEL,QVAL,QORIG,QEVAL from suppout;quit;proc export data=dmexport outfile='/app/output/dm.csv' dbms=csv replace; run;proc export data=suppdmout outfile='/app/output/suppdm.csv' dbms=csv replace; run;