Skip to main content

High-performance MS-DRG (Medicare Severity Diagnosis Related Groups) grouper

Project description

mz-drg

High-performance CMS claim processing tools written in Zig with Python bindings.

License: MIT Zig Python Docs


mz-drg provides open-source reimplementations of two CMS tools:

  • MS-DRG Grouper — assigns Diagnosis Related Groups based on diagnoses, procedures, and demographics
  • Medicare Code Editor (MCE) — validates ICD diagnosis and procedure codes against CMS edit rules

Both are written in Zig, callable from Python, and validated against the CMS reference Java implementations with a 100% match rate on 50,000+ claims.

Why mz-drg?

The official CMS tools are Java applications. While accurate, they come with practical limitations:

Java (CMS) mz-drg
Startup JVM warmup, seconds Instant
Throughput (Ryzen 5 5600U) ~500 claims/sec ~7,000+ claims/sec
Memory JVM heap overhead Minimal, memory-mapped data
Dependencies JRE 17+, classpath management Single shared library
Python integration JPype bridge (fragile) Native ctypes (simple)
Embedding Requires JVM process C ABI, any language

Both engines are ported line-by-line from the decompiled Java source and validated claim-by-claim against the original.

Quick start

Install

pip install msdrg

MS-DRG Grouper

import msdrg

with msdrg.MsdrgGrouper() as grouper:
    result = grouper.group({
        "version": 431,
        "age": 65,
        "sex": 0,
        "discharge_status": 1,
        "pdx": {"code": "I5020"},
        "sdx": [{"code": "E1165"}],
        "procedures": []
    })

print(result["final_drg"])            # 293
print(result["final_mdc"])            # 5
print(result["final_drg_description"])  # "Heart Failure and Shock without CC/MCC"

Medicare Code Editor

import msdrg

with msdrg.MceEditor() as mce:
    result = mce.edit({
        "discharge_date": 20250101,
        "age": 65,
        "sex": 0,
        "discharge_status": 1,
        "pdx": {"code": "I5020"},
        "sdx": [{"code": "E1165"}],
        "procedures": []
    })

print(result["edit_type"])  # "NONE"
print(result["edits"])      # [] — no edits triggered

Unified claim — same dict for both

import msdrg

claim = {
    "version": 431,
    "discharge_date": 20250101,
    "age": 65, "sex": 0, "discharge_status": 1,
    "pdx": {"code": "I5020"},
    "sdx": [{"code": "E1165"}],
    "procedures": []
}

with msdrg.MsdrgGrouper() as g, msdrg.MceEditor() as mce:
    drg = g.group(claim)
    mce_result = mce.edit(claim)

MS-DRG Grouper

Input format

{
    "version": 431,              # MS-DRG version (e.g. 400, 410, 421, 431)
    "age": 65,                   # Patient age in years
    "sex": 0,                    # 0=Male, 1=Female, 2=Unknown
    "discharge_status": 1,       # 1=Home/Self Care, 20=Died
    "hospital_status": "NOT_EXEMPT",  # "NOT_EXEMPT" (default), "EXEMPT", or "UNKNOWN"
    "pdx": {                     # Principal diagnosis (required)
        "code": "I5020",
        "poa": "Y"               # Present on Admission: Y/N/U/W (optional)
    },
    "admit_dx": {                # Admission diagnosis (optional)
        "code": "R0602"
    },
    "sdx": [                     # Secondary diagnoses (optional)
        {"code": "E1165", "poa": "Y"},
        {"code": "I10", "poa": "Y"}
    ],
    "procedures": [              # Procedure codes (optional)
        {"code": "02703DZ"}
    ]
}

Hospital status

The hospital_status field controls how Hospital-Acquired Condition (HAC) processing is applied, per CMS rules:

Value Behavior
"NOT_EXEMPT" Standard HAC processing. Default.
"EXEMPT" Hospital is exempt from POA reporting. No HAC/POA ungroupable conditions.
"UNKNOWN" Stricter POA validation with specific ungroupable return codes.

Output format

{
    "initial_drg": 293,
    "final_drg": 293,
    "initial_mdc": 5,
    "final_mdc": 5,
    "initial_drg_description": "Heart Failure and Shock without CC/MCC",
    "final_drg_description": "Heart Failure and Shock without CC/MCC",
    "initial_mdc_description": "Diseases and Disorders of the Circulatory System",
    "final_mdc_description": "Diseases and Disorders of the Circulatory System",
    "return_code": "OK",
    "pdx_output": {
        "code": "I5020",
        "mdc": 5,
        "severity": "CC",
        "drg_impact": "BOTH",
        "poa_error": "POA_NOT_CHECKED",
        "flags": ["VALID", "MARKED_FOR_INITIAL", "MARKED_FOR_FINAL"]
    },
    "sdx_output": [...],
    "proc_output": [...]
}

Supported DRG versions

Version CMS Fiscal Year
400 FY 2023 (Oct 2022 – Apr 2023)
401 FY 2023 (Apr 2023 – Sep 2023)
410 FY 2024 (Oct 2023 – Apr 2024)
411 FY 2024 (Apr 2024 – Sep 2024)
420 FY 2025 (Oct 2024 – Apr 2025)
421 FY 2025 (Apr 2025 – Sep 2025)
430 FY 2026 (Oct 2025 – Apr 2026)
431 FY 2026 (Apr 2026 – Sep 2026)

Medicare Code Editor (MCE)

The MCE validates ICD diagnosis and procedure codes against CMS edit rules. It checks for sex conflicts, age conflicts, unacceptable principal diagnoses, E-codes as PDX, non-covered procedures, bilateral procedures, and more.

Input format

{
    "discharge_date": 20250101,  # YYYYMMDD integer (required for MCE)
    "icd_version": 10,           # 9 or 10 (default: 10)
    "age": 65,
    "sex": 0,                    # 0=Male, 1=Female, 2=Unknown
    "discharge_status": 1,
    "pdx": {"code": "I5020"},
    "admit_dx": {"code": "R0602"},
    "sdx": [{"code": "E1165"}],
    "procedures": [{"code": "02703DZ"}]
}

Output format

{
    "version": 20260930,
    "edit_type": "PREPAYMENT",    # NONE, PREPAYMENT, POSTPAYMENT, or BOTH
    "edits": [                    # List of triggered edits (empty if NONE)
        {
            "name": "E_CODE_AS_PDX",
            "count": 1,
            "code_type": "DIAGNOSIS",
            "edit_type": "PREPAYMENT"
        }
    ]
}

Example — E-code as principal diagnosis

import msdrg

with msdrg.MceEditor() as mce:
    result = mce.edit({
        "discharge_date": 20250101,
        "age": 65, "sex": 0, "discharge_status": 1,
        "pdx": {"code": "V0001XA"},  # E-code
        "sdx": [], "procedures": []
    })

print(result["edit_type"])  # "PREPAYMENT"
print(result["edits"][0]["name"])  # "E_CODE_AS_PDX"

Supported edit types

The MCE detects ~35 edit types including:

  • INVALID_CODE — code not in CMS master for date range
  • SEX_CONFLICT — code restricted by patient sex
  • AGE_CONFLICT — code restricted by patient age
  • E_CODE_AS_PDX — E-code used as principal diagnosis
  • MANIFESTATION_AS_PDX — manifestation code used as PDX
  • UNACCEPTABLE_PDX — code unacceptable as principal diagnosis
  • NON_COVERED — procedure not covered by Medicare
  • BILATERAL — bilateral procedure without bilateral PDX
  • OPEN_BIOPSY — open biopsy without prior biopsy

MCE validation

The MCE implementation is validated against the CMS Java MCE 2.0 v43.1 with a 100% match rate on 50l,000 test claims.

Architecture

┌──────────────────────────────────────────────────────┐
│  Python (msdrg)                                      │
│  ctypes ──► C API (c_api.zig, mce_c_api.zig)        │
│                │                                     │
│    ┌───────────┴───────────┐                         │
│    ▼                       ▼                         │
│  MS-DRG Grouper         MCE Editor                  │
│  (GrouperChain)         (MceComponent)              │
│    │                       │                         │
│    ▼                       ▼                         │
│  Chain of Links:        Validation Pipeline:        │
│  Preprocess → Group     Code Check → Edit Rules     │
│  → HAC → Final DRG      → Output Counts            │
│    │                       │                         │
│    ▼                       ▼                         │
│  Memory-mapped .bin files (22 total)                │
└──────────────────────────────────────────────────────┘

Both engines share the same shared library and data files. The grouping pipeline is a chain of composable processors; the MCE is a linear validation pipeline. Both mirror the original Java architecture for validation purposes.

Building from source

Prerequisites

  • Zig 0.16+download or via package manager
  • Python 3.11+
  • uv (recommended) or pip

Setup

git clone https://github.com/Bedrock-Billing/mz-drg.git
cd mz-drg

# Create venv and install
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

This compiles the Zig shared library and bundles all data files into the Python package.

Run tests

# Zig unit tests (60+ tests)
cd zig_src && zig build test

# Python tests (MS-DRG + MCE)
python -m pytest tests/

Data pipeline

The binary data files (data/bin/*.bin) are prebuilt and included in the repository. To regenerate them from the raw CMS CSVs:

bash scripts/setup_data.sh

This runs extract → import → compile → zig build in sequence. See scripts/ for individual steps.

Comparison testing

The tests/ directory contains tools for validating mz-drg against the reference Java implementations.

# Generate random test claims
python tests/generate_test_claims.py --count 1000 --out tests/claims.json

# Compare MS-DRG grouper
python tests/compare_groupers.py --file tests/claims.json

# Compare MCE editor
python tests/compare_mce.py --file tests/claims.json

# Benchmark
python tests/compare_groupers.py --file tests/claims.json --benchmark

The Java comparisons require JDK 17+ and the reference JARs in jars/. This is only needed for validation — the Python package itself has no Java dependency.

C API

mz-drg exposes a C ABI for integration with any language.

MS-DRG Grouper

void* ctx = msdrg_context_init("/path/to/data/bin");
const char* result = msdrg_group_json(ctx, "{\"version\":431,...}");
msdrg_string_free(result);
msdrg_context_free(ctx);

MCE Editor

void* mce = mce_context_init("/path/to/data/bin");
const char* result = mce_edit_json(mce, "{\"discharge_date\":20250101,...}");
msdrg_string_free(result);
mce_context_free(mce);

Functions are thread-safe after initialization. The context is immutable and can be shared across threads.

Project structure

mz-drg/
├── msdrg/                       # Python package
│   ├── __init__.py
│   ├── grouper.py               # MsdrgGrouper class
│   └── mce.py                   # MceEditor class
├── zig_src/                     # Zig source
│   ├── build.zig
│   ├── main.zig
│   └── src/
│       ├── c_api.zig            # MS-DRG C ABI exports
│       ├── json_api.zig         # MS-DRG JSON in/out
│       ├── msdrg.zig            # GrouperChain + version routing
│       ├── chain.zig            # Composable processor chain
│       ├── models.zig           # Data models
│       ├── preprocess.zig       # Exclusion & attribute handling
│       ├── grouping.zig         # DRG formula matching
│       ├── marking.zig          # Code marking logic
│       ├── hac.zig              # Hospital-Acquired Conditions
│       ├── mce.zig              # MCE main editor
│       ├── mce_c_api.zig        # MCE C ABI exports
│       ├── mce_json_api.zig     # MCE JSON in/out
│       ├── mce_data.zig         # MCE data loading
│       ├── mce_enums.zig        # MCE attributes & edits
│       ├── mce_editing.zig      # MCE edit rules
│       └── mce_validation.zig   # MCE validation logic
├── data/bin/                    # Prebuilt binary data (22 files)
├── scripts/                     # Data extraction & compilation
├── tests/                       # Comparison & benchmark tools
├── pyproject.toml
└── setup.py

License

MIT — see LICENSE.

Documentation

Full documentation is available at Bedrock-Billing.github.io/mz-drg.

Acknowledgments

This project is intended for healthcare IT professionals who need fast, embeddable, and auditable claim processing tools.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

msdrg-0.1.4.tar.gz (1.6 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

msdrg-0.1.4-py3-none-win_amd64.whl (1.9 MB view details)

Uploaded Python 3Windows x86-64

msdrg-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

msdrg-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

msdrg-0.1.4-py3-none-macosx_11_0_arm64.whl (1.8 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

msdrg-0.1.4-py3-none-macosx_10_13_x86_64.whl (1.8 MB view details)

Uploaded Python 3macOS 10.13+ x86-64

File details

Details for the file msdrg-0.1.4.tar.gz.

File metadata

  • Download URL: msdrg-0.1.4.tar.gz
  • Upload date:
  • Size: 1.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for msdrg-0.1.4.tar.gz
Algorithm Hash digest
SHA256 501d6a060a6ad08564f1d4923131d0f696dd044afb5a1a067de1d03231d63fae
MD5 8186b66d1b9d99292fcc6450a30eb0d7
BLAKE2b-256 86cac376115af9836f427444c396dd5c11ac420043f535bf8ecee7e3a6b1c1ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for msdrg-0.1.4.tar.gz:

Publisher: build.yml on Bedrock-Billing/mz-drg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file msdrg-0.1.4-py3-none-win_amd64.whl.

File metadata

  • Download URL: msdrg-0.1.4-py3-none-win_amd64.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for msdrg-0.1.4-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 76fe9cb8ec8e7cdf1faf2cb8bec76de9ea517fe42a51d3e4bbd31b6ab7bcfb1e
MD5 f929e30a942b16c2f639f13e9e1d4691
BLAKE2b-256 d3347680e914e0969765fd97db57bfa78dfe75d2bc7de4c3b766ed09f6374a4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for msdrg-0.1.4-py3-none-win_amd64.whl:

Publisher: build.yml on Bedrock-Billing/mz-drg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file msdrg-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for msdrg-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0d633bf1dd3cef5f8881bf6ce25138f05ce3de8aaf8531642a869e29e3c86ee2
MD5 cc035cf1301899688b56dadf24b3230d
BLAKE2b-256 31a690106147a31b376acf1c07d5980e396462e0e792add89bc501bdbce5aad1

See more details on using hashes here.

Provenance

The following attestation bundles were made for msdrg-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: build.yml on Bedrock-Billing/mz-drg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file msdrg-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for msdrg-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 a262650a14540c95094c74f3c9ba2d683822479d237535a9da6e2e66cee8788a
MD5 b6e5983ca8bda440962b1e10fe9f3100
BLAKE2b-256 aeb1305745d07e2b2fcec0400116ba4ee1bf8c6ff9c292f9d706b3694ec1a1c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for msdrg-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: build.yml on Bedrock-Billing/mz-drg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file msdrg-0.1.4-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: msdrg-0.1.4-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for msdrg-0.1.4-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 603d1cd11e9bdcd05071cb5661e0573056cf2f4f775680ea3a3a696468a4ec45
MD5 2f0a649ec20d0f81d065366fa54db0bf
BLAKE2b-256 90d250c56e5c68910d7849d6c0451ceebb74ce59880dfefac0fba6af47d542aa

See more details on using hashes here.

Provenance

The following attestation bundles were made for msdrg-0.1.4-py3-none-macosx_11_0_arm64.whl:

Publisher: build.yml on Bedrock-Billing/mz-drg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file msdrg-0.1.4-py3-none-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for msdrg-0.1.4-py3-none-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 e41ccac26dafd30fea763e201c06eb923fac05941d529cc5d36205804d6b9cbc
MD5 19aee10409195c3dcf40b986ab99f576
BLAKE2b-256 27759f565f593e11aa0b8734d166d47fc21230ca59f00c05b7415a40746e6f1f

See more details on using hashes here.

Provenance

The following attestation bundles were made for msdrg-0.1.4-py3-none-macosx_10_13_x86_64.whl:

Publisher: build.yml on Bedrock-Billing/mz-drg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page