Review ask

As a clinical trial statistician or programmer, answer three short questions in Your review: the task, the inputs and outputs, and the AI-assisted review. Agreeing with all three approves this benchmark; disagreeing with any needs a comment. Propose a fix with the Edit button on any source file, or add it to your comments.

We suggest spending no more than 5 minutes on a review. The other tabs beside Your review are background for assessment, not under review.

Summary

Lifecycle: draftEditUnder review
What this benchmark means
README.md

Public entries: Python and R. Passing coverage requires an installed inventory.

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

Human review and assessment

Your review

3 questions and your comments · View benchmark 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.72026-10-20yamaa docs buildRead a specification in the 1.0 surface as its 0.5 counterpart; state that missing values stay missing where a mapping declares no missing handler, and leave out a declared missing answer that restates a handler's default
1.62026-10-17yamaa docs buildDescribe collected date parts written as ISO 8601 date text and times of day counted in seconds since midnight
1.52026-10-17yamaa docs buildName collected precision in words instead of letter codes; state imputation fallbacks, minimum source precision, bounds ignored outside the collected period, and invalid text with no handler as an error; describe date and datetime shifts, imputation flag codes, and partial text giving no date part
1.42026-10-15yamaa docs buildState datetime precision codes through the hour and minute, and complete only the time parts a collected datetime lacks
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
33 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.

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

DOMAIN is "DM" and RDOMAIN is "DM". STUDYID is the ODM study OID and USUBJID is the ODM subject key, each as given. SUBJID is the same value as USUBJID. A race marked twice counts once. RACE is "MULTIPLE" when a subject marked several distinct races. When a subject marked one race, RACE is "WHITE" for "White", "ASIAN" for "Asian", "BLACK OR AFRICAN AMERICAN" for "Black or African American", and "AMERICAN INDIAN OR ALASKA NATIVE" for "American Indian or Alaska Native". RACE is "OTHER" for "Other, specify: Fijian", "NOT REPORTED" for "Not reported", and "UNKNOWN" for "Subject refused". RACE has no value when no race was marked or the one marked answer is not one of the answers above. ETHNIC is "HISPANIC OR LATINO" for "Hispanic or Latino", "NOT HISPANIC OR LATINO" for "Not Hispanic or Latino", "NOT REPORTED" for "Not reported", and "UNKNOWN" for "Unknown". ETHNIC has no value when no ethnicity was collected or the collected answer is not one of the answers above. SUPPDM holds one record for each distinct race a subject marked, for exactly the subjects whose RACE is "MULTIPLE". IDVAR is "USUBJID" and IDVARVAL is the subject's USUBJID. A subject's records are numbered in alphabetical order of the collected answer: QNAM is "RACE1", "RACE2", and so on, and QLABEL is "Race 1", "Race 2", and so on. QVAL is that race in controlled terms, as in RACE. QORIG is "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
19 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.

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

DOMAIN is "DM" and RDOMAIN is "DM". Each collected race answer gives the same name in upper case, except that "Other, specify: Fijian" gives "OTHER" and "Subject refused" gives "UNKNOWN"; RACE also has no value. Each collected ethnicity answer gives the same name in upper case; ETHNIC also has no value. IDVAR is "USUBJID". QNAM is "RACE1", "RACE2", and so on, and QLABEL is "Race 1", "Race 2", and so on. QORIG is "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/brief.md

Edit
11 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.

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

Public calls generated from benchmark.yaml; results must match the expected output

R

Edit
4 lines
library(yamaa)yamaa_spec("spec_dm.yaml")$run()$save()yamaa_spec("spec_suppdm.yaml")$run()$output

Python

Edit
4 lines
import yamaayamaa.spec("spec_dm.yaml").run().save()yamaa.spec("spec_suppdm.yaml").run().output

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
121 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."""Build DM and SUPPDM from the ODM extract.Reads /app/input/odm.csv (long format: one row per collected item value)and writes /app/output/dm.csv (one record per subject) and/app/output/suppdm.csv (one record per distinct race marked, forsubjects whose RACE is "MULTIPLE")."""import csvfrom collections import OrderedDictINPUT_DIR = "/app/input"OUTPUT_DIR = "/app/output"RACE_MAP = {    "White": "WHITE",    "Asian": "ASIAN",    "Black or African American": "BLACK OR AFRICAN AMERICAN",    "American Indian or Alaska Native": "AMERICAN INDIAN OR ALASKA NATIVE",    "Other, specify: Fijian": "OTHER",    "Not reported": "NOT REPORTED",    "Subject refused": "UNKNOWN",}ETHNIC_MAP = {    "Hispanic or Latino": "HISPANIC OR LATINO",    "Not Hispanic or Latino": "NOT HISPANIC OR LATINO",    "Not reported": "NOT REPORTED",    "Unknown": "UNKNOWN",}DM_COLUMNS = ["DOMAIN", "STUDYID", "USUBJID", "SUBJID", "RACE", "ETHNIC"]SUPPDM_COLUMNS = [    "STUDYID",    "RDOMAIN",    "USUBJID",    "IDVAR",    "IDVARVAL",    "QNAM",    "QLABEL",    "QVAL",    "QORIG",    "QEVAL",]def main():    with open(f"{INPUT_DIR}/odm.csv", newline="", encoding="utf-8") as f:        rows = list(csv.DictReader(f))    # Collect, per subject, every marked race answer and the ethnicity    # answer, keeping subjects in order of first appearance.    subjects = OrderedDict()    for row in rows:        key = (row["StudyOID"], row["SubjectKey"])        entry = subjects.setdefault(key, {"races": [], "ethnic": ""})        if row["ItemOID"] == "IT.DM.RACE":            if row["Value"]:                entry["races"].append(row["Value"])        elif row["ItemOID"] == "IT.DM.ETHNIC":            entry["ethnic"] = row["Value"]    dm_rows = []    suppdm_rows = []    for (studyid, usubjid), entry in subjects.items():        distinct_races = sorted(set(entry["races"]))        if len(distinct_races) > 1:            race = "MULTIPLE"        elif len(distinct_races) == 1:            race = RACE_MAP.get(distinct_races[0], "")        else:            race = ""        ethnic = ETHNIC_MAP.get(entry["ethnic"], "") if entry["ethnic"] else ""        dm_rows.append(            {                "DOMAIN": "DM",                "STUDYID": studyid,                "USUBJID": usubjid,                "SUBJID": usubjid,                "RACE": race,                "ETHNIC": ethnic,            }        )        if race == "MULTIPLE":            for i, answer in enumerate(distinct_races, start=1):                suppdm_rows.append(                    {                        "STUDYID": studyid,                        "RDOMAIN": "DM",                        "USUBJID": usubjid,                        "IDVAR": "USUBJID",                        "IDVARVAL": usubjid,                        "QNAM": f"RACE{i}",                        "QLABEL": f"Race {i}",                        "QVAL": RACE_MAP.get(answer, ""),                        "QORIG": "CRF",                        "QEVAL": "",                    }                )    with open(f"{OUTPUT_DIR}/dm.csv", "w", newline="", encoding="utf-8") as f:        writer = csv.DictWriter(f, fieldnames=DM_COLUMNS)        writer.writeheader()        writer.writerows(dm_rows)    with open(f"{OUTPUT_DIR}/suppdm.csv", "w", newline="", encoding="utf-8") as f:        writer = csv.DictWriter(f, fieldnames=SUPPDM_COLUMNS)        writer.writeheader()        writer.writerows(suppdm_rows)if __name__ == "__main__":    main()

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;