hccinfhir 0.0.3__py3-none-any.whl → 0.0.4__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.
Files changed (38) hide show
  1. hccinfhir/data/ra_coefficients_2025.csv +6352 -0
  2. hccinfhir/data/ra_dx_to_cc_2025.csv +53952 -0
  3. hccinfhir/data/ra_hierarchies_2025.csv +487 -0
  4. hccinfhir/datamodels.py +84 -0
  5. hccinfhir/extractor.py +3 -3
  6. hccinfhir/extractor_837.py +1 -2
  7. hccinfhir/extractor_fhir.py +1 -1
  8. hccinfhir/filter.py +1 -1
  9. hccinfhir/hccinfhir.py +142 -0
  10. hccinfhir/model_calculate.py +50 -0
  11. hccinfhir/model_coefficients.py +143 -0
  12. hccinfhir/model_demographics.py +191 -0
  13. hccinfhir/model_dx_to_cc.py +70 -0
  14. hccinfhir/model_hierarchies.py +70 -0
  15. hccinfhir/model_interactions.py +342 -0
  16. hccinfhir/samples/__init__.py +2 -0
  17. {hccinfhir-0.0.3.dist-info → hccinfhir-0.0.4.dist-info}/METADATA +65 -7
  18. hccinfhir-0.0.4.dist-info/RECORD +39 -0
  19. hccinfhir/models.py +0 -44
  20. hccinfhir-0.0.3.dist-info/RECORD +0 -28
  21. /hccinfhir/{data → samples}/sample_837_0.txt +0 -0
  22. /hccinfhir/{data → samples}/sample_837_1.txt +0 -0
  23. /hccinfhir/{data → samples}/sample_837_10.txt +0 -0
  24. /hccinfhir/{data → samples}/sample_837_11.txt +0 -0
  25. /hccinfhir/{data → samples}/sample_837_2.txt +0 -0
  26. /hccinfhir/{data → samples}/sample_837_3.txt +0 -0
  27. /hccinfhir/{data → samples}/sample_837_4.txt +0 -0
  28. /hccinfhir/{data → samples}/sample_837_5.txt +0 -0
  29. /hccinfhir/{data → samples}/sample_837_6.txt +0 -0
  30. /hccinfhir/{data → samples}/sample_837_7.txt +0 -0
  31. /hccinfhir/{data → samples}/sample_837_8.txt +0 -0
  32. /hccinfhir/{data → samples}/sample_837_9.txt +0 -0
  33. /hccinfhir/{data → samples}/sample_eob_1.json +0 -0
  34. /hccinfhir/{data → samples}/sample_eob_2.json +0 -0
  35. /hccinfhir/{data → samples}/sample_eob_200.ndjson +0 -0
  36. /hccinfhir/{data → samples}/sample_eob_3.json +0 -0
  37. {hccinfhir-0.0.3.dist-info → hccinfhir-0.0.4.dist-info}/WHEEL +0 -0
  38. {hccinfhir-0.0.3.dist-info → hccinfhir-0.0.4.dist-info}/licenses/LICENSE +0 -0
@@ -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
@@ -0,0 +1,2 @@
1
+ # Empty file to make the package importable
2
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: hccinfhir
3
- Version: 0.0.3
3
+ Version: 0.0.4
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
@@ -45,7 +45,26 @@ sld = [{
45
45
  }, ...]
46
46
  ```
47
47
 
48
- For more details on the SLD format, see the `models.py` file.
48
+ Or, for direct risk score calculation from a list of diagnosis codes, you only need the model name, diagnosis codes, and basic demographic factors:
49
+
50
+ ```python
51
+ from hccinfhir.model_calculate import calculate_raf
52
+
53
+ diagnosis_codes = ['E119', 'I509'] # Diabetes without complications, Heart failure
54
+ age = 67
55
+ sex = 'F'
56
+ model_name = "CMS-HCC Model V24"
57
+
58
+ result = calculate_raf(
59
+ diagnosis_codes=diagnosis_codes,
60
+ model_name=model_name,
61
+ age=age,
62
+ sex=sex
63
+ )
64
+ ```
65
+
66
+
67
+ For more details on the SLD format, see the `datamodels.py` file.
49
68
 
50
69
  ## Core Components
51
70
 
@@ -71,21 +90,33 @@ filtered_sld = apply_filter(sld_list)
71
90
  ```
72
91
 
73
92
 
74
- ### 3. Logic Module (In Development)
93
+ ### 3. Logic Module
75
94
  Implements core HCC calculation logic:
76
95
  - Maps diagnosis codes to HCC categories
77
96
  - Applies hierarchical rules and interactions
78
97
  - Calculates final RAF scores
79
98
  - Integrates with standard CMS data files
80
99
 
81
- ## Usage
100
+ ```python
101
+ from hccinfhir.model_calculate import calculate_raf
102
+
103
+ diagnosis_codes = ['E119', 'I509'] # Diabetes without complications, Heart failure
104
+ result = calculate_raf(
105
+ diagnosis_codes=diagnosis_codes,
106
+ model_name="CMS-HCC Model V24",
107
+ age=67,
108
+ sex='F'
109
+ )
110
+ ```
111
+
112
+ ### 4. Running HCC on FHIR data
113
+
82
114
  ```python
83
115
  from hccinfhir import HCCInFHIR
84
116
 
85
117
  hcc_processor = HCCInFHIR()
86
- sld_list = hcc_processor.extract_sld_list(eob_list)
87
- filtered_sld = hcc_processor.apply_filters(sld_list) # future
88
- raf_details = hcc_processor.calculate_raf(filtered_sld, demographic_data) # future
118
+
119
+ result = hcc_processor.run(eob_list, demographic_data)
89
120
  ```
90
121
 
91
122
  ## Testing
@@ -172,6 +203,33 @@ $ python3 -m pytest tests/*
172
203
  3. Add support for allowed_amount in 837 if available in different segments
173
204
  4. Consider adding more robust error handling in both implementations
174
205
 
206
+ ## Data Files
207
+
208
+ `ra_dx_to_cc_mapping_2025.csv`
209
+ ```sql
210
+ SELECT diagnosis_code, cc, model_name
211
+ FROM ra_dx_to_cc_mapping
212
+ WHERE year = 2025 and model_type = 'Initial';
213
+ ```
214
+
215
+ `ra_hierarchies_2025.csv`
216
+ ```sql
217
+ SELECT cc_parent,
218
+ cc_child,
219
+ model_domain,
220
+ model_version,
221
+ model_fullname
222
+ FROM ra_hierarchies
223
+ WHERE eff_last_date > '2025-01-01';
224
+ ```
225
+
226
+ `ra_coefficients_2025.csv`
227
+ ```sql
228
+ SELECT coefficient, value, model_domain, model_version
229
+ FROM ra_coefficients
230
+ WHERE eff_last_date > '2025-01-01';
231
+ ```
232
+
175
233
  ## Contributing
176
234
  Join us at [mimilabs](https://mimilabs.ai/signup). Reference data available in MIMILabs data lakehouse.
177
235
 
@@ -0,0 +1,39 @@
1
+ hccinfhir/__init__.py,sha256=OCyYCv4jTOlYHZbTw2DTks3e6_YT1N2JXAOuyR03KNE,43
2
+ hccinfhir/datamodels.py,sha256=S-wQQXEyya_RbrMLmHCPWouaFvEflV8762mciwhrtSk,4270
3
+ hccinfhir/extractor.py,sha256=-jHVCIJqFAqvrI9GxkkXZVDQjKDa-7vF7v3PGMGAMnA,1801
4
+ hccinfhir/extractor_837.py,sha256=vkTBCd0WBaJoTrUd-Z-zCIaoLk7KV2n4AGqIORhONIk,7147
5
+ hccinfhir/extractor_fhir.py,sha256=Rg_L0Vg5tz_L2VJ_jvZwWz6RMlPAkHwj4LiK-OWQvrQ,8458
6
+ hccinfhir/filter.py,sha256=tyaK0Ss0rafkDfcCJWUZOAzzFOIYiuf_SuJ4BBiHJ38,2272
7
+ hccinfhir/hccinfhir.py,sha256=IS3Hvm8wnFL785XkANva6qB9kkc54OCFn-KkwuW5BX0,6450
8
+ hccinfhir/model_calculate.py,sha256=EA5JvbB36wrFAt6kD79E8rn9NKntVMJqXHAq_p7duEE,1947
9
+ hccinfhir/model_coefficients.py,sha256=UrDAEWBoqooSC8hy9YSUsLMmmfgIO0YGtVkui6ruOkE,5528
10
+ hccinfhir/model_demographics.py,sha256=LZLlPQOtxPh3Md6q9xwztQ9PwrUo_gloNCYSa2bDirY,6578
11
+ hccinfhir/model_dx_to_cc.py,sha256=foKn2A0ly2TOVKq5qA92CuZSxHPX00cqt5D-DjBm9x4,2348
12
+ hccinfhir/model_hierarchies.py,sha256=e8QtSayTrfPv2wh149FjK7ToiEmU1ISYMA1Pi38iVk0,2700
13
+ hccinfhir/model_interactions.py,sha256=ZLiKJepPjPkYceKDf7dLXoYE0p44I7t9y2sTOlrxojo,20264
14
+ hccinfhir/data/__init__.py,sha256=SGiSkpGrnxbvtEFMMlk82NFHOE50hFXcgKwKUSuVZUg,45
15
+ hccinfhir/data/ra_coefficients_2025.csv,sha256=I0S2hoJlfig-D0oSFxy0b3Piv7m9AzOGo2CwR6bcQ9w,215191
16
+ hccinfhir/data/ra_dx_to_cc_2025.csv,sha256=4N7vF6VZndkl7d3Fo0cGsbAPAZdCjAizSH8BOKsZNAo,1618924
17
+ hccinfhir/data/ra_eligible_cpt_hcpcs_2023.csv,sha256=VVoA4s0hsFmcRIugyFdbvSoeLcn7M7z0DITT6l4YqL8,39885
18
+ hccinfhir/data/ra_hierarchies_2025.csv,sha256=HQSPNloe6mvvwMgv8ZwYAfWKkT2b2eUvm4JQy6S_mVQ,13045
19
+ hccinfhir/samples/__init__.py,sha256=SGiSkpGrnxbvtEFMMlk82NFHOE50hFXcgKwKUSuVZUg,45
20
+ hccinfhir/samples/sample_837_0.txt,sha256=eggrD259uHa05z2dfxWBpUDseSDp_AQcLyN_adpHyTw,5295
21
+ hccinfhir/samples/sample_837_1.txt,sha256=E155MdemSDYoXokuTXUZ6Br_RGGedYv5t5dh-eMRmuk,1322
22
+ hccinfhir/samples/sample_837_10.txt,sha256=zSJXI78vHAksA7FFQEVLvepefdpMM2_AexLyoDimV3Q,1129
23
+ hccinfhir/samples/sample_837_11.txt,sha256=suVxlZEllEOy6dYgbzGIphKW6hDAKdYQTZFM3Ob84q4,817
24
+ hccinfhir/samples/sample_837_2.txt,sha256=2bvXzaiopr7pO3D3pL7nLxcpgqKXrhu3lbulveJDJ-I,1125
25
+ hccinfhir/samples/sample_837_3.txt,sha256=_B1Ktpsg7bOnA5BwZ7AUB0o7MME5AmLGuxzHq42FWok,1113
26
+ hccinfhir/samples/sample_837_4.txt,sha256=jpzyiHKmRGMqN1ij9s1X4zRj0a2PXwtee4mjn4BRF3g,1077
27
+ hccinfhir/samples/sample_837_5.txt,sha256=eYG4URk3zAr5UsnBKO5Wezo8dnL_HXGCMmXWJu0nxPA,1300
28
+ hccinfhir/samples/sample_837_6.txt,sha256=pnKQf2cVcZpUl8PGeYzZxRxjKOMcISN2dBObIMtLx7E,1331
29
+ hccinfhir/samples/sample_837_7.txt,sha256=5Y-x7ZA9d_qGaIrpVGfXKQBXqbxKiQ5CWOwEW1XGlds,1253
30
+ hccinfhir/samples/sample_837_8.txt,sha256=J-zm0fzp6F19r2SWfHcCtab9ezd3c4YaSRO-RatJ-c4,1250
31
+ hccinfhir/samples/sample_837_9.txt,sha256=nIIurZ0tLHw6ZfDM__U-WqV8Q0u4K3WP56-r3BnAEv8,1341
32
+ hccinfhir/samples/sample_eob_1.json,sha256=_NGSVR2ysFpx-DcTvyga6dFCzhQ8Vi9fNzQEMPz5awU,3124
33
+ hccinfhir/samples/sample_eob_2.json,sha256=FcnJcx0ApOczxjJ_uxVLzCep9THfNf4xs9Yf7hxk8e4,1769
34
+ hccinfhir/samples/sample_eob_200.ndjson,sha256=CxpjeQ1DCMUzZILaM68UEhfxO0p45YGhDDoCZeq8PxU,1917986
35
+ hccinfhir/samples/sample_eob_3.json,sha256=4BW4wOMBEEU9RDfJR15rBEvk0KNHyuMEh3e055y87Hc,2306
36
+ hccinfhir-0.0.4.dist-info/METADATA,sha256=_A0qRJoRtyxs2NHjypr8DP-DSIK_bg_sRgBoOMrtSig,8763
37
+ hccinfhir-0.0.4.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
38
+ hccinfhir-0.0.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
39
+ hccinfhir-0.0.4.dist-info/RECORD,,
hccinfhir/models.py DELETED
@@ -1,44 +0,0 @@
1
- from pydantic import BaseModel
2
- from typing import List, Optional
3
-
4
- class ServiceLevelData(BaseModel):
5
- """
6
- Represents standardized service-level data extracted from healthcare claims.
7
-
8
- Attributes:
9
- claim_id: Unique identifier for the claim
10
- procedure_code: Healthcare Common Procedure Coding System (HCPCS) code
11
- ndc: National Drug Code
12
- linked_diagnosis_codes: ICD-10 diagnosis codes linked to this service
13
- claim_diagnosis_codes: All diagnosis codes on the claim
14
- claim_type: Type of claim (e.g., NCH Claim Type Code, or 837I, 837P)
15
- provider_specialty: Provider taxonomy or specialty code
16
- performing_provider_npi: National Provider Identifier for performing provider
17
- billing_provider_npi: National Provider Identifier for billing provider
18
- patient_id: Unique identifier for the patient
19
- facility_type: Type of facility where service was rendered
20
- service_type: Type of service provided (facility type + service type = Type of Bill)
21
- service_date: Date service was performed (YYYY-MM-DD)
22
- place_of_service: Place of service code
23
- quantity: Number of units provided
24
- quantity_unit: Unit of measure for quantity
25
- modifiers: List of procedure code modifiers
26
- allowed_amount: Allowed amount for the service
27
- """
28
- claim_id: Optional[str] = None
29
- procedure_code: Optional[str] = None
30
- ndc: Optional[str] = None
31
- linked_diagnosis_codes: List[str] = []
32
- claim_diagnosis_codes: List[str] = []
33
- claim_type: Optional[str] = None
34
- provider_specialty: Optional[str] = None
35
- performing_provider_npi: Optional[str] = None
36
- billing_provider_npi: Optional[str] = None
37
- patient_id: Optional[str] = None
38
- facility_type: Optional[str] = None
39
- service_type: Optional[str] = None
40
- service_date: Optional[str] = None
41
- place_of_service: Optional[str] = None
42
- quantity: Optional[float] = None
43
- modifiers: List[str] = []
44
- allowed_amount: Optional[float] = None
@@ -1,28 +0,0 @@
1
- hccinfhir/__init__.py,sha256=OCyYCv4jTOlYHZbTw2DTks3e6_YT1N2JXAOuyR03KNE,43
2
- hccinfhir/extractor.py,sha256=IHKxHEsuU5JIPnScv8x9v_L28aG5F6edZZ0VeYpBF6Y,1770
3
- hccinfhir/extractor_837.py,sha256=84OeYB1nXl329osWagkkuX0q4MVATnHGk7VZa9p6zoI,7160
4
- hccinfhir/extractor_fhir.py,sha256=Yu6Ce-2iKvn0j21t_EJUeXjwjZYbTh5HgqChMz8KkjI,8445
5
- hccinfhir/filter.py,sha256=C05uFhqSVb0J7BpKPGt4hwQrCd0_HbGSmrxKHIZLg4w,2259
6
- hccinfhir/models.py,sha256=dH0qICn8yjsqc35INYSG4HbvYyegRCPtQOPTJf5Qozw,2033
7
- hccinfhir/data/__init__.py,sha256=SGiSkpGrnxbvtEFMMlk82NFHOE50hFXcgKwKUSuVZUg,45
8
- hccinfhir/data/ra_eligible_cpt_hcpcs_2023.csv,sha256=VVoA4s0hsFmcRIugyFdbvSoeLcn7M7z0DITT6l4YqL8,39885
9
- hccinfhir/data/sample_837_0.txt,sha256=eggrD259uHa05z2dfxWBpUDseSDp_AQcLyN_adpHyTw,5295
10
- hccinfhir/data/sample_837_1.txt,sha256=E155MdemSDYoXokuTXUZ6Br_RGGedYv5t5dh-eMRmuk,1322
11
- hccinfhir/data/sample_837_10.txt,sha256=zSJXI78vHAksA7FFQEVLvepefdpMM2_AexLyoDimV3Q,1129
12
- hccinfhir/data/sample_837_11.txt,sha256=suVxlZEllEOy6dYgbzGIphKW6hDAKdYQTZFM3Ob84q4,817
13
- hccinfhir/data/sample_837_2.txt,sha256=2bvXzaiopr7pO3D3pL7nLxcpgqKXrhu3lbulveJDJ-I,1125
14
- hccinfhir/data/sample_837_3.txt,sha256=_B1Ktpsg7bOnA5BwZ7AUB0o7MME5AmLGuxzHq42FWok,1113
15
- hccinfhir/data/sample_837_4.txt,sha256=jpzyiHKmRGMqN1ij9s1X4zRj0a2PXwtee4mjn4BRF3g,1077
16
- hccinfhir/data/sample_837_5.txt,sha256=eYG4URk3zAr5UsnBKO5Wezo8dnL_HXGCMmXWJu0nxPA,1300
17
- hccinfhir/data/sample_837_6.txt,sha256=pnKQf2cVcZpUl8PGeYzZxRxjKOMcISN2dBObIMtLx7E,1331
18
- hccinfhir/data/sample_837_7.txt,sha256=5Y-x7ZA9d_qGaIrpVGfXKQBXqbxKiQ5CWOwEW1XGlds,1253
19
- hccinfhir/data/sample_837_8.txt,sha256=J-zm0fzp6F19r2SWfHcCtab9ezd3c4YaSRO-RatJ-c4,1250
20
- hccinfhir/data/sample_837_9.txt,sha256=nIIurZ0tLHw6ZfDM__U-WqV8Q0u4K3WP56-r3BnAEv8,1341
21
- hccinfhir/data/sample_eob_1.json,sha256=_NGSVR2ysFpx-DcTvyga6dFCzhQ8Vi9fNzQEMPz5awU,3124
22
- hccinfhir/data/sample_eob_2.json,sha256=FcnJcx0ApOczxjJ_uxVLzCep9THfNf4xs9Yf7hxk8e4,1769
23
- hccinfhir/data/sample_eob_200.ndjson,sha256=CxpjeQ1DCMUzZILaM68UEhfxO0p45YGhDDoCZeq8PxU,1917986
24
- hccinfhir/data/sample_eob_3.json,sha256=4BW4wOMBEEU9RDfJR15rBEvk0KNHyuMEh3e055y87Hc,2306
25
- hccinfhir-0.0.3.dist-info/METADATA,sha256=Ekro5D_Wg4htDTmM1NDJOE03Z9BSggoQEdHKSsv1DY8,7654
26
- hccinfhir-0.0.3.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
27
- hccinfhir-0.0.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
28
- hccinfhir-0.0.3.dist-info/RECORD,,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes