hccinfhir 0.0.3__py3-none-any.whl → 0.0.5__py3-none-any.whl
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/data/ra_coefficients_2025.csv +6352 -0
- hccinfhir/data/ra_dx_to_cc_2025.csv +53952 -0
- hccinfhir/data/ra_eligible_cpt_hcpcs_2024.csv +6697 -0
- hccinfhir/data/ra_eligible_cpt_hcpcs_2025.csv +6725 -0
- hccinfhir/data/ra_hierarchies_2025.csv +487 -0
- hccinfhir/datamodels.py +101 -0
- hccinfhir/extractor.py +3 -3
- hccinfhir/extractor_837.py +1 -2
- hccinfhir/extractor_fhir.py +1 -1
- hccinfhir/filter.py +3 -5
- hccinfhir/hccinfhir.py +149 -0
- hccinfhir/model_calculate.py +95 -0
- hccinfhir/model_coefficients.py +143 -0
- hccinfhir/model_demographics.py +191 -0
- hccinfhir/model_dx_to_cc.py +54 -0
- hccinfhir/model_hierarchies.py +70 -0
- hccinfhir/model_interactions.py +342 -0
- hccinfhir/samples/__init__.py +2 -0
- hccinfhir/utils.py +51 -0
- {hccinfhir-0.0.3.dist-info → hccinfhir-0.0.5.dist-info}/METADATA +147 -9
- hccinfhir-0.0.5.dist-info/RECORD +42 -0
- hccinfhir/models.py +0 -44
- hccinfhir-0.0.3.dist-info/RECORD +0 -28
- /hccinfhir/{data → samples}/sample_837_0.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_1.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_10.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_11.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_2.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_3.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_4.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_5.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_6.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_7.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_8.txt +0 -0
- /hccinfhir/{data → samples}/sample_837_9.txt +0 -0
- /hccinfhir/{data → samples}/sample_eob_1.json +0 -0
- /hccinfhir/{data → samples}/sample_eob_2.json +0 -0
- /hccinfhir/{data → samples}/sample_eob_200.ndjson +0 -0
- /hccinfhir/{data → samples}/sample_eob_3.json +0 -0
- {hccinfhir-0.0.3.dist-info → hccinfhir-0.0.5.dist-info}/WHEEL +0 -0
- {hccinfhir-0.0.3.dist-info → hccinfhir-0.0.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import Dict, Set, Tuple
|
|
2
|
+
import importlib.resources
|
|
3
|
+
from hccinfhir.datamodels import ModelName
|
|
4
|
+
|
|
5
|
+
# Load default mappings from csv file
|
|
6
|
+
hierarchies_file_default = 'ra_hierarchies_2025.csv'
|
|
7
|
+
hierarchies_default: Dict[Tuple[str, ModelName], Set[str]] = {} # (diagnosis_code, model_name) -> {cc}
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
with importlib.resources.open_text('hccinfhir.data', hierarchies_file_default) as f:
|
|
11
|
+
for line in f.readlines()[1:]: # Skip header
|
|
12
|
+
try:
|
|
13
|
+
cc_parent, cc_child, model_domain, model_version, _ = line.strip().split(',')
|
|
14
|
+
if model_domain == 'ESRD':
|
|
15
|
+
model_name = f"CMS-HCC {model_domain} Model {model_version}"
|
|
16
|
+
else:
|
|
17
|
+
model_name = f"{model_domain} Model {model_version}"
|
|
18
|
+
key = (cc_parent, model_name)
|
|
19
|
+
if key not in hierarchies_default:
|
|
20
|
+
hierarchies_default[key] = {cc_child}
|
|
21
|
+
else:
|
|
22
|
+
hierarchies_default[key].add(cc_child)
|
|
23
|
+
except ValueError:
|
|
24
|
+
continue # Skip malformed lines
|
|
25
|
+
except Exception as e:
|
|
26
|
+
print(f"Error loading mapping file: {e}")
|
|
27
|
+
hierarchies_default = {}
|
|
28
|
+
|
|
29
|
+
def apply_hierarchies(
|
|
30
|
+
cc_set: Set[str], # Set of active CCs
|
|
31
|
+
model_name: ModelName = "CMS-HCC Model V28",
|
|
32
|
+
hierarchies: Dict[Tuple[str, ModelName], Set[str]] = hierarchies_default
|
|
33
|
+
) -> Set[str]:
|
|
34
|
+
"""
|
|
35
|
+
Apply hierarchical rules to a set of CCs based on model version.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
ccs: Set of current active CCs
|
|
39
|
+
model_name: HCC model name to use for hierarchy rules
|
|
40
|
+
hierarchies: Optional custom hierarchy dictionary
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Set of CCs after applying hierarchies
|
|
44
|
+
"""
|
|
45
|
+
# Track CCs that should be zeroed out
|
|
46
|
+
to_remove = set()
|
|
47
|
+
|
|
48
|
+
# For V28, if none of 221, 222, 224, 225, 226 are present, remove 223
|
|
49
|
+
if model_name == "CMS-HCC Model V28":
|
|
50
|
+
if ("223" in cc_set and
|
|
51
|
+
not any(cc in cc_set for cc in ["221", "222", "224", "225", "226"])):
|
|
52
|
+
cc_set.remove("223")
|
|
53
|
+
elif model_name == "CMS-HCC ESRD Model V21":
|
|
54
|
+
if "134" in cc_set:
|
|
55
|
+
cc_set.remove("134")
|
|
56
|
+
elif model_name == "CMS-HCC ESRD Model V24":
|
|
57
|
+
for cc in ["134", "135", "136", "137"]:
|
|
58
|
+
if cc in cc_set:
|
|
59
|
+
cc_set.remove(cc)
|
|
60
|
+
|
|
61
|
+
# Apply hierarchies
|
|
62
|
+
for cc in cc_set:
|
|
63
|
+
hierarchy_key = (cc, model_name)
|
|
64
|
+
if hierarchy_key in hierarchies:
|
|
65
|
+
# If parent CC exists, remove all child CCs
|
|
66
|
+
child_ccs = hierarchies[hierarchy_key]
|
|
67
|
+
to_remove.update(child_ccs & cc_set)
|
|
68
|
+
|
|
69
|
+
# Return CCs with hierarchical exclusions removed
|
|
70
|
+
return cc_set - to_remove
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
from hccinfhir.datamodels import Demographics, ModelName
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
def has_any_hcc(hcc_list: list[str], hcc_set: set[str]) -> int:
|
|
5
|
+
"""Returns 1 if any HCC in the list is present, 0 otherwise"""
|
|
6
|
+
return int(bool(set(hcc_list) & hcc_set))
|
|
7
|
+
|
|
8
|
+
def create_demographic_interactions(demographics: Demographics) -> dict:
|
|
9
|
+
"""Creates common demographic-based interactions"""
|
|
10
|
+
interactions = {}
|
|
11
|
+
is_female = demographics.category.startswith('F')
|
|
12
|
+
is_male = demographics.category.startswith('M')
|
|
13
|
+
is_aged = not demographics.non_aged
|
|
14
|
+
|
|
15
|
+
# Original Disability interactions
|
|
16
|
+
if is_aged:
|
|
17
|
+
interactions['OriginallyDisabled_Female'] = int(demographics.orig_disabled) * int(is_female)
|
|
18
|
+
interactions['OriginallyDisabled_Male'] = int(demographics.orig_disabled) * int(is_male)
|
|
19
|
+
else:
|
|
20
|
+
interactions['OriginallyDisabled_Female'] = 0
|
|
21
|
+
interactions['OriginallyDisabled_Male'] = 0
|
|
22
|
+
|
|
23
|
+
# LTI interactions - used for ESRD models
|
|
24
|
+
if demographics.lti:
|
|
25
|
+
interactions['LTI_Aged'] = int(is_aged)
|
|
26
|
+
interactions['LTI_NonAged'] = int(not is_aged)
|
|
27
|
+
else:
|
|
28
|
+
interactions['LTI_Aged'] = 0
|
|
29
|
+
interactions['LTI_NonAged'] = 0
|
|
30
|
+
|
|
31
|
+
nemcaid = False
|
|
32
|
+
if demographics.new_enrollee and demographics.dual_elgbl_cd in {'01', '02', '03', '04', '05', '06', '08'}:
|
|
33
|
+
nemcaid = True
|
|
34
|
+
ne_origds = int(demographics.age >= 65 and (demographics.orec is not None and demographics.orec == "1"))
|
|
35
|
+
|
|
36
|
+
# Four mutually exclusive groups
|
|
37
|
+
interactions.update({
|
|
38
|
+
f'NMCAID_NORIGDIS_{demographics.category}': int(not nemcaid and not ne_origds),
|
|
39
|
+
f'MCAID_NORIGDIS_{demographics.category}': int(nemcaid and not ne_origds),
|
|
40
|
+
f'NMCAID_ORIGDIS_{demographics.category}': int(not nemcaid and ne_origds),
|
|
41
|
+
f'MCAID_ORIGDIS_{demographics.category}': int(nemcaid and ne_origds)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
return interactions
|
|
45
|
+
|
|
46
|
+
def create_dual_interactions(demographics: Demographics) -> dict:
|
|
47
|
+
"""Creates dual status interactions"""
|
|
48
|
+
interactions = {}
|
|
49
|
+
is_female = demographics.category.startswith('F')
|
|
50
|
+
is_male = demographics.category.startswith('M')
|
|
51
|
+
is_aged = not demographics.non_aged
|
|
52
|
+
|
|
53
|
+
if demographics.fbd:
|
|
54
|
+
interactions.update({
|
|
55
|
+
'FBDual_Female_Aged': int(is_female) * int(is_aged),
|
|
56
|
+
'FBDual_Female_NonAged': int(is_female) * int(not is_aged),
|
|
57
|
+
'FBDual_Male_Aged': int(is_male) * int(is_aged),
|
|
58
|
+
'FBDual_Male_NonAged': int(is_male) * int(not is_aged)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
if demographics.pbd:
|
|
62
|
+
interactions.update({
|
|
63
|
+
'PBDual_Female_Aged': int(is_female) * int(is_aged),
|
|
64
|
+
'PBDual_Female_NonAged': int(is_female) * int(not is_aged),
|
|
65
|
+
'PBDual_Male_Aged': int(is_male) * int(is_aged),
|
|
66
|
+
'PBDual_Male_NonAged': int(is_male) * int(not is_aged)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
return interactions
|
|
70
|
+
|
|
71
|
+
def create_hcc_counts(hcc_set: set[str]) -> dict:
|
|
72
|
+
"""Creates HCC count variables"""
|
|
73
|
+
counts = {}
|
|
74
|
+
hcc_count = len(hcc_set)
|
|
75
|
+
|
|
76
|
+
for i in range(1, 10):
|
|
77
|
+
counts[f'D{i}'] = int(hcc_count == i)
|
|
78
|
+
counts['D10P'] = int(hcc_count >= 10)
|
|
79
|
+
|
|
80
|
+
return counts
|
|
81
|
+
|
|
82
|
+
def get_diagnostic_categories(model_name: ModelName, hcc_set: set[str]) -> dict:
|
|
83
|
+
"""Creates disease categories based on model version"""
|
|
84
|
+
if model_name == "CMS-HCC Model V28":
|
|
85
|
+
return {
|
|
86
|
+
'CANCER_V28': has_any_hcc(['17', '18', '19', '20', '21', '22', '23'], hcc_set),
|
|
87
|
+
'DIABETES_V28': has_any_hcc(['35', '36', '37', '38'], hcc_set),
|
|
88
|
+
'CARD_RESP_FAIL_V28': has_any_hcc(['211', '212', '213'], hcc_set),
|
|
89
|
+
'HF_V28': has_any_hcc(['221', '222', '223', '224', '225', '226'], hcc_set),
|
|
90
|
+
'CHR_LUNG_V28': has_any_hcc(['276', '277', '278', '279', '280'], hcc_set),
|
|
91
|
+
'KIDNEY_V28': has_any_hcc(['326', '327', '328', '329'], hcc_set),
|
|
92
|
+
'SEPSIS_V28': int('2' in hcc_set),
|
|
93
|
+
'gSubUseDisorder_V28': has_any_hcc(['135', '136', '137', '138', '139'], hcc_set),
|
|
94
|
+
'gPsychiatric_V28': has_any_hcc(['151', '152', '153', '154', '155'], hcc_set),
|
|
95
|
+
'NEURO_V28': has_any_hcc(['180', '181', '182', '190', '191', '192', '195', '196', '198', '199'], hcc_set),
|
|
96
|
+
'ULCER_V28': has_any_hcc(['379', '380', '381', '382'], hcc_set)
|
|
97
|
+
}
|
|
98
|
+
elif model_name == "CMS-HCC Model V24":
|
|
99
|
+
return {
|
|
100
|
+
'CANCER': has_any_hcc(['8', '9', '10', '11', '12'], hcc_set),
|
|
101
|
+
'DIABETES': has_any_hcc(['17', '18', '19'], hcc_set),
|
|
102
|
+
'CARD_RESP_FAIL': has_any_hcc(['82', '83', '84'], hcc_set),
|
|
103
|
+
'CHF': int('85' in hcc_set),
|
|
104
|
+
'gCopdCF': has_any_hcc(['110', '111', '112'], hcc_set),
|
|
105
|
+
'RENAL_V24': has_any_hcc(['134', '135', '136', '137', '138'], hcc_set),
|
|
106
|
+
'SEPSIS': int('2' in hcc_set),
|
|
107
|
+
'gSubstanceUseDisorder_V24': has_any_hcc(['54', '55', '56'], hcc_set),
|
|
108
|
+
'gPsychiatric_V24': has_any_hcc(['57', '58', '59', '60'], hcc_set),
|
|
109
|
+
'PRESSURE_ULCER': has_any_hcc(['157', '158', '159'], hcc_set) # added in 2018-11-20
|
|
110
|
+
}
|
|
111
|
+
elif model_name == "CMS-HCC Model V22":
|
|
112
|
+
return {
|
|
113
|
+
'CANCER': has_any_hcc(['8', '9', '10', '11', '12'], hcc_set),
|
|
114
|
+
'DIABETES': has_any_hcc(['17', '18', '19'], hcc_set),
|
|
115
|
+
'CARD_RESP_FAIL': has_any_hcc(['82', '83', '84'], hcc_set),
|
|
116
|
+
'CHF': int('85' in hcc_set),
|
|
117
|
+
'gCopdCF': has_any_hcc(['110', '111', '112'], hcc_set),
|
|
118
|
+
'RENAL': has_any_hcc(['134', '135', '136', '137'], hcc_set),
|
|
119
|
+
'SEPSIS': int('2' in hcc_set),
|
|
120
|
+
'gSubstanceUseDisorder': has_any_hcc(['54', '55'], hcc_set),
|
|
121
|
+
'gPsychiatric': has_any_hcc(['57', '58'], hcc_set),
|
|
122
|
+
'PRESSURE_ULCER': has_any_hcc(['157', '158'], hcc_set) # added in 2012-10-19
|
|
123
|
+
}
|
|
124
|
+
elif model_name == "CMS-HCC ESRD Model V24":
|
|
125
|
+
return {
|
|
126
|
+
'CANCER': has_any_hcc(['8', '9', '10', '11', '12'], hcc_set),
|
|
127
|
+
'DIABETES': has_any_hcc(['17', '18', '19'], hcc_set),
|
|
128
|
+
'CARD_RESP_FAIL': has_any_hcc(['82', '83', '84'], hcc_set),
|
|
129
|
+
'CHF': int('85' in hcc_set),
|
|
130
|
+
'gCopdCF': has_any_hcc(['110', '111', '112'], hcc_set),
|
|
131
|
+
'RENAL_V24': has_any_hcc(['134', '135', '136', '137', '138'], hcc_set),
|
|
132
|
+
'SEPSIS': int('2' in hcc_set),
|
|
133
|
+
'PRESSURE_ULCER': has_any_hcc(['157', '158', '159', '160'], hcc_set), # added in 2018-11-20
|
|
134
|
+
'gSubstanceUseDisorder_V24': has_any_hcc(['54', '55', '56'], hcc_set),
|
|
135
|
+
'gPsychiatric_V24': has_any_hcc(['57', '58', '59', '60'], hcc_set)
|
|
136
|
+
}
|
|
137
|
+
elif model_name == "CMS-HCC ESRD Model V21":
|
|
138
|
+
return {
|
|
139
|
+
'CANCER': has_any_hcc(['8', '9', '10', '11', '12'], hcc_set),
|
|
140
|
+
'DIABETES': has_any_hcc(['17', '18', '19'], hcc_set),
|
|
141
|
+
'IMMUNE': int('47' in hcc_set),
|
|
142
|
+
'CARD_RESP_FAIL': has_any_hcc(['82', '83', '84'], hcc_set),
|
|
143
|
+
'CHF': int('85' in hcc_set),
|
|
144
|
+
'COPD': has_any_hcc(['110', '111'], hcc_set),
|
|
145
|
+
'RENAL': has_any_hcc(['134', '135', '136', '137', '138', '139', '140', '141'], hcc_set),
|
|
146
|
+
'COMPL': int('176' in hcc_set),
|
|
147
|
+
'SEPSIS': int('2' in hcc_set),
|
|
148
|
+
'PRESSURE_ULCER': has_any_hcc(['157', '158', '159', '160'], hcc_set)
|
|
149
|
+
}
|
|
150
|
+
elif model_name == "RxHCC Model V08":
|
|
151
|
+
# RxModel doesn't seem to have any diagnostic category interactions
|
|
152
|
+
return {}
|
|
153
|
+
return {}
|
|
154
|
+
|
|
155
|
+
def create_disease_interactions(model_name: ModelName,
|
|
156
|
+
diagnostic_cats: dict,
|
|
157
|
+
demographics: Optional[Demographics],
|
|
158
|
+
hcc_set: Optional[set[str]]) -> dict:
|
|
159
|
+
"""Creates disease interaction variables based on model version.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
model_name: The HCC model version being used
|
|
163
|
+
diagnostic_cats: Dictionary of diagnostic categories
|
|
164
|
+
demographics: Optional demographic information for age/sex/disability interactions
|
|
165
|
+
hcc_set: Optional set of HCCs for direct HCC checks
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dictionary containing all disease interaction variables
|
|
169
|
+
"""
|
|
170
|
+
interactions = {}
|
|
171
|
+
|
|
172
|
+
if model_name == "CMS-HCC Model V28":
|
|
173
|
+
# Base V28 disease interactions
|
|
174
|
+
interactions.update({
|
|
175
|
+
'DIABETES_HF_V28': diagnostic_cats['DIABETES_V28'] * diagnostic_cats['HF_V28'],
|
|
176
|
+
'HF_CHR_LUNG_V28': diagnostic_cats['HF_V28'] * diagnostic_cats['CHR_LUNG_V28'],
|
|
177
|
+
'HF_KIDNEY_V28': diagnostic_cats['HF_V28'] * diagnostic_cats['KIDNEY_V28'],
|
|
178
|
+
'CHR_LUNG_CARD_RESP_FAIL_V28': diagnostic_cats['CHR_LUNG_V28'] * diagnostic_cats['CARD_RESP_FAIL_V28'],
|
|
179
|
+
'gSubUseDisorder_gPsych_V28': diagnostic_cats['gSubUseDisorder_V28'] * diagnostic_cats['gPsychiatric_V28'],
|
|
180
|
+
'DISABLED_CANCER_V28': demographics.disabled * diagnostic_cats['CANCER_V28'],
|
|
181
|
+
'DISABLED_NEURO_V28': demographics.disabled * diagnostic_cats['NEURO_V28'],
|
|
182
|
+
'DISABLED_HF_V28': demographics.disabled * diagnostic_cats['HF_V28'],
|
|
183
|
+
'DISABLED_CHR_LUNG_V28': demographics.disabled * diagnostic_cats['CHR_LUNG_V28'],
|
|
184
|
+
'DISABLED_ULCER_V28': demographics.disabled * diagnostic_cats['ULCER_V28']
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
elif model_name == "CMS-HCC Model V24":
|
|
188
|
+
# Base V24/V22 disease interactions
|
|
189
|
+
interactions.update({
|
|
190
|
+
'HCC47_gCancer': int('47' in hcc_set) * diagnostic_cats['CANCER'],
|
|
191
|
+
'DIABETES_CHF': diagnostic_cats['DIABETES'] * diagnostic_cats['CHF'],
|
|
192
|
+
'CHF_gCopdCF': diagnostic_cats['CHF'] * diagnostic_cats['gCopdCF'],
|
|
193
|
+
'HCC85_gRenal_V24': diagnostic_cats['CHF'] * diagnostic_cats['RENAL_V24'],
|
|
194
|
+
'gCopdCF_CARD_RESP_FAIL': diagnostic_cats['gCopdCF'] * diagnostic_cats['CARD_RESP_FAIL'],
|
|
195
|
+
'HCC85_HCC96': int('85' in hcc_set) * int('96' in hcc_set),
|
|
196
|
+
'gSubstanceAbuse_gPsych': diagnostic_cats['gSubstanceUseDisorder_V24'] * diagnostic_cats['gPsychiatric_V24'],
|
|
197
|
+
'SEPSIS_PRESSURE_ULCER': diagnostic_cats['SEPSIS'] * diagnostic_cats['PRESSURE_ULCER'],
|
|
198
|
+
'SEPSIS_ARTIF_OPENINGS': diagnostic_cats['SEPSIS'] * int('188' in hcc_set),
|
|
199
|
+
'ART_OPENINGS_PRESS_ULCER': int('188' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
200
|
+
'gCopdCF_ASP_SPEC_B_PNEUM': diagnostic_cats['gCopdCF'] * int('114' in hcc_set),
|
|
201
|
+
'ASP_SPEC_B_PNEUM_PRES_ULC': int('114' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
202
|
+
'SEPSIS_ASP_SPEC_BACT_PNEUM': diagnostic_cats['SEPSIS'] * int('114' in hcc_set),
|
|
203
|
+
'SCHIZOPHRENIA_gCopdCF': int('57' in hcc_set) * diagnostic_cats['gCopdCF'],
|
|
204
|
+
'SCHIZOPHRENIA_CHF': int('57' in hcc_set) * diagnostic_cats['CHF'],
|
|
205
|
+
'SCHIZOPHRENIA_SEIZURES': int('57' in hcc_set) * int('79' in hcc_set),
|
|
206
|
+
'DISABLED_HCC85': demographics.disabled * int('85' in hcc_set),
|
|
207
|
+
'DISABLED_PRESSURE_ULCER': demographics.disabled * diagnostic_cats['PRESSURE_ULCER'],
|
|
208
|
+
'DISABLED_HCC161': demographics.disabled * int('161' in hcc_set),
|
|
209
|
+
'DISABLED_HCC39': demographics.disabled * int('39' in hcc_set),
|
|
210
|
+
'DISABLED_HCC77': demographics.disabled * int('77' in hcc_set),
|
|
211
|
+
'DISABLED_HCC6': demographics.disabled * int('6' in hcc_set)
|
|
212
|
+
})
|
|
213
|
+
elif model_name == "CMS-HCC Model V22":
|
|
214
|
+
# Base V24/V22 disease interactions
|
|
215
|
+
interactions.update({
|
|
216
|
+
'HCC47_gCancer': int('47' in hcc_set) * diagnostic_cats['CANCER'],
|
|
217
|
+
'HCC85_gDiabetesMellitus': int('85' in hcc_set) * diagnostic_cats['DIABETES'],
|
|
218
|
+
'HCC85_gCopdCF': int('85' in hcc_set) * diagnostic_cats['gCopdCF'],
|
|
219
|
+
'HCC85_gRenal': int('85' in hcc_set) * diagnostic_cats['RENAL'],
|
|
220
|
+
'gRespDepandArre_gCopdCF': diagnostic_cats['CARD_RESP_FAIL'] * diagnostic_cats['gCopdCF'],
|
|
221
|
+
'HCC85_HCC96': int('85' in hcc_set) * int('96' in hcc_set),
|
|
222
|
+
'gSubstanceAbuse_gPsychiatric': diagnostic_cats['gSubstanceUseDisorder'] * diagnostic_cats['gPsychiatric'],
|
|
223
|
+
'DIABETES_CHF': diagnostic_cats['DIABETES'] * diagnostic_cats['CHF'],
|
|
224
|
+
'CHF_gCopdCF': diagnostic_cats['CHF'] * diagnostic_cats['gCopdCF'],
|
|
225
|
+
'gCopdCF_CARD_RESP_FAIL': diagnostic_cats['gCopdCF'] * diagnostic_cats['CARD_RESP_FAIL'],
|
|
226
|
+
'SEPSIS_PRESSURE_ULCER': diagnostic_cats['SEPSIS'] * diagnostic_cats['PRESSURE_ULCER'],
|
|
227
|
+
'SEPSIS_ARTIF_OPENINGS': diagnostic_cats['SEPSIS'] * int('188' in hcc_set),
|
|
228
|
+
'ART_OPENINGS_PRESSURE_ULCER': int('188' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
229
|
+
'DIABETES_CHF': diagnostic_cats['DIABETES'] * diagnostic_cats['CHF'],
|
|
230
|
+
'gCopdCF_ASP_SPEC_BACT_PNEUM': diagnostic_cats['gCopdCF'] * int('114' in hcc_set),
|
|
231
|
+
'ASP_SPEC_BACT_PNEUM_PRES_ULC': int('114' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
232
|
+
'SEPSIS_ASP_SPEC_BACT_PNEUM': diagnostic_cats['SEPSIS'] * int('114' in hcc_set),
|
|
233
|
+
'SCHIZOPHRENIA_gCopdCF': int('57' in hcc_set) * diagnostic_cats['gCopdCF'],
|
|
234
|
+
'SCHIZOPHRENIA_CHF': int('57' in hcc_set) * diagnostic_cats['CHF'],
|
|
235
|
+
'SCHIZOPHRENIA_SEIZURES': int('57' in hcc_set) * int('79' in hcc_set),
|
|
236
|
+
'DISABLED_HCC85': demographics.disabled * int('85' in hcc_set),
|
|
237
|
+
'DISABLED_PRESSURE_ULCER': demographics.disabled * diagnostic_cats['PRESSURE_ULCER'],
|
|
238
|
+
'DISABLED_HCC161': demographics.disabled * int('161' in hcc_set),
|
|
239
|
+
'DISABLED_HCC39': demographics.disabled * int('39' in hcc_set),
|
|
240
|
+
'DISABLED_HCC77': demographics.disabled * int('77' in hcc_set),
|
|
241
|
+
'DISABLED_HCC6': demographics.disabled * int('6' in hcc_set)
|
|
242
|
+
})
|
|
243
|
+
elif model_name == "CMS-HCC ESRD Model V24":
|
|
244
|
+
# Base ESRD V24 disease interactions
|
|
245
|
+
interactions.update({
|
|
246
|
+
'HCC47_gCancer': int('47' in hcc_set) * diagnostic_cats['CANCER'],
|
|
247
|
+
'DIABETES_CHF': diagnostic_cats['DIABETES'] * diagnostic_cats['CHF'],
|
|
248
|
+
'CHF_gCopdCF': diagnostic_cats['CHF'] * diagnostic_cats['gCopdCF'],
|
|
249
|
+
'HCC85_gRenal_V24': int('85' in hcc_set) * diagnostic_cats['RENAL_V24'],
|
|
250
|
+
'gCopdCF_CARD_RESP_FAIL': diagnostic_cats['gCopdCF'] * diagnostic_cats['CARD_RESP_FAIL'],
|
|
251
|
+
'HCC85_HCC96': int('85' in hcc_set) * int('96' in hcc_set),
|
|
252
|
+
'gSubUseDs_gPsych_V24': diagnostic_cats['gSubstanceUseDisorder_V24'] * diagnostic_cats['gPsychiatric_V24'],
|
|
253
|
+
'NONAGED_gSubUseDs_gPsych': demographics.non_aged * (diagnostic_cats['gSubstanceUseDisorder_V24'] * diagnostic_cats['gPsychiatric_V24']),
|
|
254
|
+
'NONAGED_HCC6': demographics.non_aged * int('6' in hcc_set),
|
|
255
|
+
'NONAGED_HCC34': demographics.non_aged * int('34' in hcc_set),
|
|
256
|
+
'NONAGED_HCC46': demographics.non_aged * int('46' in hcc_set),
|
|
257
|
+
'NONAGED_HCC110': demographics.non_aged * int('110' in hcc_set),
|
|
258
|
+
'NONAGED_HCC176': demographics.non_aged * int('176' in hcc_set),
|
|
259
|
+
'SEPSIS_PRESSURE_ULCER_V24': diagnostic_cats['SEPSIS'] * diagnostic_cats['PRESSURE_ULCER'],
|
|
260
|
+
'SEPSIS_ARTIF_OPENINGS': diagnostic_cats['SEPSIS'] * int('188' in hcc_set),
|
|
261
|
+
'ART_OPENINGS_PRESS_ULCER_V24': int('188' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
262
|
+
'gCopdCF_ASP_SPEC_B_PNEUM': diagnostic_cats['gCopdCF'] * int('114' in hcc_set),
|
|
263
|
+
'ASP_SPEC_B_PNEUM_PRES_ULC_V24': int('114' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
264
|
+
'SEPSIS_ASP_SPEC_BACT_PNEUM': diagnostic_cats['SEPSIS'] * int('114' in hcc_set),
|
|
265
|
+
'SCHIZOPHRENIA_gCopdCF': int('57' in hcc_set) * diagnostic_cats['gCopdCF'],
|
|
266
|
+
'SCHIZOPHRENIA_CHF': int('57' in hcc_set) * diagnostic_cats['CHF'],
|
|
267
|
+
'SCHIZOPHRENIA_SEIZURES': int('57' in hcc_set) * int('79' in hcc_set),
|
|
268
|
+
'NONAGED_HCC85': demographics.non_aged * int('85' in hcc_set),
|
|
269
|
+
'NONAGED_PRESSURE_ULCER_V24': demographics.non_aged * diagnostic_cats['PRESSURE_ULCER'],
|
|
270
|
+
'NONAGED_HCC161': demographics.non_aged * int('161' in hcc_set),
|
|
271
|
+
'NONAGED_HCC39': demographics.non_aged * int('39' in hcc_set),
|
|
272
|
+
'NONAGED_HCC77': demographics.non_aged * int('77' in hcc_set)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
elif model_name == 'CMS-HCC ESRD Model V21':
|
|
276
|
+
# ESRD Community model interactions
|
|
277
|
+
interactions.update({
|
|
278
|
+
'SEPSIS_CARD_RESP_FAIL': diagnostic_cats['SEPSIS'] * diagnostic_cats['CARD_RESP_FAIL'],
|
|
279
|
+
'CANCER_IMMUNE': diagnostic_cats['CANCER'] * diagnostic_cats['IMMUNE'],
|
|
280
|
+
'DIABETES_CHF': diagnostic_cats['DIABETES'] * diagnostic_cats['CHF'],
|
|
281
|
+
'CHF_COPD': diagnostic_cats['CHF'] * diagnostic_cats['COPD'],
|
|
282
|
+
'CHF_RENAL': diagnostic_cats['CHF'] * diagnostic_cats['RENAL'],
|
|
283
|
+
'COPD_CARD_RESP_FAIL': diagnostic_cats['COPD'] * diagnostic_cats['CARD_RESP_FAIL'],
|
|
284
|
+
'NONAGED_HCC6': demographics.non_aged * int('6' in hcc_set),
|
|
285
|
+
'NONAGED_HCC34': demographics.non_aged * int('34' in hcc_set),
|
|
286
|
+
'NONAGED_HCC46': demographics.non_aged * int('46' in hcc_set),
|
|
287
|
+
'NONAGED_HCC54': demographics.non_aged * int('54' in hcc_set),
|
|
288
|
+
'NONAGED_HCC55': demographics.non_aged * int('55' in hcc_set),
|
|
289
|
+
'NONAGED_HCC110': demographics.non_aged * int('110' in hcc_set),
|
|
290
|
+
'NONAGED_HCC176': demographics.non_aged * int('176' in hcc_set),
|
|
291
|
+
'SEPSIS_PRESSURE_ULCER': diagnostic_cats['SEPSIS'] * diagnostic_cats['PRESSURE_ULCER'],
|
|
292
|
+
'SEPSIS_ARTIF_OPENINGS': diagnostic_cats['SEPSIS'] * int('188' in hcc_set),
|
|
293
|
+
'ART_OPENINGS_PRESSURE_ULCER': int('188' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
294
|
+
'DIABETES_CHF': diagnostic_cats['DIABETES'] * diagnostic_cats['CHF'],
|
|
295
|
+
'COPD_ASP_SPEC_BACT_PNEUM': diagnostic_cats['COPD'] * int('114' in hcc_set),
|
|
296
|
+
'ASP_SPEC_BACT_PNEUM_PRES_ULC': int('114' in hcc_set) * diagnostic_cats['PRESSURE_ULCER'],
|
|
297
|
+
'SEPSIS_ASP_SPEC_BACT_PNEUM': diagnostic_cats['SEPSIS'] * int('114' in hcc_set),
|
|
298
|
+
'SCHIZOPHRENIA_COPD': int('57' in hcc_set) * diagnostic_cats['COPD'],
|
|
299
|
+
'SCHIZOPHRENIA_CHF': int('57' in hcc_set) * diagnostic_cats['CHF'],
|
|
300
|
+
'SCHIZOPHRENIA_SEIZURES': int('57' in hcc_set) * int('79' in hcc_set),
|
|
301
|
+
'NONAGED_HCC85': demographics.non_aged * int('85' in hcc_set),
|
|
302
|
+
'NONAGED_PRESSURE_ULCER': demographics.non_aged * diagnostic_cats['PRESSURE_ULCER'],
|
|
303
|
+
'NONAGED_HCC161': demographics.non_aged * int('161' in hcc_set),
|
|
304
|
+
'NONAGED_HCC39': demographics.non_aged * int('39' in hcc_set),
|
|
305
|
+
'NONAGED_HCC77': demographics.non_aged * int('77' in hcc_set)
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
elif model_name == "RxHCC Model V08":
|
|
309
|
+
# RxHCC NonAged interactions
|
|
310
|
+
interactions.update({
|
|
311
|
+
'NonAged_RXHCC1': demographics.non_aged * int('1' in hcc_set),
|
|
312
|
+
'NonAged_RXHCC130': demographics.non_aged * int('130' in hcc_set),
|
|
313
|
+
'NonAged_RXHCC131': demographics.non_aged * int('131' in hcc_set),
|
|
314
|
+
'NonAged_RXHCC132': demographics.non_aged * int('132' in hcc_set),
|
|
315
|
+
'NonAged_RXHCC133': demographics.non_aged * int('133' in hcc_set),
|
|
316
|
+
'NonAged_RXHCC159': demographics.non_aged * int('159' in hcc_set),
|
|
317
|
+
'NonAged_RXHCC163': demographics.non_aged * int('163' in hcc_set)
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
return interactions
|
|
321
|
+
|
|
322
|
+
def apply_interactions(demographics: Demographics,
|
|
323
|
+
hcc_set: set[str],
|
|
324
|
+
model_name: ModelName = "CMS-HCC Model V28") -> dict:
|
|
325
|
+
"""
|
|
326
|
+
Calculate HCC interactions across CMS models. Handles CMS-HCC, ESRD, and RxHCC models.
|
|
327
|
+
"""
|
|
328
|
+
# Start with demographic interactions
|
|
329
|
+
interactions = create_demographic_interactions(demographics)
|
|
330
|
+
|
|
331
|
+
# Add dual status interactions
|
|
332
|
+
interactions.update(create_dual_interactions(demographics))
|
|
333
|
+
|
|
334
|
+
# Get diagnostic categories for the model
|
|
335
|
+
diagnostic_cats = get_diagnostic_categories(model_name, hcc_set)
|
|
336
|
+
|
|
337
|
+
interactions.update(create_disease_interactions(model_name, diagnostic_cats, demographics, hcc_set))
|
|
338
|
+
|
|
339
|
+
# Add HCC counts
|
|
340
|
+
interactions.update(create_hcc_counts(hcc_set))
|
|
341
|
+
|
|
342
|
+
return interactions
|
hccinfhir/utils.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from typing import Set, Dict, Tuple
|
|
2
|
+
import importlib.resources
|
|
3
|
+
from hccinfhir.datamodels import ModelName, ProcFilteringFilename, DxCCMappingFilename
|
|
4
|
+
|
|
5
|
+
def load_proc_filtering(filename: ProcFilteringFilename) -> Set[str]:
|
|
6
|
+
"""
|
|
7
|
+
Load a single-column CSV file into a set of strings.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
filename: Name of the CSV file in the hccinfhir.data package
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
Set of strings from the CSV file
|
|
14
|
+
"""
|
|
15
|
+
try:
|
|
16
|
+
with importlib.resources.open_text('hccinfhir.data', filename) as f:
|
|
17
|
+
return set(f.read().splitlines())
|
|
18
|
+
except Exception as e:
|
|
19
|
+
print(f"Error loading {filename}: {e}")
|
|
20
|
+
return set()
|
|
21
|
+
|
|
22
|
+
def load_dx_to_cc_mapping(filename: DxCCMappingFilename) -> Dict[Tuple[str, ModelName], Set[str]]:
|
|
23
|
+
"""
|
|
24
|
+
Load diagnosis to CC mapping from a CSV file.
|
|
25
|
+
Expected format: diagnosis_code,cc,model_name
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
filename: Name of the CSV file in the hccinfhir.data package
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Dictionary mapping (diagnosis_code, model_name) to a set of CC codes
|
|
32
|
+
"""
|
|
33
|
+
mapping: Dict[Tuple[str, ModelName], Set[str]] = {}
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
with importlib.resources.open_text('hccinfhir.data', filename) as f:
|
|
37
|
+
for line in f.readlines()[1:]: # Skip header
|
|
38
|
+
try:
|
|
39
|
+
diagnosis_code, cc, model_name = line.strip().split(',')
|
|
40
|
+
key = (diagnosis_code, model_name)
|
|
41
|
+
if key not in mapping:
|
|
42
|
+
mapping[key] = {cc}
|
|
43
|
+
else:
|
|
44
|
+
mapping[key].add(cc)
|
|
45
|
+
except ValueError:
|
|
46
|
+
continue # Skip malformed lines
|
|
47
|
+
except Exception as e:
|
|
48
|
+
print(f"Error loading mapping file: {e}")
|
|
49
|
+
return {}
|
|
50
|
+
|
|
51
|
+
return mapping
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: hccinfhir
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
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
|
|
@@ -20,6 +20,9 @@ A Python library for extracting standardized service-level data from FHIR Explan
|
|
|
20
20
|
- Support for both BCDA (Blue Button 2.0) and standard FHIR R4 formats
|
|
21
21
|
- Pydantic models for type safety and data validation
|
|
22
22
|
- Standardized Service Level Data (SLD) output format
|
|
23
|
+
- Multiple HCC model support (V22, V24, V28, ESRD V21, ESRD V24, RxHCC V08)
|
|
24
|
+
- Flexible input options: FHIR EOBs, service data, or direct diagnosis codes
|
|
25
|
+
|
|
23
26
|
|
|
24
27
|
## Installation
|
|
25
28
|
```bash
|
|
@@ -45,7 +48,26 @@ sld = [{
|
|
|
45
48
|
}, ...]
|
|
46
49
|
```
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
Or, for direct risk score calculation from a list of diagnosis codes, you only need the model name, diagnosis codes, and basic demographic factors:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from hccinfhir.model_calculate import calculate_raf
|
|
55
|
+
|
|
56
|
+
diagnosis_codes = ['E119', 'I509'] # Diabetes without complications, Heart failure
|
|
57
|
+
age = 67
|
|
58
|
+
sex = 'F'
|
|
59
|
+
model_name = "CMS-HCC Model V24"
|
|
60
|
+
|
|
61
|
+
result = calculate_raf(
|
|
62
|
+
diagnosis_codes=diagnosis_codes,
|
|
63
|
+
model_name=model_name,
|
|
64
|
+
age=age,
|
|
65
|
+
sex=sex
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
For more details on the SLD format, see the `datamodels.py` file.
|
|
49
71
|
|
|
50
72
|
## Core Components
|
|
51
73
|
|
|
@@ -71,23 +93,99 @@ filtered_sld = apply_filter(sld_list)
|
|
|
71
93
|
```
|
|
72
94
|
|
|
73
95
|
|
|
74
|
-
### 3. Logic Module
|
|
96
|
+
### 3. Logic Module
|
|
75
97
|
Implements core HCC calculation logic:
|
|
76
98
|
- Maps diagnosis codes to HCC categories
|
|
77
99
|
- Applies hierarchical rules and interactions
|
|
78
100
|
- Calculates final RAF scores
|
|
79
101
|
- Integrates with standard CMS data files
|
|
80
102
|
|
|
81
|
-
## Usage
|
|
82
103
|
```python
|
|
83
|
-
from hccinfhir import
|
|
104
|
+
from hccinfhir.model_calculate import calculate_raf
|
|
105
|
+
|
|
106
|
+
diagnosis_codes = ['E119', 'I509'] # Diabetes without complications, Heart failure
|
|
107
|
+
result = calculate_raf(
|
|
108
|
+
diagnosis_codes=diagnosis_codes,
|
|
109
|
+
model_name="CMS-HCC Model V24",
|
|
110
|
+
age=67,
|
|
111
|
+
sex='F'
|
|
112
|
+
)
|
|
113
|
+
```
|
|
84
114
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
115
|
+
### 4. HCCInFHIR Class
|
|
116
|
+
The main processor class that integrates extraction, filtering, and calculation components:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from hccinfhir.hccinfhir import HCCInFHIR
|
|
120
|
+
from hccinfhir.datamodels import Demographics
|
|
121
|
+
|
|
122
|
+
# Initialize with custom configuration
|
|
123
|
+
hcc_processor = HCCInFHIR(
|
|
124
|
+
filter_claims=True, # Enable claim filtering
|
|
125
|
+
model_name="CMS-HCC Model V28", # Choose HCC model version
|
|
126
|
+
proc_filtering_filename="ra_eligible_cpt_hcpcs_2025.csv", # CPT/HCPCS filtering rules
|
|
127
|
+
dx_cc_mapping_filename="ra_dx_to_cc_2025.csv" # Diagnosis to CC mapping
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Define beneficiary demographics
|
|
131
|
+
demographics = Demographics(
|
|
132
|
+
age=67,
|
|
133
|
+
sex='F',
|
|
134
|
+
dual_elgbl_cd='00', # Not dual eligible
|
|
135
|
+
orec='0', # Old age
|
|
136
|
+
crec='0', # Current old age
|
|
137
|
+
new_enrollee=False,
|
|
138
|
+
snp=False
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Method 1: Process FHIR EOB resources
|
|
142
|
+
raf_result = hcc_processor.run(eob_list, demographics)
|
|
143
|
+
|
|
144
|
+
# Method 2: Process service level data
|
|
145
|
+
service_data = [{
|
|
146
|
+
"procedure_code": "99214",
|
|
147
|
+
"claim_diagnosis_codes": ["E11.9", "I10"],
|
|
148
|
+
"claim_type": "71",
|
|
149
|
+
"service_date": "2024-01-15"
|
|
150
|
+
}]
|
|
151
|
+
raf_result = hcc_processor.run_from_service_data(service_data, demographics)
|
|
152
|
+
|
|
153
|
+
# Method 3: Direct diagnosis processing
|
|
154
|
+
diagnosis_codes = ['E119', 'I509']
|
|
155
|
+
raf_result = hcc_processor.calculate_from_diagnosis(diagnosis_codes, demographics)
|
|
156
|
+
|
|
157
|
+
# RAF Result contains:
|
|
158
|
+
print(f"Risk Score: {raf_result['risk_score']}")
|
|
159
|
+
print(f"HCC List: {raf_result['hcc_list']}")
|
|
160
|
+
print(f"CC to Diagnosis Mapping: {raf_result['cc_to_dx']}")
|
|
161
|
+
print(f"Applied Coefficients: {raf_result['coefficients']}")
|
|
162
|
+
print(f"Applied Interactions: {raf_result['interactions']}")
|
|
89
163
|
```
|
|
90
164
|
|
|
165
|
+
The HCCInFHIR class provides three main processing methods:
|
|
166
|
+
|
|
167
|
+
1. `run(eob_list, demographics)`: Process FHIR ExplanationOfBenefit resources
|
|
168
|
+
- Extracts service data from FHIR resources
|
|
169
|
+
- Applies filtering rules if enabled
|
|
170
|
+
- Calculates RAF scores using the specified model
|
|
171
|
+
|
|
172
|
+
2. `run_from_service_data(service_data, demographics)`: Process standardized service data
|
|
173
|
+
- Accepts pre-formatted service level data
|
|
174
|
+
- Validates data structure using Pydantic models
|
|
175
|
+
- Applies filtering and calculates RAF scores
|
|
176
|
+
|
|
177
|
+
3. `calculate_from_diagnosis(diagnosis_codes, demographics)`: Direct diagnosis processing
|
|
178
|
+
- Processes raw diagnosis codes without service context
|
|
179
|
+
- Useful for quick RAF calculations or validation
|
|
180
|
+
- Bypasses service-level filtering
|
|
181
|
+
|
|
182
|
+
Each method returns a RAFResult containing:
|
|
183
|
+
- Final risk score
|
|
184
|
+
- List of HCCs
|
|
185
|
+
- Mapping of condition categories to diagnosis codes
|
|
186
|
+
- Applied coefficients and interactions
|
|
187
|
+
- Processed service level data (when applicable)
|
|
188
|
+
|
|
91
189
|
## Testing
|
|
92
190
|
```bash
|
|
93
191
|
$ python3 -m hatch shell
|
|
@@ -172,8 +270,48 @@ $ python3 -m pytest tests/*
|
|
|
172
270
|
3. Add support for allowed_amount in 837 if available in different segments
|
|
173
271
|
4. Consider adding more robust error handling in both implementations
|
|
174
272
|
|
|
273
|
+
## Data Files
|
|
274
|
+
|
|
275
|
+
`ra_dx_to_cc_mapping_2025.csv`
|
|
276
|
+
```sql
|
|
277
|
+
SELECT diagnosis_code, cc, model_name
|
|
278
|
+
FROM ra_dx_to_cc_mapping
|
|
279
|
+
WHERE year = 2025 and model_type = 'Initial';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`ra_hierarchies_2025.csv`
|
|
283
|
+
```sql
|
|
284
|
+
SELECT cc_parent,
|
|
285
|
+
cc_child,
|
|
286
|
+
model_domain,
|
|
287
|
+
model_version,
|
|
288
|
+
model_fullname
|
|
289
|
+
FROM ra_hierarchies
|
|
290
|
+
WHERE eff_last_date > '2025-01-01';
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
`ra_coefficients_2025.csv`
|
|
294
|
+
```sql
|
|
295
|
+
SELECT coefficient, value, model_domain, model_version
|
|
296
|
+
FROM ra_coefficients
|
|
297
|
+
WHERE eff_last_date > '2025-01-01';
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`ra_eligible_cpt_hcpcs_2025.csv`
|
|
301
|
+
```sql
|
|
302
|
+
SELECT DISTINCT cpt_hcpcs_code
|
|
303
|
+
FROM mimi_ws_1.cmspayment.ra_eligible_cpt_hcpcs
|
|
304
|
+
WHERE is_included = 'yes' AND YEAR(mimi_src_file_date) = 2024;
|
|
305
|
+
```
|
|
306
|
+
|
|
175
307
|
## Contributing
|
|
176
308
|
Join us at [mimilabs](https://mimilabs.ai/signup). Reference data available in MIMILabs data lakehouse.
|
|
177
309
|
|
|
310
|
+
## Publishing (only for those maintainers...)
|
|
311
|
+
```bash
|
|
312
|
+
$ hatch build
|
|
313
|
+
$ hatch publish
|
|
314
|
+
```
|
|
315
|
+
|
|
178
316
|
## License
|
|
179
317
|
Apache License 2.0
|