cehrbert-data 0.0.1__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.
- __init__.py +0 -0
- cehrbert_data/__init__.py +0 -0
- cehrbert_data/apps/__init__.py +0 -0
- cehrbert_data/apps/generate_concept_similarity_table.py +423 -0
- cehrbert_data/apps/generate_hierarchical_bert_training_data.py +238 -0
- cehrbert_data/apps/generate_included_concept_list.py +116 -0
- cehrbert_data/apps/generate_information_content.py +131 -0
- cehrbert_data/apps/generate_required_labs.py +112 -0
- cehrbert_data/apps/generate_training_data.py +337 -0
- cehrbert_data/cohorts/__init__.py +0 -0
- cehrbert_data/cohorts/atrial_fibrillation.py +45 -0
- cehrbert_data/cohorts/cabg.py +72 -0
- cehrbert_data/cohorts/coronary_artery_disease.py +84 -0
- cehrbert_data/cohorts/covid.py +43 -0
- cehrbert_data/cohorts/covid_inpatient.py +84 -0
- cehrbert_data/cohorts/death.py +46 -0
- cehrbert_data/cohorts/heart_failure.py +423 -0
- cehrbert_data/cohorts/ischemic_stroke.py +45 -0
- cehrbert_data/cohorts/last_visit_discharged_home.py +35 -0
- cehrbert_data/cohorts/query_builder.py +153 -0
- cehrbert_data/cohorts/spark_app_base.py +745 -0
- cehrbert_data/cohorts/type_two_diabietes.py +166 -0
- cehrbert_data/cohorts/ventilation.py +22 -0
- cehrbert_data/config/__init__.py +0 -0
- cehrbert_data/config/output_names.py +9 -0
- cehrbert_data/const/__init__.py +0 -0
- cehrbert_data/const/__pycache__/__init__.cpython-311.pyc +0 -0
- cehrbert_data/const/__pycache__/common.cpython-311.pyc +0 -0
- cehrbert_data/const/common.py +28 -0
- cehrbert_data/decorators/__init__.py +0 -0
- cehrbert_data/decorators/__pycache__/__init__.cpython-311.pyc +0 -0
- cehrbert_data/decorators/__pycache__/patient_event_decorator.cpython-311.pyc +0 -0
- cehrbert_data/decorators/patient_event_decorator.py +759 -0
- cehrbert_data/prediction_cohorts/__init__.py +0 -0
- cehrbert_data/prediction_cohorts/afib_ischemic_stroke.py +14 -0
- cehrbert_data/prediction_cohorts/cad_cabg_cohort.py +19 -0
- cehrbert_data/prediction_cohorts/cad_hf_cohort.py +14 -0
- cehrbert_data/prediction_cohorts/copd_readmission.py +76 -0
- cehrbert_data/prediction_cohorts/covid_death.py +14 -0
- cehrbert_data/prediction_cohorts/covid_ventilation.py +14 -0
- cehrbert_data/prediction_cohorts/discharge_home_death.py +18 -0
- cehrbert_data/prediction_cohorts/hf_readmission.py +82 -0
- cehrbert_data/prediction_cohorts/hospitalization.py +100 -0
- cehrbert_data/prediction_cohorts/hospitalization_mortality.py +77 -0
- cehrbert_data/prediction_cohorts/t2dm_hf_cohort.py +14 -0
- cehrbert_data/queries/__init__.py +0 -0
- cehrbert_data/queries/measurement_unit_stats_query.py +42 -0
- cehrbert_data/tools/__init__.py +0 -0
- cehrbert_data/tools/download_omop_tables.py +141 -0
- cehrbert_data/utils/__init__.py +0 -0
- cehrbert_data/utils/spark_parse_args.py +350 -0
- cehrbert_data/utils/spark_utils.py +1405 -0
- cehrbert_data-0.0.1.dist-info/LICENSE +21 -0
- cehrbert_data-0.0.1.dist-info/METADATA +116 -0
- cehrbert_data-0.0.1.dist-info/RECORD +57 -0
- cehrbert_data-0.0.1.dist-info/WHEEL +5 -0
- cehrbert_data-0.0.1.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
from cehrbert_data.cohorts.query_builder import (
|
|
2
|
+
AncestorTableSpec,
|
|
3
|
+
QueryBuilder,
|
|
4
|
+
QuerySpec,
|
|
5
|
+
create_cohort_entry_query_spec,
|
|
6
|
+
create_negative_query_spec,
|
|
7
|
+
)
|
|
8
|
+
from cehrbert_data.const.common import (
|
|
9
|
+
CONDITION_OCCURRENCE,
|
|
10
|
+
DRUG_EXPOSURE,
|
|
11
|
+
MEASUREMENT,
|
|
12
|
+
PERSON,
|
|
13
|
+
PROCEDURE_OCCURRENCE,
|
|
14
|
+
VISIT_OCCURRENCE,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# 1. Incidens of Heart Failure
|
|
18
|
+
HEART_FAILURE_CONCEPT = [316139]
|
|
19
|
+
|
|
20
|
+
# 2. At least one new or worsening symptoms due to HF
|
|
21
|
+
WORSEN_HF_DIAGNOSIS_CONCEPT = [312437, 4263848, 46272935, 4223659, 315361]
|
|
22
|
+
|
|
23
|
+
# 3. At least TWO physical examination findings OR one physical examination finding and at least
|
|
24
|
+
# ONE laboratory criterion
|
|
25
|
+
PHYSICAL_EXAM_CONCEPT = [433595, 200528, 4117930, 4329988, 4289004, 4285133]
|
|
26
|
+
## Lab result concept
|
|
27
|
+
# https://labtestsonline.org/tests/bnp-and-nt-probnp
|
|
28
|
+
BNP_CONCEPT = [
|
|
29
|
+
4307029,
|
|
30
|
+
3031569,
|
|
31
|
+
3011960,
|
|
32
|
+
3052295,
|
|
33
|
+
] # High B-type Natriuretic Peptide (BNP) > 500 pg/mL
|
|
34
|
+
NT_PRO_BNP_CONCEPT = [3029187, 42529224, 3029435, 42529225]
|
|
35
|
+
PWP_CONCEPT = [
|
|
36
|
+
1002721,
|
|
37
|
+
4040920,
|
|
38
|
+
21490776,
|
|
39
|
+
] # Pulmonary artery wedge pressure >= 18 no patient in cumc
|
|
40
|
+
CVP_CONCEPT = [
|
|
41
|
+
21490675,
|
|
42
|
+
4323687,
|
|
43
|
+
3000333,
|
|
44
|
+
1003995,
|
|
45
|
+
] # Central venous pressure >= 12 no patient in cumc
|
|
46
|
+
CI_CONCEPT = 21490712 # Cardiac index < 2.2 no patient in cumc
|
|
47
|
+
|
|
48
|
+
# 4. At least ONE of the treatments specifically for HF
|
|
49
|
+
DRUG_CONCEPT = [
|
|
50
|
+
956874,
|
|
51
|
+
942350,
|
|
52
|
+
987406,
|
|
53
|
+
932745,
|
|
54
|
+
1309799,
|
|
55
|
+
970250,
|
|
56
|
+
992590,
|
|
57
|
+
907013,
|
|
58
|
+
1942960,
|
|
59
|
+
]
|
|
60
|
+
MECHANICAL_CIRCULATORY_SUPPORT_CONCEPT = [
|
|
61
|
+
45888564,
|
|
62
|
+
4052536,
|
|
63
|
+
4337306,
|
|
64
|
+
2107514,
|
|
65
|
+
45889695,
|
|
66
|
+
2107500,
|
|
67
|
+
45887675,
|
|
68
|
+
43527920,
|
|
69
|
+
2107501,
|
|
70
|
+
45890116,
|
|
71
|
+
40756954,
|
|
72
|
+
4338594,
|
|
73
|
+
43527923,
|
|
74
|
+
40757060,
|
|
75
|
+
2100812,
|
|
76
|
+
]
|
|
77
|
+
DIALYSIS_CONCEPT = [4032243, 45889365]
|
|
78
|
+
ARTIFICIAL_HEART_ASSOCIATED_PROCEDURE_CONCEPT = [
|
|
79
|
+
4144390,
|
|
80
|
+
4150347,
|
|
81
|
+
4281764,
|
|
82
|
+
725038,
|
|
83
|
+
725037,
|
|
84
|
+
2100816,
|
|
85
|
+
2100822,
|
|
86
|
+
725039,
|
|
87
|
+
2100828,
|
|
88
|
+
4337306,
|
|
89
|
+
4140024,
|
|
90
|
+
4146121,
|
|
91
|
+
4060257,
|
|
92
|
+
4309033,
|
|
93
|
+
4222272,
|
|
94
|
+
4243758,
|
|
95
|
+
4241906,
|
|
96
|
+
4080968,
|
|
97
|
+
4224193,
|
|
98
|
+
4052537,
|
|
99
|
+
4050864,
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
DIURETIC_CONCEPT_ID = [4186999]
|
|
103
|
+
|
|
104
|
+
ROLL_UP_DIURETICS_TO_INGREDIENT_TEMPLATE = """
|
|
105
|
+
SELECT DISTINCT
|
|
106
|
+
c.*
|
|
107
|
+
FROM global_temp.diuretics_ancestor_table AS a
|
|
108
|
+
JOIN global_temp.concept_relationship AS cr
|
|
109
|
+
ON a.descendant_concept_id = cr.concept_id_1 AND cr.relationship_id = 'Maps to'
|
|
110
|
+
JOIN global_temp.concept_ancestor AS ca
|
|
111
|
+
ON cr.concept_id_2 = ca.descendant_concept_id
|
|
112
|
+
JOIN global_temp.concept AS c
|
|
113
|
+
ON ca.ancestor_concept_id = c.concept_id
|
|
114
|
+
WHERE c.concept_class_id = 'Ingredient'
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
HEART_FAILURE_ENTRY_COHORT = """
|
|
118
|
+
WITH hf_conditions AS (
|
|
119
|
+
SELECT
|
|
120
|
+
*
|
|
121
|
+
FROM global_temp.condition_occurrence AS co
|
|
122
|
+
JOIN global_temp.{hf_concept} AS hf
|
|
123
|
+
ON co.condition_concept_id = hf.concept_id
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
SELECT
|
|
127
|
+
c.person_id,
|
|
128
|
+
c.earliest_visit_start_date AS index_date,
|
|
129
|
+
c.earliest_visit_occurrence_id AS visit_occurrence_id,
|
|
130
|
+
COUNT(c.visit_occurrence_id) OVER(PARTITION BY c.person_id) AS num_of_diagnosis
|
|
131
|
+
FROM
|
|
132
|
+
(
|
|
133
|
+
SELECT DISTINCT
|
|
134
|
+
v.person_id,
|
|
135
|
+
v.visit_occurrence_id,
|
|
136
|
+
first(DATE(c.condition_start_date)) OVER (PARTITION BY v.person_id
|
|
137
|
+
ORDER BY DATE(c.condition_start_date)) AS earliest_condition_start_date,
|
|
138
|
+
first(DATE(v.visit_start_date)) OVER (PARTITION BY v.person_id
|
|
139
|
+
ORDER BY DATE(v.visit_start_date)) AS earliest_visit_start_date,
|
|
140
|
+
first(v.visit_occurrence_id) OVER (PARTITION BY v.person_id
|
|
141
|
+
ORDER BY DATE(v.visit_start_date)) AS earliest_visit_occurrence_id
|
|
142
|
+
FROM global_temp.visit_occurrence AS v
|
|
143
|
+
JOIN hf_conditions AS c
|
|
144
|
+
ON v.visit_occurrence_id = c.visit_occurrence_id
|
|
145
|
+
) c
|
|
146
|
+
WHERE c.earliest_visit_start_date <= c.earliest_condition_start_date
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
HEART_FAILURE_INTERMEDIATE_COHORT_QUERY = """
|
|
150
|
+
WITH hf_conditions AS (
|
|
151
|
+
SELECT
|
|
152
|
+
*
|
|
153
|
+
FROM global_temp.condition_occurrence AS co
|
|
154
|
+
JOIN global_temp.{hf_concept} AS hf
|
|
155
|
+
ON co.condition_concept_id = hf.concept_id
|
|
156
|
+
),
|
|
157
|
+
|
|
158
|
+
worsen_hf_diagnosis AS (
|
|
159
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
160
|
+
FROM global_temp.condition_occurrence AS co
|
|
161
|
+
JOIN global_temp.{worsen_hf_dx_concepts} AS w_hf
|
|
162
|
+
ON co.condition_concept_id = w_hf.concept_id
|
|
163
|
+
),
|
|
164
|
+
|
|
165
|
+
phy_exam_cohort AS (
|
|
166
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
167
|
+
FROM global_temp.condition_occurrence AS co
|
|
168
|
+
JOIN global_temp.{phy_exam_concepts} AS phy
|
|
169
|
+
ON co.condition_concept_id = phy.concept_id
|
|
170
|
+
),
|
|
171
|
+
|
|
172
|
+
bnp_cohort AS (
|
|
173
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
174
|
+
FROM global_temp.measurement AS m
|
|
175
|
+
JOIN global_temp.{bnp_concepts} AS bnp
|
|
176
|
+
ON m.measurement_concept_id = bnp.concept_id
|
|
177
|
+
AND m.value_source_value > 500
|
|
178
|
+
UNION ALL
|
|
179
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
180
|
+
FROM global_temp.measurement AS m
|
|
181
|
+
JOIN global_temp.{nt_pro_bnp_concepts} AS nt_bnp
|
|
182
|
+
ON m.measurement_concept_id = nt_bnp.concept_id
|
|
183
|
+
AND m.value_source_value > 2000
|
|
184
|
+
),
|
|
185
|
+
|
|
186
|
+
drug_concepts AS (
|
|
187
|
+
SELECT DISTINCT
|
|
188
|
+
*
|
|
189
|
+
FROM
|
|
190
|
+
(
|
|
191
|
+
SELECT *
|
|
192
|
+
FROM global_temp.{drug_concepts}
|
|
193
|
+
|
|
194
|
+
UNION
|
|
195
|
+
|
|
196
|
+
SELECT *
|
|
197
|
+
FROM global_temp.diuretics_concepts
|
|
198
|
+
) d
|
|
199
|
+
),
|
|
200
|
+
|
|
201
|
+
drug_cohort AS (
|
|
202
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
203
|
+
FROM global_temp.drug_exposure AS d
|
|
204
|
+
JOIN drug_concepts AS dc
|
|
205
|
+
ON d.drug_concept_id = dc.concept_id
|
|
206
|
+
),
|
|
207
|
+
|
|
208
|
+
mechanical_support_cohort AS (
|
|
209
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
210
|
+
FROM global_temp.procedure_occurrence AS p
|
|
211
|
+
JOIN global_temp.{mechanical_support_concepts} AS msc
|
|
212
|
+
ON p.procedure_concept_id = msc.concept_id
|
|
213
|
+
),
|
|
214
|
+
|
|
215
|
+
dialysis_cohort AS (
|
|
216
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
217
|
+
FROM global_temp.procedure_occurrence AS p
|
|
218
|
+
JOIN global_temp.{dialysis_concepts} AS dc
|
|
219
|
+
ON p.procedure_concept_id = dc.concept_id
|
|
220
|
+
),
|
|
221
|
+
|
|
222
|
+
artificial_heart_cohort AS (
|
|
223
|
+
SELECT DISTINCT person_id, visit_occurrence_id
|
|
224
|
+
FROM global_temp.procedure_occurrence AS p
|
|
225
|
+
JOIN global_temp.{artificial_heart_concepts} AS ahc
|
|
226
|
+
ON p.procedure_concept_id = ahc.concept_id
|
|
227
|
+
),
|
|
228
|
+
|
|
229
|
+
treatment_cohort AS (
|
|
230
|
+
-- SELECT * FROM drug_cohort
|
|
231
|
+
-- UNION ALL
|
|
232
|
+
SELECT * FROM mechanical_support_cohort
|
|
233
|
+
UNION ALL
|
|
234
|
+
SELECT * FROM dialysis_cohort
|
|
235
|
+
UNION ALL
|
|
236
|
+
SELECT * FROM artificial_heart_cohort
|
|
237
|
+
),
|
|
238
|
+
|
|
239
|
+
entry_cohort AS (
|
|
240
|
+
SELECT
|
|
241
|
+
c.person_id,
|
|
242
|
+
c.earliest_visit_start_date AS index_date,
|
|
243
|
+
c.earliest_visit_occurrence_id AS visit_occurrence_id,
|
|
244
|
+
COUNT(c.visit_occurrence_id) OVER(PARTITION BY c.person_id) AS num_of_diagnosis
|
|
245
|
+
FROM
|
|
246
|
+
(
|
|
247
|
+
SELECT DISTINCT
|
|
248
|
+
v.person_id,
|
|
249
|
+
v.visit_occurrence_id,
|
|
250
|
+
first(DATE(c.condition_start_date)) OVER (PARTITION BY v.person_id
|
|
251
|
+
ORDER BY DATE(c.condition_start_date)) AS earliest_condition_start_date,
|
|
252
|
+
first(DATE(v.visit_start_date)) OVER (PARTITION BY v.person_id
|
|
253
|
+
ORDER BY DATE(v.visit_start_date)) AS earliest_visit_start_date,
|
|
254
|
+
first(v.visit_occurrence_id) OVER (PARTITION BY v.person_id
|
|
255
|
+
ORDER BY DATE(v.visit_start_date)) AS earliest_visit_occurrence_id
|
|
256
|
+
FROM global_temp.visit_occurrence AS v
|
|
257
|
+
JOIN hf_conditions AS c
|
|
258
|
+
ON v.visit_occurrence_id = c.visit_occurrence_id
|
|
259
|
+
) c
|
|
260
|
+
WHERE c.earliest_visit_start_date <= c.earliest_condition_start_date
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
SELECT
|
|
264
|
+
c.*,
|
|
265
|
+
CAST(COALESCE(bnp.person_id, tc.person_id, dc.person_id) IS NOT NULL AS INT) AS inclusion
|
|
266
|
+
FROM entry_cohort AS c
|
|
267
|
+
LEFT JOIN (
|
|
268
|
+
SELECT DISTINCT person_id FROM bnp_cohort
|
|
269
|
+
) AS bnp
|
|
270
|
+
ON c.person_id = bnp.person_id
|
|
271
|
+
LEFT JOIN (
|
|
272
|
+
SELECT DISTINCT
|
|
273
|
+
person_id
|
|
274
|
+
FROM treatment_cohort
|
|
275
|
+
) AS tc
|
|
276
|
+
ON c.person_id = tc.person_id
|
|
277
|
+
LEFT JOIN (
|
|
278
|
+
SELECT DISTINCT
|
|
279
|
+
hf.person_id
|
|
280
|
+
FROM hf_conditions hf
|
|
281
|
+
JOIN drug_cohort dc
|
|
282
|
+
ON hf.visit_occurrence_id = dc.visit_occurrence_id
|
|
283
|
+
) AS dc
|
|
284
|
+
ON c.person_id = dc.person_id
|
|
285
|
+
"""
|
|
286
|
+
|
|
287
|
+
HEART_FAILURE_COHORT_QUERY = """
|
|
288
|
+
SELECT
|
|
289
|
+
person_id,
|
|
290
|
+
index_date,
|
|
291
|
+
visit_occurrence_id
|
|
292
|
+
FROM global_temp.{intermediate_heart_failure}
|
|
293
|
+
WHERE inclusion = {inclusion}
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
DEPENDENCY_LIST = [PERSON, VISIT_OCCURRENCE, CONDITION_OCCURRENCE, DRUG_EXPOSURE, PROCEDURE_OCCURRENCE, MEASUREMENT]
|
|
297
|
+
HEART_FAILURE_CONCEPT_TABLE = "hf_concept"
|
|
298
|
+
WORSEN_HF_DX_CONCEPT_TABLE = "worsen_hf_dx_concepts"
|
|
299
|
+
PHYSICAL_EXAM_COHORT_TABLE = "phy_exam_concepts"
|
|
300
|
+
BNP_CONCEPT_TABLE = "bnp_concepts"
|
|
301
|
+
NT_PRO_BNP_CONCEPT_TABLE = "nt_pro_bnp_concepts"
|
|
302
|
+
DRUG_CONCEPT_TABLE = "drug_concepts"
|
|
303
|
+
MECHANICAL_SUPPORT_CONCEPT_TABLE = "mechanical_support_concepts"
|
|
304
|
+
DIALYSIS_CONCEPT_TABLE = "dialysis_concepts"
|
|
305
|
+
ARTIFICIAL_HEART_CONCEPT_TABLE = "artificial_heart_concepts"
|
|
306
|
+
|
|
307
|
+
DIURETICS_ANCESTOR_TABLE = "diuretics_ancestor_table"
|
|
308
|
+
DIURETICS_INGREDIENT_CONCEPTS = "diuretics_concepts"
|
|
309
|
+
|
|
310
|
+
INTERMEDIATE_COHORT_NAME = "intermediate_heart_failure"
|
|
311
|
+
DEFAULT_COHORT_NAME = "heart_failure"
|
|
312
|
+
NEGATIVE_COHORT_NAME = "negative_heart_failure"
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def query_builder():
|
|
316
|
+
query = QuerySpec(
|
|
317
|
+
table_name=DEFAULT_COHORT_NAME,
|
|
318
|
+
query_template=HEART_FAILURE_COHORT_QUERY,
|
|
319
|
+
parameters={
|
|
320
|
+
"intermediate_heart_failure": INTERMEDIATE_COHORT_NAME,
|
|
321
|
+
"inclusion": 1,
|
|
322
|
+
},
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
ancestor_table_specs = [
|
|
326
|
+
AncestorTableSpec(
|
|
327
|
+
table_name=HEART_FAILURE_CONCEPT_TABLE,
|
|
328
|
+
ancestor_concept_ids=HEART_FAILURE_CONCEPT,
|
|
329
|
+
is_standard=True,
|
|
330
|
+
),
|
|
331
|
+
AncestorTableSpec(
|
|
332
|
+
table_name=WORSEN_HF_DX_CONCEPT_TABLE,
|
|
333
|
+
ancestor_concept_ids=WORSEN_HF_DIAGNOSIS_CONCEPT,
|
|
334
|
+
is_standard=True,
|
|
335
|
+
),
|
|
336
|
+
AncestorTableSpec(
|
|
337
|
+
table_name=PHYSICAL_EXAM_COHORT_TABLE,
|
|
338
|
+
ancestor_concept_ids=PHYSICAL_EXAM_CONCEPT,
|
|
339
|
+
is_standard=True,
|
|
340
|
+
),
|
|
341
|
+
AncestorTableSpec(
|
|
342
|
+
table_name=BNP_CONCEPT_TABLE,
|
|
343
|
+
ancestor_concept_ids=BNP_CONCEPT,
|
|
344
|
+
is_standard=True,
|
|
345
|
+
),
|
|
346
|
+
AncestorTableSpec(
|
|
347
|
+
table_name=NT_PRO_BNP_CONCEPT_TABLE,
|
|
348
|
+
ancestor_concept_ids=NT_PRO_BNP_CONCEPT,
|
|
349
|
+
is_standard=True,
|
|
350
|
+
),
|
|
351
|
+
AncestorTableSpec(
|
|
352
|
+
table_name=DRUG_CONCEPT_TABLE,
|
|
353
|
+
ancestor_concept_ids=DRUG_CONCEPT,
|
|
354
|
+
is_standard=True,
|
|
355
|
+
),
|
|
356
|
+
AncestorTableSpec(
|
|
357
|
+
table_name=MECHANICAL_SUPPORT_CONCEPT_TABLE,
|
|
358
|
+
ancestor_concept_ids=MECHANICAL_CIRCULATORY_SUPPORT_CONCEPT,
|
|
359
|
+
is_standard=True,
|
|
360
|
+
),
|
|
361
|
+
AncestorTableSpec(
|
|
362
|
+
table_name=DIALYSIS_CONCEPT_TABLE,
|
|
363
|
+
ancestor_concept_ids=DIALYSIS_CONCEPT,
|
|
364
|
+
is_standard=True,
|
|
365
|
+
),
|
|
366
|
+
AncestorTableSpec(
|
|
367
|
+
table_name=ARTIFICIAL_HEART_CONCEPT_TABLE,
|
|
368
|
+
ancestor_concept_ids=ARTIFICIAL_HEART_ASSOCIATED_PROCEDURE_CONCEPT,
|
|
369
|
+
is_standard=True,
|
|
370
|
+
),
|
|
371
|
+
AncestorTableSpec(
|
|
372
|
+
table_name=DIURETICS_ANCESTOR_TABLE,
|
|
373
|
+
ancestor_concept_ids=DIURETIC_CONCEPT_ID,
|
|
374
|
+
is_standard=False,
|
|
375
|
+
),
|
|
376
|
+
]
|
|
377
|
+
|
|
378
|
+
dependency_queries = [
|
|
379
|
+
QuerySpec(
|
|
380
|
+
table_name=DIURETICS_INGREDIENT_CONCEPTS,
|
|
381
|
+
query_template=ROLL_UP_DIURETICS_TO_INGREDIENT_TEMPLATE,
|
|
382
|
+
parameters={},
|
|
383
|
+
),
|
|
384
|
+
QuerySpec(
|
|
385
|
+
table_name=INTERMEDIATE_COHORT_NAME,
|
|
386
|
+
query_template=HEART_FAILURE_INTERMEDIATE_COHORT_QUERY,
|
|
387
|
+
parameters={
|
|
388
|
+
"hf_concept": HEART_FAILURE_CONCEPT_TABLE,
|
|
389
|
+
"worsen_hf_dx_concepts": WORSEN_HF_DX_CONCEPT_TABLE,
|
|
390
|
+
"phy_exam_concepts": PHYSICAL_EXAM_COHORT_TABLE,
|
|
391
|
+
"bnp_concepts": BNP_CONCEPT_TABLE,
|
|
392
|
+
"nt_pro_bnp_concepts": NT_PRO_BNP_CONCEPT_TABLE,
|
|
393
|
+
"drug_concepts": DRUG_CONCEPT_TABLE,
|
|
394
|
+
"mechanical_support_concepts": MECHANICAL_SUPPORT_CONCEPT_TABLE,
|
|
395
|
+
"dialysis_concepts": DIALYSIS_CONCEPT_TABLE,
|
|
396
|
+
"artificial_heart_concepts": ARTIFICIAL_HEART_CONCEPT_TABLE,
|
|
397
|
+
},
|
|
398
|
+
),
|
|
399
|
+
]
|
|
400
|
+
|
|
401
|
+
entry_cohort_query = create_cohort_entry_query_spec(
|
|
402
|
+
entry_query_template=HEART_FAILURE_ENTRY_COHORT,
|
|
403
|
+
parameters={"hf_concept": HEART_FAILURE_CONCEPT_TABLE},
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
negative_query = create_negative_query_spec(
|
|
407
|
+
entry_query_template=HEART_FAILURE_COHORT_QUERY,
|
|
408
|
+
parameters={
|
|
409
|
+
"intermediate_heart_failure": INTERMEDIATE_COHORT_NAME,
|
|
410
|
+
"inclusion": 0,
|
|
411
|
+
},
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
return QueryBuilder(
|
|
415
|
+
cohort_name=DEFAULT_COHORT_NAME,
|
|
416
|
+
query=query,
|
|
417
|
+
negative_query=negative_query,
|
|
418
|
+
entry_cohort_query=entry_cohort_query,
|
|
419
|
+
dependency_list=DEPENDENCY_LIST,
|
|
420
|
+
dependency_queries=dependency_queries,
|
|
421
|
+
post_queries=[],
|
|
422
|
+
ancestor_table_specs=ancestor_table_specs,
|
|
423
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from cehrbert_data.cohorts.query_builder import AncestorTableSpec, QueryBuilder, QuerySpec
|
|
2
|
+
from cehrbert_data.const.common import CONDITION_OCCURRENCE, PERSON, VISIT_OCCURRENCE
|
|
3
|
+
|
|
4
|
+
COHORT_QUERY_TEMPLATE = """
|
|
5
|
+
SELECT
|
|
6
|
+
co.person_id,
|
|
7
|
+
FIRST(DATE(vo.visit_start_date)) OVER (PARTITION BY co.person_id
|
|
8
|
+
ORDER BY DATE(vo.visit_start_date), vo.visit_occurrence_id) AS index_date,
|
|
9
|
+
FIRST(vo.visit_occurrence_id) OVER (PARTITION BY co.person_id
|
|
10
|
+
ORDER BY DATE(vo.visit_start_date), vo.visit_occurrence_id) AS visit_occurrence_id
|
|
11
|
+
FROM global_temp.condition_occurrence AS co
|
|
12
|
+
JOIN global_temp.visit_occurrence AS vo
|
|
13
|
+
ON co.visit_occurrence_id = vo.visit_occurrence_id
|
|
14
|
+
JOIN global_temp.{ischemic_stroke_concepts} AS c
|
|
15
|
+
ON co.condition_concept_id = c.concept_id
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
ISCHEMIC_STROKE_CONCEPT_ID = [443454]
|
|
19
|
+
|
|
20
|
+
DEPENDENCY_LIST = [PERSON, VISIT_OCCURRENCE, CONDITION_OCCURRENCE]
|
|
21
|
+
|
|
22
|
+
DEFAULT_COHORT_NAME = "ischemic_stroke"
|
|
23
|
+
ISCHEMIC_STROKE_CONCEPTS = "ischemic_stroke_concepts"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def query_builder():
|
|
27
|
+
query = QuerySpec(
|
|
28
|
+
table_name=DEFAULT_COHORT_NAME,
|
|
29
|
+
query_template=COHORT_QUERY_TEMPLATE,
|
|
30
|
+
parameters={"ischemic_stroke_concepts": ISCHEMIC_STROKE_CONCEPTS},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
ancestor_table_specs = [
|
|
34
|
+
AncestorTableSpec(
|
|
35
|
+
table_name=ISCHEMIC_STROKE_CONCEPTS,
|
|
36
|
+
ancestor_concept_ids=ISCHEMIC_STROKE_CONCEPT_ID,
|
|
37
|
+
is_standard=True,
|
|
38
|
+
)
|
|
39
|
+
]
|
|
40
|
+
return QueryBuilder(
|
|
41
|
+
cohort_name=DEFAULT_COHORT_NAME,
|
|
42
|
+
dependency_list=DEPENDENCY_LIST,
|
|
43
|
+
query=query,
|
|
44
|
+
ancestor_table_specs=ancestor_table_specs,
|
|
45
|
+
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from cehrbert_data.cohorts.query_builder import QueryBuilder, QuerySpec
|
|
2
|
+
from cehrbert_data.const.common import PERSON, VISIT_OCCURRENCE
|
|
3
|
+
|
|
4
|
+
COHORT_QUERY = """
|
|
5
|
+
SELECT DISTINCT
|
|
6
|
+
v.person_id,
|
|
7
|
+
v.visit_occurrence_id,
|
|
8
|
+
v.index_date
|
|
9
|
+
FROM
|
|
10
|
+
(
|
|
11
|
+
SELECT
|
|
12
|
+
v.person_id,
|
|
13
|
+
v.visit_occurrence_id,
|
|
14
|
+
v.visit_end_date AS index_date,
|
|
15
|
+
v.discharged_to_concept_id,
|
|
16
|
+
ROW_NUMBER() OVER(PARTITION BY v.person_id ORDER BY DATE(v.visit_end_date) DESC) AS rn
|
|
17
|
+
FROM global_temp.visit_occurrence AS v
|
|
18
|
+
WHERE v.visit_concept_id IN (9201, 262) --inpatient, er-inpatient
|
|
19
|
+
AND v.visit_end_date IS NOT NULL
|
|
20
|
+
AND v.discharged_to_concept_id = 8536 --discharge to home
|
|
21
|
+
) AS v
|
|
22
|
+
WHERE v.rn = 1 AND v.index_date >= '{date_lower_bound}'
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
DEPENDENCY_LIST = [PERSON, VISIT_OCCURRENCE]
|
|
26
|
+
DEFAULT_COHORT_NAME = "last_visit_discharge_home"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def query_builder(spark_args):
|
|
30
|
+
query = QuerySpec(
|
|
31
|
+
table_name=DEFAULT_COHORT_NAME,
|
|
32
|
+
query_template=COHORT_QUERY,
|
|
33
|
+
parameters={"date_lower_bound": spark_args.date_lower_bound},
|
|
34
|
+
)
|
|
35
|
+
return QueryBuilder(cohort_name=DEFAULT_COHORT_NAME, dependency_list=DEPENDENCY_LIST, query=query)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from abc import ABC
|
|
3
|
+
from typing import List, NamedTuple
|
|
4
|
+
|
|
5
|
+
ENTRY_COHORT = "entry_cohort"
|
|
6
|
+
NEGATIVE_COHORT = "negative_cohort"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def create_cohort_entry_query_spec(entry_query_template, parameters):
|
|
10
|
+
return QuerySpec(
|
|
11
|
+
table_name=ENTRY_COHORT,
|
|
12
|
+
query_template=entry_query_template,
|
|
13
|
+
parameters=parameters,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_negative_query_spec(entry_query_template, parameters):
|
|
18
|
+
return QuerySpec(
|
|
19
|
+
table_name=NEGATIVE_COHORT,
|
|
20
|
+
query_template=entry_query_template,
|
|
21
|
+
parameters=parameters,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class QuerySpec(NamedTuple):
|
|
26
|
+
query_template: str
|
|
27
|
+
parameters: dict
|
|
28
|
+
table_name: str
|
|
29
|
+
|
|
30
|
+
def __str__(self):
|
|
31
|
+
return f"table={self.table_name}\n" f"query={self.query_template.format(**self.parameters)}\n"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AncestorTableSpec(NamedTuple):
|
|
35
|
+
ancestor_concept_ids: List[int]
|
|
36
|
+
table_name: str
|
|
37
|
+
is_standard: bool
|
|
38
|
+
|
|
39
|
+
def __str__(self):
|
|
40
|
+
return (
|
|
41
|
+
f"table_name={self.table_name}\n"
|
|
42
|
+
f"ancestor_concept_ids={self.ancestor_concept_ids}\n"
|
|
43
|
+
f"is_standard={self.is_standard}\n"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class QueryBuilder(ABC):
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
cohort_name: str,
|
|
52
|
+
dependency_list: List[str],
|
|
53
|
+
query: QuerySpec,
|
|
54
|
+
negative_query: QuerySpec = None,
|
|
55
|
+
entry_cohort_query: QuerySpec = None,
|
|
56
|
+
dependency_queries: List[QuerySpec] = None,
|
|
57
|
+
post_queries: List[QuerySpec] = None,
|
|
58
|
+
ancestor_table_specs: List[AncestorTableSpec] = None,
|
|
59
|
+
):
|
|
60
|
+
"""
|
|
61
|
+
:param cohort_name:
|
|
62
|
+
|
|
63
|
+
:param query:
|
|
64
|
+
:param dependency_queries:
|
|
65
|
+
:param post_queries:
|
|
66
|
+
:param dependency_list:
|
|
67
|
+
:param ancestor_table_specs:
|
|
68
|
+
"""
|
|
69
|
+
self._cohort_name = cohort_name
|
|
70
|
+
self._query = query
|
|
71
|
+
self._negative_query = negative_query
|
|
72
|
+
self._entry_cohort_query = entry_cohort_query
|
|
73
|
+
self._dependency_queries = dependency_queries
|
|
74
|
+
self._post_queries = post_queries
|
|
75
|
+
self._dependency_list = dependency_list
|
|
76
|
+
self._ancestor_table_specs = ancestor_table_specs
|
|
77
|
+
|
|
78
|
+
self.get_logger().info(
|
|
79
|
+
f"cohort_name: {cohort_name}\n"
|
|
80
|
+
f"post_queries: {post_queries}\n"
|
|
81
|
+
f"entry_cohort: {entry_cohort_query}\n"
|
|
82
|
+
f"dependency_queries: {dependency_queries}\n"
|
|
83
|
+
f"dependency_list: {dependency_list}\n"
|
|
84
|
+
f"ancestor_table_specs: {ancestor_table_specs}\n"
|
|
85
|
+
f"query: {query}\n"
|
|
86
|
+
f"negative_query: {negative_query}\n"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def get_dependency_queries(self):
|
|
90
|
+
"""
|
|
91
|
+
Instantiate table dependencies in spark for.
|
|
92
|
+
|
|
93
|
+
:return:
|
|
94
|
+
"""
|
|
95
|
+
return self._dependency_queries
|
|
96
|
+
|
|
97
|
+
def get_entry_cohort_query(self):
|
|
98
|
+
"""
|
|
99
|
+
Queryspec for Instantiating the entry cohort in spark context.
|
|
100
|
+
|
|
101
|
+
:return:
|
|
102
|
+
"""
|
|
103
|
+
return self._entry_cohort_query
|
|
104
|
+
|
|
105
|
+
def get_query(self):
|
|
106
|
+
"""
|
|
107
|
+
Create a query that can be executed by spark.sql.
|
|
108
|
+
|
|
109
|
+
:return:
|
|
110
|
+
"""
|
|
111
|
+
return self._query
|
|
112
|
+
|
|
113
|
+
def get_negative_query(self):
|
|
114
|
+
"""
|
|
115
|
+
Return the negative query that can be executed by spark.sql.
|
|
116
|
+
|
|
117
|
+
:return:
|
|
118
|
+
"""
|
|
119
|
+
return self._negative_query
|
|
120
|
+
|
|
121
|
+
def get_post_process_queries(self):
|
|
122
|
+
"""
|
|
123
|
+
Get a list of post process queries to process the cohort.
|
|
124
|
+
|
|
125
|
+
:return:
|
|
126
|
+
"""
|
|
127
|
+
return self._post_queries
|
|
128
|
+
|
|
129
|
+
def get_dependency_list(self):
|
|
130
|
+
"""
|
|
131
|
+
Get a list of tables that are required for this cohort.
|
|
132
|
+
|
|
133
|
+
:return:
|
|
134
|
+
"""
|
|
135
|
+
return self._dependency_list
|
|
136
|
+
|
|
137
|
+
def get_cohort_name(self):
|
|
138
|
+
return self._cohort_name
|
|
139
|
+
|
|
140
|
+
def get_ancestor_table_specs(self):
|
|
141
|
+
"""
|
|
142
|
+
Create the descendant table for the provided ancestor_table_specs.
|
|
143
|
+
|
|
144
|
+
:return:
|
|
145
|
+
"""
|
|
146
|
+
return self._ancestor_table_specs
|
|
147
|
+
|
|
148
|
+
def __str__(self):
|
|
149
|
+
return f"{str(self.__class__.__name__)} for {self.get_cohort_name()}"
|
|
150
|
+
|
|
151
|
+
@classmethod
|
|
152
|
+
def get_logger(cls):
|
|
153
|
+
return logging.getLogger(cls.__name__)
|