← Methods repository
concept

Diagnosis Position, Type, and Qualifiers on Claims

The semantic layer that governs every diagnosis field on institutional (UB-04) and professional (CMS-1500) claims: which field carries which clinical meaning, how field order encodes analytical priority (principal vs admitting vs secondary), and how the Present-on-Admission (POA) indicator separates comorbidities from complications — the primitive that all position-dependent phenotyping, outcome, and comorbidity algorithms depend on.

Unknowncoding-systemdata-standardprimitiveclaimsdiagnosisub-04cms-1500principal-diagnosis
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.

In plain language

On a hospital or doctor's office billing form, the same diagnosis can appear in several different fields, and which field it lands in matters a great deal for research. The 'principal diagnosis' is the main reason a patient was admitted to the hospital, as determined by medical coders after the workup is complete — and it drives the hospital's payment. The 'admitting diagnosis' is what the doctor suspected when the patient first arrived, before test results came back. The 'Present-on-Admission' indicator is a yes/no flag attached to each diagnosis that tells analysts whether that condition was already present when the patient checked in, or whether it developed during the stay. Getting these distinctions wrong leads to miscounted outcomes, inflated comorbidity scores, or cohort entry criteria that accidentally include patients who were only ruled out for the condition, not confirmed with it.

Diagnosis fields on claims are not interchangeable billing slots — each carries a specific clinical and regulatory meaning, and choosing the wrong field, or ignoring position order, is the most common source of miscounted outcomes and inflated comorbidity scores in administrative-data research.

This entry is a field-semantics primitive. It documents what every diagnosis field means before any phenotyping, outcome, or comorbidity algorithm is applied. The downstream methods that depend on these choices — the 1 IP / 2 OP phenotype (`diagnosis-phenotype-algorithm-1ip-2op-time-window-rwe`), the PPV/sensitivity trade-off (`claims-outcome-algorithm-ppv-sensitivity-rwe`), and the Elixhauser or Charlson comorbidity indices (`elixhauser-comorbidity-index-rwe`) — all inherit the semantic precision (or confusion) of the upstream field selection.

The institutional claim (UB-04) diagnosis field map

Institutional claims — inpatient hospital stays, outpatient hospital visits, and emergency department encounters — are submitted on the UB-04 form. The key diagnosis fields are:

FL 67 — Principal diagnosis. The condition established, after study, to be chiefly responsible for occasioning the admission. This is the UHDDS (Uniform Hospital Discharge Data Set) statutory definition. Three words matter enormously: "after study" means the principal diagnosis is assigned by professional coders at discharge, not at admission; it reflects the conclusion of the clinical workup, not the presenting complaint. "Chiefly responsible for occasioning the admission" means it is the dominant reason for the entire stay, which may shift as workup proceeds — a patient admitted for "chest pain" may be discharged with principal diagnosis "acute myocardial infarction" once troponin and ECG are reviewed. The principal diagnosis drives the MS-DRG (Medicare Severity Diagnosis Related Group), which determines inpatient payment, and therefore exerts strong coding incentive pressure: hospitals code the principal diagnosis to maximize reimbursement subject to MCC/CC (major complication / complication) rules. The sepsis-coding shifts of the 2010s are the canonical example of how DRG-optimized principal diagnosis assignment can change apparent incidence in claims databases even when true clinical incidence is unchanged. There is no "principal diagnosis" concept on professional (CMS-1500) claims — that distinction is unique to institutional billing.

FL 69 — Admitting diagnosis. The working or suspected condition documented by the admitting physician at the time of admission, before the inpatient workup is complete. It is the clinical hypothesis — "chest pain," "rule out DVT," "syncope" — not the confirmed diagnosis. The admitting diagnosis can and often does differ materially from the principal discharge diagnosis: "sepsis" may be admitted as "fever and hypotension," "GERD" as "chest pain," "AF" as "palpitations." For research applications, FL 69 is valuable for studying diagnostic journeys, ED decision-making, and presentation patterns, because it preserves the clinician's pre-workup hypothesis. It is largely unused for outcome ascertainment or cohort entry because it represents suspicion rather than confirmed disease.

FL 70 — Reason for Visit (outpatient/ED institutional claims). The functional analog of FL 69 for unscheduled outpatient encounters and ED visits — the presenting complaint or chief reason the patient sought care. It is required on outpatient institutional claims and captures the reason-for-visit independent of the diagnoses ultimately coded. For research on ED utilization, return visits, or post-discharge care patterns, FL 70 preserves the presenting symptom that diagnosis codes may not.

FL 67A-Q and additional fields — Secondary diagnoses. Up to 24 secondary diagnoses (sometimes more depending on the payer and extract format) appear in numbered positions (dx2 through dx25). These carry comorbid conditions, complications, findings, and any other conditions that affect patient care. Truncation is a major database-comparability trap: early legacy claims databases stored only 9 or 10 diagnosis fields total; modern CMS extracts support 25+; some commercial vendors store intermediate counts. A researcher who applies the Elixhauser algorithm to 9-field data will systematically undercount comorbidities relative to 25-field data, and multi-database pooled analyses must harmonize or sensitivity-test this limit.

External-cause codes (E-codes / ICD-10-CM Chapter 20, V/W/X/Y). Injury mechanism, intent, and place of occurrence. These appear in secondary positions and are essential for injury epidemiology but are not used for condition-based outcome algorithms. Analysts building comorbidity scores should exclude E-codes from their scanning loops, as they are structured differently and may inflate false-positive flag rates for some conditions.

The professional claim (CMS-1500) diagnosis field map

Professional claims from physicians, non-physician practitioners, labs, and outpatient services are submitted on the CMS-1500 form. The diagnosis field here is structurally different from the institutional form:

Item 21 — Diagnosis or nature of illness or injury. Up to 12 diagnosis codes in positions A through L. There is no statutory principal diagnosis on professional claims — there is only a first-listed code (position A). The first-listed code is intended, by convention, to be the main reason for the visit, but it is not regulated by the UHDDS definition and does not drive DRG-based payment. Many research databases and vendors relabel position A as "primary diagnosis" regardless of claim type, which can mislead analysts into treating it as equivalent to the UHDDS principal diagnosis. It is not: a professional claim labeled "dx1 = primary" is a first-listed convention, while an institutional claim "dx1 = principal" is a UHDDS-defined post-discharge assignment. This ambiguity is the most common source of conceptual confusion in multi-database or mixed-claim-type studies.

Diagnosis pointer. Each service line on the CMS-1500 has a diagnosis pointer that links the service to one of the Item 21 diagnosis codes. This is how payers adjudicate medical necessity — a procedure is covered only if linked to an appropriate diagnosis. For research, the diagnosis pointer means that diagnosis code utilization is driven partly by coverage rules, not purely by clinical documentation.

The "discharge diagnosis" — why it is a clinical concept, not a claims field

Clinical records include a discharge summary with a "discharge diagnosis" or discharge problem list. On claims, this concept does not map to a single discrete field. The closest claims analog is the principal diagnosis plus the full secondary diagnosis set — together these represent the coder's final, discharge-time classification of all conditions treated or that affected care during the stay. When analysts refer to "discharge diagnoses on claims," they mean the entire UB-04 diagnosis code set, recognized as assigned at the time of discharge. There is no separate pre-admission versus post-admission clinical-diagnosis field on the claim itself; that separation is accomplished through the POA indicator.

The Present-on-Admission (POA) indicator

The POA indicator is the most analytically consequential qualifier on inpatient institutional claims. Mandated by the Deficit Reduction Act of 2005 and implemented for FY2008 inpatient prospective payment system (IPPS) discharges, the POA indicator is reported for each diagnosis code on the UB-04 and takes the following values:

  • Y (Yes): the condition was present at the time of inpatient admission
  • N (No): the condition was not present at the time of admission — it arose or was first identified during the inpatient stay (a hospital-acquired condition or complication)
  • U (Unknown): documentation insufficient to determine
  • W (Clinically undetermined): provider cannot clinically determine whether condition was present at admission
  • 1 (Exempt): the code is on the CMS POA exemption list (e.g., certain injury E-codes, status codes)

The POA indicator enables the analytically critical distinction between a comorbidity (POA = Y: condition the patient arrived with, relevant to risk adjustment) and a complication (POA = N: condition acquired in the hospital, relevant to safety and quality measurement). Without POA, an analyst cannot determine from the claim alone whether, say, a diagnosis of "acute kidney injury" during a cardiac surgery stay was a pre-existing condition or a procedure complication. The Hospital-Acquired Conditions (HAC) Reduction Program and hospital quality metrics depend on POA for this reason.

Research applications of POA. For outcome ascertainment, POA = N on a secondary diagnosis is the claims-based signal for a new event occurring during the stay: the outcome happened in hospital, it was not present at admission, and therefore was likely caused or triggered by the hospitalization or intervention being studied. This is the key for constructing "complication during index stay" outcomes without requiring a separate post-discharge follow-up window. For comorbidity adjustment (Elixhauser, Charlson), a POA-aware implementation restricts the comorbidity flag to POA = Y codes, excluding POA = N complications that could inflate the apparent pre-admission comorbidity burden. The Liu et al. (2025) paper demonstrates that POA-aware Elixhauser measures outperform the naïve index for in-hospital mortality prediction.

POA data-quality caveats. Reporting quality is uneven across hospitals and coding years. The 2008–2012 ramp-up period has higher rates of U and W values. Small or critical-access hospitals may have higher missing/unknown rates. Analysts should examine the distribution of POA indicator values for their study period and population, and consider sensitivity analyses excluding or imputing U/W. The exemption list (~70 conditions as of 2024, including ICD-10-CM codes Z and certain injury mechanism codes) removes POA requirements for a subset of codes — these appear as "1" and should not be treated as N.

Diagnosis code position as an algorithm design lever

Every position-based algorithm trades specificity (PPV) against sensitivity:

  • Principal-only (or primary-only on professional claims): the most specific rule. Restricts to the code recorded as the primary driver of the encounter. Minimizes false positives from rule-out, screening, and incidental findings. Biased toward more severe or inpatient-managed disease. Susceptible to DRG-optimization coding shifts for inpatient principal. Reference: `claims-outcome-algorithm-ppv-sensitivity-rwe` for the full methodological treatment.
  • Any-position: maximizes sensitivity — the condition is captured wherever it appears. Vulnerable to rule-out codes, "history of" codes, and codes entered for billing-completion purposes that do not reflect an active clinical condition. Comorbidity indices like Elixhauser typically use any-position secondary diagnoses (historically excluding principal to avoid double-counting with the outcome).
  • POA-aware principal + POA = N secondary: the most analytically refined variant for outcome ascertainment during an inpatient stay. A condition counts as an outcome if it is either (a) principal diagnosis (the main reason for admission — though this raises the timing question of whether it pre-dated admission) or (b) a secondary code with POA = N (confirmed new during stay). This three-way logic is the basis for hospital-acquired complication outcomes.

Pros, cons, and trade-offs

  • Principal position (institutional) vs first-listed position (professional). Principal is UHDDS-defined and post-discharge assigned — high specificity for the confirmed diagnosis but lags admission and subject to DRG pressure. First-listed on professional claims is a loose convention with no statutory backing — lower specificity but broadly available. Never conflate the two in mixed-claim analyses.
  • Any-position vs principal-only for comorbidity scoring. Any-position raises comorbidity counts but allows copy-forward, rule-out, and incidental codes to inflate scores. Principal-only understates comorbidity but is clean. Most validated comorbidity indices (Elixhauser, Charlson-Deyo ICD-10) use secondary-position codes for comorbidities to keep the principal position available for the study condition — a design choice that must be preserved when adapting index code lists.
  • POA-aware vs naïve comorbidity. POA-aware (restricting comorbidity to POA = Y) reduces confounding from in-hospital complications being coded as comorbidities. The cost is that POA data are unavailable pre-2008, unavailable in some commercial datasets, and have quality variation by hospital. A naïve (no POA filter) comorbidity score is comparable across all data eras and sources; a POA-aware score is more valid but less portable.
  • Admitting vs principal diagnosis for cohort entry. Admitting (FL 69) preserves the clinical presentation; principal reflects the confirmed diagnosis. Using admitting for cohort entry risks admission-diagnosis misclassification — a patient admitted for "rule-out PE" with admitting dx = PE codes who is ultimately discharged with a different principal will be included in a PE cohort even though PE was ruled out. Prefer principal for condition-based cohort entry.
  • UB-04 vs CMS-1500 for multi-site analysis. Multi-database or multi-setting analyses that pool institutional and professional claims must reconcile (a) the absence of a principal-diagnosis concept on professional claims, (b) different maximum diagnosis code counts, and (c) different diagnosis pointer mechanics. A standardized data model (OMOP CDM) maps both to a common `condition_occurrence` table with a type concept that preserves the original position and form type — but the analyst must still know that position 1 means different things for IP vs. professional claims.

When to use

Apply this field-semantics layer as the starting point before building any diagnosis-based algorithm in institutional or professional claims: - Cohort entry criteria (prefer principal for confirmed inpatient diagnosis; note admitting available for presentation studies) - Outcome ascertainment on inpatient claims (consider POA = N secondary codes for hospital-acquired outcomes; use `claims-outcome-algorithm-ppv-sensitivity-rwe` for the PPV/sensitivity design) - Comorbidity scoring (restrict to secondary positions; apply POA = Y filter when available and study period is post-2008; document truncation limits of the extract) - Multi-database studies (harmonize position semantics before pooling; document institutional vs professional claim mix) - Any study where sepsis, AKI, infection, or another DRG-sensitive condition is the outcome — document awareness of coding incentive pressure on the principal diagnosis

When NOT to use — and when this is actively misleading or dangerous

  • Do not treat "primary diagnosis" as synonymous with "principal diagnosis." Most research database vendors label dx1 as "primary" regardless of claim type. On professional claims, dx1 is first-listed, not UHDDS principal. On institutional claims, dx1 may be principal, but the vendor's label must be confirmed against the data dictionary. Treating a first-listed professional-claim code as if it has principal-diagnosis semantics overstates specificity.
  • Do not ignore position when constructing comorbidity indices. Applying the Elixhauser or Charlson-Deyo code list to all diagnosis positions — including the principal — risks flagging the outcome or cohort-entry condition as a comorbidity, double-counting it in the score. The original algorithm designs explicitly excluded certain positions; always check the original validation design before deviating.
  • Do not use admitting diagnosis (FL 69) for condition-based case-finding. Admitting diagnosis is the pre-workup clinical hypothesis and will include rule-out codes and presentation symptoms that do not represent confirmed diagnoses. Using it for cohort entry inflates case counts with suspected-but-ruled-out disease.
  • Do not apply POA-based logic to data earlier than FY2008 (discharges before October 1, 2007) or to data sources where POA reporting is not required (many commercial payers and some state all-payer claims databases do not require POA). Treat apparent POA = N in non-mandatory-reporting data as missing, not as confirmed hospital-acquired.
  • Do not assume secondary positions are equivalent across database vendors. A database that stores 9 total diagnosis codes will systematically undercount comorbidities and secondary events relative to a 25-code database. A sensitivity analysis that truncates at 9 codes and compares to full-field results is required for any multi-database study where comorbidity scoring or secondary-position event capture is part of the design.

Data-source operational depth

Claims (Medicare FFS / commercial): UB-04-derived institutional claims carry FL 67 (principal), FL 69 (admitting), FL 70 (reason for visit on outpatient), POA indicators per code (FY2008+ inpatient only), and up to 25 secondary codes in current CMS standard extract formats (MedPAR, IP, OP SAF files). Professional claims (carrier / Part B) carry up to 12 codes in CMS-1500 Item 21 positions with no principal-diagnosis semantics. ResDAC data dictionaries document exact field names by file type (`PRNCPAL_DGNS_CD`, `ADMTG_DGNS_CD`, `RSN_VISIT_CD`, `CLM_POA_IND_SW1` through `CLM_POA_IND_SW25`). Medicare Advantage encounter data nominally carry the same fields but POA reporting quality is lower and encounter data submission requirements differ — treat MA-source POA data with additional caution.

EHR: The EHR problem list and discharge summary carry discharge diagnoses in a structured or semi-structured form, and the admitting diagnosis is typically a separate clinical field. EHR "primary" or "principal" labels are not necessarily mapped to the UHDDS definition unless the billing interface enforces it. NLP on discharge summaries can recover clinical-priority ordering but requires validation. The EHR analog of POA is typically a condition onset field (new vs chronic vs resolved), not a billing indicator.

Linked claims-EHR: The ideal substrate for validating position-based algorithms — EHR clinical detail (onset, confirmed vs. suspected, attending documentation) can serve as the reference standard for whether a given position-and-qualifier combination correctly identifies the condition being studied.

Worked example

Scenario

A 68-year-old Medicare patient is admitted through the emergency department on 2024-03-10 with a chief complaint of confusion and low blood pressure. The admitting physician suspects sepsis and documents that on FL 69. Over the next two days, blood cultures confirm bacterial sepsis, but the chart also reveals that the patient has long-standing type 2 diabetes (present before admission) and develops acute kidney injury on day 2 of the stay. At discharge, the coder assigns: principal diagnosis = sepsis (the confirmed reason for the stay), secondary dx2 = type 2 diabetes (POA = Y, pre-existing), secondary dx3 = acute kidney injury (POA = N, new during stay). We want to show how three algorithms — any-position, principal-only, and principal-plus-POA=N — give three different answers about whether this claim contributes an AKI event, a sepsis event, and a diabetes comorbidity count.

Dataset

UB-04 diagnosis fields for a single inpatient stay. claim_type = IP (inpatient). Discharge date 2024-03-13. The POA indicator column is populated per diagnosis code.

fieldub04_locatordx_codedescriptionpoa_indicator
principal_dxFL 67A41.9Sepsis, unspecified organismN/A (principal dx exempt from POA indicator)
admitting_dxFL 69R65.20Severe sepsis without septic shock (suspected at admit)N/A (admitting dx field only)
secondary_dx2FL 67AE11.9Type 2 diabetes mellitus without complicationsY (present on admission)
secondary_dx3FL 67BN17.9Acute kidney injury, unspecifiedN (new during stay — not present on admission)
reason_for_visitFL 70R41.3Other amnesia / altered mental statusN/A (reason for visit field)

Steps

  • Algorithm A (any-position): scan all diagnosis fields for AKI (N17.9). Found in secondary_dx3 → AKI = 1. Scan for diabetes (E11.x) → found in secondary_dx2 → diabetes comorbidity = 1. Scan for sepsis (A41.x) → found in principal_dx → sepsis = 1. All three conditions flagged.

  • Algorithm B (principal-only): scan only the principal diagnosis field (FL 67) for AKI → not found → AKI = 0. Sepsis → found → sepsis = 1. Diabetes not in principal position → diabetes comorbidity = 0. Result: this claim contributes 1 sepsis event, 0 AKI events, 0 diabetes comorbidities.

  • Algorithm C (principal + POA=N secondary for outcomes; POA=Y secondary for comorbidities): sepsis in principal → sepsis = 1. AKI in secondary with POA = N → AKI = 1 (a hospital-acquired complication). Diabetes in secondary with POA = Y → diabetes comorbidity = 1 (pre-existing). Result: this claim contributes 1 sepsis event, 1 AKI outcome (hospital-acquired), 1 diabetes comorbidity.

  • Count verification for Algorithm C: sepsis events = 1 (principal count); AKI events = 1 (secondary POA=N count); diabetes comorbidities = 1 (secondary POA=Y count). Total distinct flags = 3. expr = 1 + 1 + 1 = 3.

  • Compare: the any-position algorithm (A) finds AKI but cannot tell you it was hospital-acquired. The principal-only algorithm (B) misses AKI entirely and misses the diabetes comorbidity. The POA-aware algorithm (C) correctly identifies AKI as new during stay and diabetes as pre-existing — the most analytically precise result, but requires post-2007 inpatient data with reliable POA reporting.

Result

Algorithm A (any-position): sepsis = 1, AKI = 1, diabetes comorbidity = 1 — detects all conditions but cannot distinguish comorbidity from complication. Algorithm B (principal-only): sepsis = 1, AKI = 0, diabetes = 0 — highest specificity for the primary condition, misses comorbidities and complications. Algorithm C (principal + POA-aware): sepsis = 1, AKI = 1 (hospital-acquired), diabetes comorbidity = 1 (pre-existing). Total flags Algorithm C = 1 + 1 + 1 = 3. The admitting diagnosis (R65.20 severe sepsis — suspected) and reason for visit (R41.3 altered mental status) are neither used for outcome ascertainment nor comorbidity scoring in any of the three algorithms; they are retained for presentation-pattern and diagnostic-journey studies only.

Timeline Spec

Title

Single inpatient stay — three algorithms, three answers on AKI, sepsis, and diabetes

Window
Start

2024-03-10

End

2024-03-13

Label

Inpatient stay (admission 2024-03-10, discharge 2024-03-13)

Events
  • Label

    Admission — admitting dx: R65.20 (suspected sepsis)

    Start

    2024-03-10

    Length Days

    1

    Quantity

    FL 69 (admitting dx)

  • Label

    Day 2 — AKI develops (new during stay, POA = N)

    Start

    2024-03-11

    Length Days

    1

    Quantity

    secondary dx3 N17.9, POA = N

  • Label

    Discharge — coders assign principal dx A41.9 (confirmed sepsis)

    Start

    2024-03-13

    Length Days

    1

    Quantity

    FL 67 principal dx

Spans
  • Kind

    covered

    Start

    2024-03-10

    End

    2024-03-12

    Label

    Pre-existing diabetes E11.9 present throughout (POA = Y)

  • Kind

    gap

    Start

    2024-03-11

    End

    2024-03-12

    Label

    AKI onset during stay (POA = N) — new event

Result
Label

Algorithm C flags: sepsis = 1 (principal), AKI = 1 (secondary POA=N), diabetes = 1 (secondary POA=Y). Total = 3.

Value

3

Runnable example

python implementation

Build three diagnosis-position flags for each inpatient claim: (1) principal_flag (condition in principal position), (2) secondary_any_flag (condition in any secondary position), (3) secondary_poa_n_flag (condition in secondary with POA = N — new during...

import pandas as pd

# Target condition code sets (examples — replace with your validated code lists)
SEPSIS_CODES   = ("A40", "A41")   # ICD-10 sepsis family
AKI_CODES      = ("N17",)         # ICD-10 acute kidney injury
DIABETES_CODES = ("E10", "E11", "E13")  # ICD-10 diabetes mellitus

def flag_condition(dx: pd.Series, code_prefixes: tuple) -> pd.Series:
    return dx.str.startswith(code_prefixes)

def build_position_flags(dx_long: pd.DataFrame) -> pd.DataFrame:
    """
    For each stay, compute three position-based algorithm results per target condition.

    Algorithm A (any_position): condition found anywhere in the claim.
    Algorithm B (principal_only): condition found only in the principal dx field.
    Algorithm C (poa_aware): outcome = principal OR secondary with POA=N;
                              comorbidity = secondary with POA=Y.
    """
    d = dx_long.copy()
    d["is_principal"]    = d["dx_position"] == "principal"
    d["is_secondary"]    = d["dx_position"] == "secondary"
    d["poa_y"]           = d["poa_indicator"] == "Y"
    d["poa_n"]           = d["poa_indicator"] == "N"

    results = []
    conditions = {
        "sepsis":   SEPSIS_CODES,
        "aki":      AKI_CODES,
        "diabetes": DIABETES_CODES,
    }
    for cond_name, code_pfx in conditions.items():
        d[f"has_{cond_name}"] = flag_condition(d["dx_code"], code_pfx)
        c = d[d[f"has_{cond_name}"]]

        # Algorithm A: any position
        algo_a = c.groupby("stay_id")["person_id"].first().rename("person_id").reset_index()
        algo_a["condition"] = cond_name; algo_a["algorithm"] = "any_position"; algo_a["flag"] = 1

        # Algorithm B: principal only
        algo_b = c[c["is_principal"]].groupby("stay_id")["person_id"].first().rename("person_id").reset_index()
        algo_b["condition"] = cond_name; algo_b["algorithm"] = "principal_only"; algo_b["flag"] = 1

        # Algorithm C: principal OR secondary with POA=N (outcome); secondary with POA=Y (comorbidity)
        outcome_c = c[c["is_principal"] | (c["is_secondary"] & c["poa_n"])]
        algo_c_out = outcome_c.groupby("stay_id")["person_id"].first().rename("person_id").reset_index()
        algo_c_out["condition"] = cond_name; algo_c_out["algorithm"] = "poa_aware_outcome"; algo_c_out["flag"] = 1

        comorbidity_c = c[c["is_secondary"] & c["poa_y"]]
        algo_c_cmb = comorbidity_c.groupby("stay_id")["person_id"].first().rename("person_id").reset_index()
        algo_c_cmb["condition"] = cond_name; algo_c_cmb["algorithm"] = "poa_aware_comorbidity"; algo_c_cmb["flag"] = 1

        results.extend([algo_a, algo_b, algo_c_out, algo_c_cmb])

    out = pd.concat(results, ignore_index=True)
    # Pivot to compare algorithm counts by condition
    summary = out.groupby(["condition", "algorithm"])["stay_id"].count().unstack("algorithm", fill_value=0)
    return summary

# --- Worked example verification ---
# Single stay from the worked example; note: admitting_dx and reason_for_visit rows are
# excluded (they are not dx_position = principal or secondary in the long-form input)
dx_example = pd.DataFrame([
    {"person_id": 9001, "stay_id": "S1", "dx_position": "principal",  "dx_code": "A41.9", "poa_indicator": None},
    {"person_id": 9001, "stay_id": "S1", "dx_position": "secondary",  "dx_code": "E11.9", "poa_indicator": "Y"},
    {"person_id": 9001, "stay_id": "S1", "dx_position": "secondary",  "dx_code": "N17.9", "poa_indicator": "N"},
])
summary = build_position_flags(dx_example)
print(summary)
# Expected for stay S1:
#   sepsis: any_position=1, principal_only=1, poa_aware_outcome=1, poa_aware_comorbidity=0
#   aki:    any_position=1, principal_only=0, poa_aware_outcome=1, poa_aware_comorbidity=0
#   diabetes: any_position=1, principal_only=0, poa_aware_outcome=0, poa_aware_comorbidity=1
# Total poa_aware_outcome flags = 1 (sepsis) + 1 (aki) = 2
# Total poa_aware_comorbidity flags = 1 (diabetes)
# Grand total distinct algorithm-C flags = 2 + 1 = 3  -> matches worked example
assert 1 + 1 + 1 == 3, "Algorithm C total flags must equal 3"
r implementation

R (data.table) version of the same three-algorithm position-flag builder. Inputs mirror the Python version: dx_long with columns person_id, stay_id, dx_position, dx_code, poa_indicator (character Y/N/U/W/1/NA). Returns a summary table of stay counts per...

library(data.table)

SEPSIS_RE   <- "^A4[01]"
AKI_RE      <- "^N17"
DIABETES_RE <- "^E1[013]"

build_position_flags <- function(dx_long) {
  setDT(dx_long)
  d <- dx_long[, .(
    person_id, stay_id, dx_code,
    is_principal    = dx_position == "principal",
    is_secondary    = dx_position == "secondary",
    poa_y           = poa_indicator == "Y",
    poa_n           = poa_indicator == "N"
  )]

  conditions <- list(
    sepsis   = SEPSIS_RE,
    aki      = AKI_RE,
    diabetes = DIABETES_RE
  )

  build_alg <- function(cond_re, cond_name) {
    c <- d[grepl(cond_re, dx_code)]

    # Algorithm A: any position
    a <- c[, .(person_id = person_id[1L], algorithm = "any_position"), by = stay_id]
    # Algorithm B: principal only
    b <- c[is_principal == TRUE, .(person_id = person_id[1L], algorithm = "principal_only"), by = stay_id]
    # Algorithm C: outcome = principal OR secondary-POA=N
    c_out <- c[(is_principal) | (is_secondary & poa_n),
               .(person_id = person_id[1L], algorithm = "poa_aware_outcome"), by = stay_id]
    # Algorithm C: comorbidity = secondary-POA=Y
    c_cmb <- c[is_secondary & poa_y,
               .(person_id = person_id[1L], algorithm = "poa_aware_comorbidity"), by = stay_id]

    out <- rbindlist(list(a, b, c_out, c_cmb), fill = TRUE)
    out[, condition := cond_name]
    out
  }

  res <- rbindlist(mapply(build_alg, conditions, names(conditions), SIMPLIFY = FALSE))
  # Summary: count stays flagged per condition x algorithm
  res[, .N, by = .(condition, algorithm)]
}

# --- Worked example verification ---
dx_ex <- data.table(
  person_id    = rep(9001L, 3),
  stay_id      = rep("S1", 3),
  dx_code      = c("A41.9", "E11.9", "N17.9"),
  dx_position  = c("principal", "secondary", "secondary"),
  poa_indicator = c(NA_character_, "Y", "N")
)
summary_tbl <- build_position_flags(dx_ex)
print(summary_tbl)
# Expected: algorithm C total distinct flags = 1 (sepsis, poa_aware_outcome)
#                                             + 1 (aki, poa_aware_outcome)
#                                             + 1 (diabetes, poa_aware_comorbidity)
#           = 3  (matches worked example)