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.
Files changed (57) hide show
  1. __init__.py +0 -0
  2. cehrbert_data/__init__.py +0 -0
  3. cehrbert_data/apps/__init__.py +0 -0
  4. cehrbert_data/apps/generate_concept_similarity_table.py +423 -0
  5. cehrbert_data/apps/generate_hierarchical_bert_training_data.py +238 -0
  6. cehrbert_data/apps/generate_included_concept_list.py +116 -0
  7. cehrbert_data/apps/generate_information_content.py +131 -0
  8. cehrbert_data/apps/generate_required_labs.py +112 -0
  9. cehrbert_data/apps/generate_training_data.py +337 -0
  10. cehrbert_data/cohorts/__init__.py +0 -0
  11. cehrbert_data/cohorts/atrial_fibrillation.py +45 -0
  12. cehrbert_data/cohorts/cabg.py +72 -0
  13. cehrbert_data/cohorts/coronary_artery_disease.py +84 -0
  14. cehrbert_data/cohorts/covid.py +43 -0
  15. cehrbert_data/cohorts/covid_inpatient.py +84 -0
  16. cehrbert_data/cohorts/death.py +46 -0
  17. cehrbert_data/cohorts/heart_failure.py +423 -0
  18. cehrbert_data/cohorts/ischemic_stroke.py +45 -0
  19. cehrbert_data/cohorts/last_visit_discharged_home.py +35 -0
  20. cehrbert_data/cohorts/query_builder.py +153 -0
  21. cehrbert_data/cohorts/spark_app_base.py +745 -0
  22. cehrbert_data/cohorts/type_two_diabietes.py +166 -0
  23. cehrbert_data/cohorts/ventilation.py +22 -0
  24. cehrbert_data/config/__init__.py +0 -0
  25. cehrbert_data/config/output_names.py +9 -0
  26. cehrbert_data/const/__init__.py +0 -0
  27. cehrbert_data/const/__pycache__/__init__.cpython-311.pyc +0 -0
  28. cehrbert_data/const/__pycache__/common.cpython-311.pyc +0 -0
  29. cehrbert_data/const/common.py +28 -0
  30. cehrbert_data/decorators/__init__.py +0 -0
  31. cehrbert_data/decorators/__pycache__/__init__.cpython-311.pyc +0 -0
  32. cehrbert_data/decorators/__pycache__/patient_event_decorator.cpython-311.pyc +0 -0
  33. cehrbert_data/decorators/patient_event_decorator.py +759 -0
  34. cehrbert_data/prediction_cohorts/__init__.py +0 -0
  35. cehrbert_data/prediction_cohorts/afib_ischemic_stroke.py +14 -0
  36. cehrbert_data/prediction_cohorts/cad_cabg_cohort.py +19 -0
  37. cehrbert_data/prediction_cohorts/cad_hf_cohort.py +14 -0
  38. cehrbert_data/prediction_cohorts/copd_readmission.py +76 -0
  39. cehrbert_data/prediction_cohorts/covid_death.py +14 -0
  40. cehrbert_data/prediction_cohorts/covid_ventilation.py +14 -0
  41. cehrbert_data/prediction_cohorts/discharge_home_death.py +18 -0
  42. cehrbert_data/prediction_cohorts/hf_readmission.py +82 -0
  43. cehrbert_data/prediction_cohorts/hospitalization.py +100 -0
  44. cehrbert_data/prediction_cohorts/hospitalization_mortality.py +77 -0
  45. cehrbert_data/prediction_cohorts/t2dm_hf_cohort.py +14 -0
  46. cehrbert_data/queries/__init__.py +0 -0
  47. cehrbert_data/queries/measurement_unit_stats_query.py +42 -0
  48. cehrbert_data/tools/__init__.py +0 -0
  49. cehrbert_data/tools/download_omop_tables.py +141 -0
  50. cehrbert_data/utils/__init__.py +0 -0
  51. cehrbert_data/utils/spark_parse_args.py +350 -0
  52. cehrbert_data/utils/spark_utils.py +1405 -0
  53. cehrbert_data-0.0.1.dist-info/LICENSE +21 -0
  54. cehrbert_data-0.0.1.dist-info/METADATA +116 -0
  55. cehrbert_data-0.0.1.dist-info/RECORD +57 -0
  56. cehrbert_data-0.0.1.dist-info/WHEEL +5 -0
  57. 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__)