hccinfhir 0.1.5__tar.gz → 0.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/PKG-INFO +91 -2
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/README.md +90 -1
- hccinfhir-0.1.7/hccinfhir/data/hcc_is_chronic.csv +876 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/datamodels.py +41 -1
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/extractor_837.py +2 -5
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/extractor_fhir.py +2 -2
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/hccinfhir.py +74 -23
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/model_calculate.py +44 -28
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/model_coefficients.py +11 -7
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/model_demographics.py +62 -12
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/model_interactions.py +34 -11
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/pyproject.toml +1 -1
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/.gitignore +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/LICENSE +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/__init__.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/__init__.py +0 -0
- /hccinfhir-0.1.5/hccinfhir/data/hcc_is_chronic.csv → /hccinfhir-0.1.7/hccinfhir/data/hcc_is_chronic_without_esrd_model.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_coefficients_2025.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_coefficients_2026.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_dx_to_cc_2025.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_dx_to_cc_2026.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_eligible_cpt_hcpcs_2023.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_eligible_cpt_hcpcs_2024.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_eligible_cpt_hcpcs_2025.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_eligible_cpt_hcpcs_2026.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_hierarchies_2025.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/data/ra_hierarchies_2026.csv +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/extractor.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/filter.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/model_dx_to_cc.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/model_hierarchies.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/__init__.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_0.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_1.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_10.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_11.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_12.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_2.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_3.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_4.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_5.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_6.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_7.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_8.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_837_9.txt +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_eob_1.json +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_eob_2.json +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_eob_200.ndjson +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/sample_files/sample_eob_3.json +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/samples.py +0 -0
- {hccinfhir-0.1.5 → hccinfhir-0.1.7}/hccinfhir/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: hccinfhir
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: HCC Algorithm for FHIR Resources
|
|
5
5
|
Project-URL: Homepage, https://github.com/mimilabs/hccinfhir
|
|
6
6
|
Project-URL: Issues, https://github.com/mimilabs/hccinfhir/issues
|
|
@@ -535,6 +535,89 @@ export_data = result.model_dump(
|
|
|
535
535
|
)
|
|
536
536
|
```
|
|
537
537
|
|
|
538
|
+
### Overriding Demographic Categorization
|
|
539
|
+
|
|
540
|
+
**Problem**: Sometimes demographic data has quality issues (e.g., ESRD patients with incorrect `orec`/`crec` codes), leading to wrong risk score calculations.
|
|
541
|
+
|
|
542
|
+
**Solution**: Use the `prefix_override` parameter to manually specify the coefficient prefix.
|
|
543
|
+
|
|
544
|
+
#### Common Use Case: ESRD Patients with Incorrect OREC/CREC
|
|
545
|
+
|
|
546
|
+
```python
|
|
547
|
+
from hccinfhir import HCCInFHIR, Demographics
|
|
548
|
+
|
|
549
|
+
# ESRD dialysis patient, but source data has wrong orec/crec codes
|
|
550
|
+
processor = HCCInFHIR(model_name="CMS-HCC ESRD Model V24")
|
|
551
|
+
|
|
552
|
+
demographics = Demographics(
|
|
553
|
+
age=65,
|
|
554
|
+
sex="F",
|
|
555
|
+
orec="0", # Should be '2' or '3' for ESRD, but data is incorrect
|
|
556
|
+
crec="0" # Should be '2' or '3' for ESRD, but data is incorrect
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
diagnosis_codes = ["N18.6", "E11.22", "I12.0"] # ESRD + diabetes + hypertensive CKD
|
|
560
|
+
|
|
561
|
+
# Force ESRD dialysis coefficients despite incorrect orec/crec
|
|
562
|
+
result = processor.calculate_from_diagnosis(
|
|
563
|
+
diagnosis_codes,
|
|
564
|
+
demographics,
|
|
565
|
+
prefix_override='DI_' # DI_ = ESRD Dialysis
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
print(f"Risk Score with override: {result.risk_score}")
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
#### Other Common Scenarios
|
|
572
|
+
|
|
573
|
+
```python
|
|
574
|
+
# Long-term institutionalized patient not properly flagged
|
|
575
|
+
processor = HCCInFHIR(model_name="CMS-HCC Model V28")
|
|
576
|
+
demographics = Demographics(age=78, sex="M")
|
|
577
|
+
diagnosis_codes = ["F03.90", "I48.91", "N18.4"]
|
|
578
|
+
|
|
579
|
+
result = processor.calculate_from_diagnosis(
|
|
580
|
+
diagnosis_codes,
|
|
581
|
+
demographics,
|
|
582
|
+
prefix_override='INS_' # INS_ = Institutionalized
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
# New enrollee with missing flag
|
|
586
|
+
result = processor.calculate_from_diagnosis(
|
|
587
|
+
diagnosis_codes,
|
|
588
|
+
demographics,
|
|
589
|
+
prefix_override='NE_' # NE_ = New Enrollee
|
|
590
|
+
)
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
#### Common Prefix Values
|
|
594
|
+
|
|
595
|
+
**CMS-HCC Models (V22, V24, V28):**
|
|
596
|
+
- `CNA_` - Community, Non-Dual, Aged (65+)
|
|
597
|
+
- `CND_` - Community, Non-Dual, Disabled (<65)
|
|
598
|
+
- `CFA_` - Community, Full Benefit Dual, Aged
|
|
599
|
+
- `CFD_` - Community, Full Benefit Dual, Disabled
|
|
600
|
+
- `CPA_` - Community, Partial Benefit Dual, Aged
|
|
601
|
+
- `CPD_` - Community, Partial Benefit Dual, Disabled
|
|
602
|
+
- `INS_` - Long-Term Institutionalized
|
|
603
|
+
- `NE_` - New Enrollee
|
|
604
|
+
- `SNPNE_` - Special Needs Plan New Enrollee
|
|
605
|
+
|
|
606
|
+
**ESRD Models (V21, V24):**
|
|
607
|
+
- `DI_` - Dialysis (standard)
|
|
608
|
+
- `DNE_` - Dialysis New Enrollee
|
|
609
|
+
- `GI_` - Graft, Institutionalized
|
|
610
|
+
- `GNE_` - Graft, New Enrollee
|
|
611
|
+
- `GFPA_`, `GFPN_`, `GNPA_`, `GNPN_` - Graft with various dual/age combinations
|
|
612
|
+
|
|
613
|
+
**RxHCC Model (V08):**
|
|
614
|
+
- `Rx_CE_LowAged_` - Community, Low Income, Aged
|
|
615
|
+
- `Rx_CE_NoLowAged_` - Community, Not Low Income, Aged
|
|
616
|
+
- `Rx_NE_Lo_` - New Enrollee, Low Income
|
|
617
|
+
- `Rx_CE_LTI_` - Community, Long-Term Institutionalized
|
|
618
|
+
|
|
619
|
+
See [CLAUDE.md](./CLAUDE.md#coefficient-prefix-reference) for complete prefix reference.
|
|
620
|
+
|
|
538
621
|
### Custom Filtering Rules
|
|
539
622
|
|
|
540
623
|
```python
|
|
@@ -544,7 +627,7 @@ from hccinfhir.filter import apply_filter
|
|
|
544
627
|
filtered_data = apply_filter(
|
|
545
628
|
service_data,
|
|
546
629
|
include_inpatient=True,
|
|
547
|
-
include_outpatient=True,
|
|
630
|
+
include_outpatient=True,
|
|
548
631
|
eligible_cpt_hcpcs_file="custom_procedures.csv"
|
|
549
632
|
)
|
|
550
633
|
```
|
|
@@ -665,6 +748,12 @@ FROM mimi_ws_1.cmspayment.ra_eligible_cpt_hcpcs
|
|
|
665
748
|
WHERE is_included = 'yes' AND YEAR(mimi_src_file_date) = 2025;
|
|
666
749
|
```
|
|
667
750
|
|
|
751
|
+
`hcc_is_chronic.csv`
|
|
752
|
+
```sql
|
|
753
|
+
SELECT hcc, is_chronic, model_version, model_domain
|
|
754
|
+
FROM cmspayment.ra_report_to_congress
|
|
755
|
+
WHERE mimi_src_file_name = '2024riskadjustmentinma-rtc.pdf'
|
|
756
|
+
```
|
|
668
757
|
|
|
669
758
|
## 🧪 Testing
|
|
670
759
|
|
|
@@ -521,6 +521,89 @@ export_data = result.model_dump(
|
|
|
521
521
|
)
|
|
522
522
|
```
|
|
523
523
|
|
|
524
|
+
### Overriding Demographic Categorization
|
|
525
|
+
|
|
526
|
+
**Problem**: Sometimes demographic data has quality issues (e.g., ESRD patients with incorrect `orec`/`crec` codes), leading to wrong risk score calculations.
|
|
527
|
+
|
|
528
|
+
**Solution**: Use the `prefix_override` parameter to manually specify the coefficient prefix.
|
|
529
|
+
|
|
530
|
+
#### Common Use Case: ESRD Patients with Incorrect OREC/CREC
|
|
531
|
+
|
|
532
|
+
```python
|
|
533
|
+
from hccinfhir import HCCInFHIR, Demographics
|
|
534
|
+
|
|
535
|
+
# ESRD dialysis patient, but source data has wrong orec/crec codes
|
|
536
|
+
processor = HCCInFHIR(model_name="CMS-HCC ESRD Model V24")
|
|
537
|
+
|
|
538
|
+
demographics = Demographics(
|
|
539
|
+
age=65,
|
|
540
|
+
sex="F",
|
|
541
|
+
orec="0", # Should be '2' or '3' for ESRD, but data is incorrect
|
|
542
|
+
crec="0" # Should be '2' or '3' for ESRD, but data is incorrect
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
diagnosis_codes = ["N18.6", "E11.22", "I12.0"] # ESRD + diabetes + hypertensive CKD
|
|
546
|
+
|
|
547
|
+
# Force ESRD dialysis coefficients despite incorrect orec/crec
|
|
548
|
+
result = processor.calculate_from_diagnosis(
|
|
549
|
+
diagnosis_codes,
|
|
550
|
+
demographics,
|
|
551
|
+
prefix_override='DI_' # DI_ = ESRD Dialysis
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
print(f"Risk Score with override: {result.risk_score}")
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
#### Other Common Scenarios
|
|
558
|
+
|
|
559
|
+
```python
|
|
560
|
+
# Long-term institutionalized patient not properly flagged
|
|
561
|
+
processor = HCCInFHIR(model_name="CMS-HCC Model V28")
|
|
562
|
+
demographics = Demographics(age=78, sex="M")
|
|
563
|
+
diagnosis_codes = ["F03.90", "I48.91", "N18.4"]
|
|
564
|
+
|
|
565
|
+
result = processor.calculate_from_diagnosis(
|
|
566
|
+
diagnosis_codes,
|
|
567
|
+
demographics,
|
|
568
|
+
prefix_override='INS_' # INS_ = Institutionalized
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
# New enrollee with missing flag
|
|
572
|
+
result = processor.calculate_from_diagnosis(
|
|
573
|
+
diagnosis_codes,
|
|
574
|
+
demographics,
|
|
575
|
+
prefix_override='NE_' # NE_ = New Enrollee
|
|
576
|
+
)
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
#### Common Prefix Values
|
|
580
|
+
|
|
581
|
+
**CMS-HCC Models (V22, V24, V28):**
|
|
582
|
+
- `CNA_` - Community, Non-Dual, Aged (65+)
|
|
583
|
+
- `CND_` - Community, Non-Dual, Disabled (<65)
|
|
584
|
+
- `CFA_` - Community, Full Benefit Dual, Aged
|
|
585
|
+
- `CFD_` - Community, Full Benefit Dual, Disabled
|
|
586
|
+
- `CPA_` - Community, Partial Benefit Dual, Aged
|
|
587
|
+
- `CPD_` - Community, Partial Benefit Dual, Disabled
|
|
588
|
+
- `INS_` - Long-Term Institutionalized
|
|
589
|
+
- `NE_` - New Enrollee
|
|
590
|
+
- `SNPNE_` - Special Needs Plan New Enrollee
|
|
591
|
+
|
|
592
|
+
**ESRD Models (V21, V24):**
|
|
593
|
+
- `DI_` - Dialysis (standard)
|
|
594
|
+
- `DNE_` - Dialysis New Enrollee
|
|
595
|
+
- `GI_` - Graft, Institutionalized
|
|
596
|
+
- `GNE_` - Graft, New Enrollee
|
|
597
|
+
- `GFPA_`, `GFPN_`, `GNPA_`, `GNPN_` - Graft with various dual/age combinations
|
|
598
|
+
|
|
599
|
+
**RxHCC Model (V08):**
|
|
600
|
+
- `Rx_CE_LowAged_` - Community, Low Income, Aged
|
|
601
|
+
- `Rx_CE_NoLowAged_` - Community, Not Low Income, Aged
|
|
602
|
+
- `Rx_NE_Lo_` - New Enrollee, Low Income
|
|
603
|
+
- `Rx_CE_LTI_` - Community, Long-Term Institutionalized
|
|
604
|
+
|
|
605
|
+
See [CLAUDE.md](./CLAUDE.md#coefficient-prefix-reference) for complete prefix reference.
|
|
606
|
+
|
|
524
607
|
### Custom Filtering Rules
|
|
525
608
|
|
|
526
609
|
```python
|
|
@@ -530,7 +613,7 @@ from hccinfhir.filter import apply_filter
|
|
|
530
613
|
filtered_data = apply_filter(
|
|
531
614
|
service_data,
|
|
532
615
|
include_inpatient=True,
|
|
533
|
-
include_outpatient=True,
|
|
616
|
+
include_outpatient=True,
|
|
534
617
|
eligible_cpt_hcpcs_file="custom_procedures.csv"
|
|
535
618
|
)
|
|
536
619
|
```
|
|
@@ -651,6 +734,12 @@ FROM mimi_ws_1.cmspayment.ra_eligible_cpt_hcpcs
|
|
|
651
734
|
WHERE is_included = 'yes' AND YEAR(mimi_src_file_date) = 2025;
|
|
652
735
|
```
|
|
653
736
|
|
|
737
|
+
`hcc_is_chronic.csv`
|
|
738
|
+
```sql
|
|
739
|
+
SELECT hcc, is_chronic, model_version, model_domain
|
|
740
|
+
FROM cmspayment.ra_report_to_congress
|
|
741
|
+
WHERE mimi_src_file_name = '2024riskadjustmentinma-rtc.pdf'
|
|
742
|
+
```
|
|
654
743
|
|
|
655
744
|
## 🧪 Testing
|
|
656
745
|
|