cehrbert-data 0.0.4__tar.gz → 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/.github/workflows/python-build.yml +2 -2
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/.github/workflows/tests.yml +5 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/PKG-INFO +2 -2
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_training_data.py +22 -2
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/spark_app_base.py +76 -30
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/artificial_time_token_decorator.py +100 -32
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/clinical_event_decorator.py +45 -36
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/death_event_decorator.py +17 -10
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/demographic_event_decorator.py +38 -8
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/patient_event_decorator_base.py +26 -2
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/token_priority.py +1 -0
- cehrbert_data-0.0.5/src/cehrbert_data/tools/connect_omop_visit.py +288 -0
- cehrbert_data-0.0.5/src/cehrbert_data/tools/ehrshot_to_omop.py +952 -0
- cehrbert_data-0.0.5/src/cehrbert_data/tools/extract_features.py +302 -0
- cehrbert_data-0.0.5/src/cehrbert_data/tools/prepare_ehrshot_cohorts.py +22 -0
- cehrbert_data-0.0.5/src/cehrbert_data/tools/update_omop_visit.py +60 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/utils/spark_parse_args.py +28 -2
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/utils/spark_utils.py +85 -41
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data.egg-info/PKG-INFO +2 -2
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data.egg-info/SOURCES.txt +7 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/integration_tests/test_generate_training_data.py +2 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/integration_tests/test_hf_readmission.py +2 -0
- cehrbert_data-0.0.5/tests/integration_tests/test_hf_readmission_cohort_meds.py +43 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/pyspark_test_base.py +12 -2
- cehrbert_data-0.0.5/tests/unit_tests/test_ehrshot_to_omop.py +353 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/.gitignore +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/.pre-commit-config.yaml +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/LICENSE +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/README.md +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/pyproject.toml +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/.part-00000-4b12270c-f6c8-4b59-8e0f-fd588bd79386-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/.part-00003-4b12270c-f6c8-4b59-8e0f-fd588bd79386-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/.part-00010-4b12270c-f6c8-4b59-8e0f-fd588bd79386-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/part-00000-4b12270c-f6c8-4b59-8e0f-fd588bd79386-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/part-00003-4b12270c-f6c8-4b59-8e0f-fd588bd79386-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept/part-00010-4b12270c-f6c8-4b59-8e0f-fd588bd79386-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/.part-00000-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/.part-00002-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/.part-00006-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/.part-00011-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/.part-00013-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/part-00000-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/part-00002-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/part-00006-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/part-00011-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_ancestor/part-00013-eafbd8be-3337-46da-89d3-20f79c2565d4-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/.part-00000-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/.part-00002-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/.part-00007-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/.part-00012-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/part-00000-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/part-00002-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/part-00007-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/concept_relationship/part-00012-5752b472-8ba7-4189-ab69-8c92e46443aa-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/condition_occurrence/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/condition_occurrence/.part-00000-4eff03a1-cdcf-4c89-b0cd-9ce590b9b1eb-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/condition_occurrence/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/condition_occurrence/part-00000-4eff03a1-cdcf-4c89-b0cd-9ce590b9b1eb-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/drug_exposure/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/drug_exposure/.part-00000-10bbf1a4-a7da-416e-9703-58609c7edfad-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/drug_exposure/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/drug_exposure/part-00000-10bbf1a4-a7da-416e-9703-58609c7edfad-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/observation_period/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/observation_period/.part-00000-694316e5-cc95-49f1-9fad-5a7f377e2602-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/observation_period/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/observation_period/part-00000-694316e5-cc95-49f1-9fad-5a7f377e2602-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/person/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/person/.part-00000-7d789011-f361-48da-af6f-cfe102978b3a-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/person/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/person/part-00000-7d789011-f361-48da-af6f-cfe102978b3a-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/procedure_occurrence/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/procedure_occurrence/.part-00000-e73003c1-aed5-41c0-b2d4-eaccaccf044a-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/procedure_occurrence/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/procedure_occurrence/part-00000-e73003c1-aed5-41c0-b2d4-eaccaccf044a-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/visit_occurrence/._SUCCESS.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/visit_occurrence/.part-00000-e874b5f1-bf9e-4cb9-93bf-c309a47b0476-c000.snappy.parquet.crc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/visit_occurrence/_SUCCESS +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/sample_data/omop_sample/visit_occurrence/part-00000-e874b5f1-bf9e-4cb9-93bf-c309a47b0476-c000.snappy.parquet +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/setup.cfg +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_concept_similarity_table.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_hierarchical_bert_training_data.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_included_concept_list.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_information_content.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_required_labs.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/atrial_fibrillation.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/cabg.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/coronary_artery_disease.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/covid.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/covid_inpatient.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/death.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/heart_failure.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/ischemic_stroke.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/last_visit_discharged_home.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/query_builder.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/type_two_diabietes.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/cohorts/ventilation.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/config/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/config/output_names.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/const/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/const/__pycache__/__init__.cpython-311.pyc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/const/__pycache__/common.cpython-311.pyc +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/const/artificial_tokens.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/const/common.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/decorators/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/afib_ischemic_stroke.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/cad_cabg_cohort.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/cad_hf_cohort.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/copd_readmission.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/covid_death.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/covid_ventilation.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/discharge_home_death.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/hf_readmission.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/hospitalization.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/hospitalization_mortality.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/prediction_cohorts/t2dm_hf_cohort.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/queries/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/queries/measurement_queries.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/tools/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/tools/download_omop_tables.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/utils/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/utils/logging_utils.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data.egg-info/dependency_links.txt +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data.egg-info/requires.txt +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data.egg-info/top_level.txt +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/integration_tests/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/unit_tests/__init__.py +0 -0
- {cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/tests/unit_tests/test_spark_utils.py +0 -0
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
name: python-package-distributions
|
|
69
69
|
path: dist/
|
|
70
70
|
- name: Sign the dists with Sigstore
|
|
71
|
-
uses: sigstore/gh-action-sigstore-python@
|
|
71
|
+
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
|
72
72
|
with:
|
|
73
73
|
inputs: >-
|
|
74
74
|
./dist/*.tar.gz
|
|
@@ -90,4 +90,4 @@ jobs:
|
|
|
90
90
|
run: >-
|
|
91
91
|
gh release upload
|
|
92
92
|
'${{ github.ref_name }}' dist/**
|
|
93
|
-
--repo '${{ github.repository }}'
|
|
93
|
+
--repo '${{ github.repository }}'
|
|
@@ -23,6 +23,11 @@ jobs:
|
|
|
23
23
|
uses: actions/setup-python@v3
|
|
24
24
|
with:
|
|
25
25
|
python-version: "3.10"
|
|
26
|
+
- name: Set up Java 11
|
|
27
|
+
uses: actions/setup-java@v3
|
|
28
|
+
with:
|
|
29
|
+
java-version: "11" # specify the Java version here
|
|
30
|
+
distribution: "temurin" # or use 'adopt' or 'zulu', depending on your preference
|
|
26
31
|
- name: Install dependencies
|
|
27
32
|
run: |
|
|
28
33
|
python -m pip install --upgrade pip
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: cehrbert_data
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: The Spark ETL tools for generating the CEHR-BERT and CEHR-GPT pre-training and finetuning data
|
|
5
5
|
Author-email: Chao Pang <chaopang229@gmail.com>, Xinzhuo Jiang <xj2193@cumc.columbia.edu>, Krishna Kalluri <kk3326@cumc.columbia.edu>, Nishanth Parameshwar Pavinkurve <np2689@cumc.columbia.edu>, Karthik Natarajan <kn2174@cumc.columbia.edu>
|
|
6
6
|
License: MIT License
|
{cehrbert_data-0.0.4 → cehrbert_data-0.0.5}/src/cehrbert_data/apps/generate_training_data.py
RENAMED
|
@@ -41,13 +41,15 @@ def main(
|
|
|
41
41
|
apply_age_filter: bool,
|
|
42
42
|
include_death: bool,
|
|
43
43
|
att_type: AttType,
|
|
44
|
+
inpatient_att_type: AttType,
|
|
44
45
|
include_sequence_information_content: bool = False,
|
|
45
46
|
exclude_demographic: bool = False,
|
|
46
47
|
use_age_group: bool = False,
|
|
47
48
|
with_drug_rollup: bool = True,
|
|
48
49
|
include_inpatient_hour_token: bool = False,
|
|
49
50
|
continue_from_events: bool = False,
|
|
50
|
-
refresh_measurement: bool = False
|
|
51
|
+
refresh_measurement: bool = False,
|
|
52
|
+
aggregate_by_hour: bool = True,
|
|
51
53
|
):
|
|
52
54
|
spark = SparkSession.builder.appName("Generate CEHR-BERT Training Data").getOrCreate()
|
|
53
55
|
|
|
@@ -71,6 +73,7 @@ def main(
|
|
|
71
73
|
f"use_age_group: {use_age_group}\n"
|
|
72
74
|
f"with_drug_rollup: {with_drug_rollup}\n"
|
|
73
75
|
f"refresh_measurement: {refresh_measurement}\n"
|
|
76
|
+
f"aggregate_by_hour: {aggregate_by_hour}\n"
|
|
74
77
|
)
|
|
75
78
|
|
|
76
79
|
domain_tables = []
|
|
@@ -128,7 +131,8 @@ def main(
|
|
|
128
131
|
processed_measurement = get_measurement_table(
|
|
129
132
|
spark,
|
|
130
133
|
input_folder,
|
|
131
|
-
refresh=refresh_measurement
|
|
134
|
+
refresh=refresh_measurement,
|
|
135
|
+
aggregate_by_hour=aggregate_by_hour,
|
|
132
136
|
)
|
|
133
137
|
if patient_events:
|
|
134
138
|
# Union all measurement records together with other domain records
|
|
@@ -165,9 +169,12 @@ def main(
|
|
|
165
169
|
patient_demographic=person if gpt_patient_sequence else None,
|
|
166
170
|
death=death,
|
|
167
171
|
att_type=att_type,
|
|
172
|
+
inpatient_att_type=inpatient_att_type,
|
|
168
173
|
exclude_demographic=exclude_demographic,
|
|
169
174
|
use_age_group=use_age_group,
|
|
170
175
|
include_inpatient_hour_token=include_inpatient_hour_token,
|
|
176
|
+
spark=spark,
|
|
177
|
+
persistence_folder=output_folder,
|
|
171
178
|
)
|
|
172
179
|
else:
|
|
173
180
|
sequence_data = create_sequence_data(
|
|
@@ -325,12 +332,23 @@ if __name__ == "__main__":
|
|
|
325
332
|
dest="refresh_measurement",
|
|
326
333
|
action="store_true"
|
|
327
334
|
)
|
|
335
|
+
parser.add_argument(
|
|
336
|
+
"--aggregate_by_hour",
|
|
337
|
+
dest="aggregate_by_hour",
|
|
338
|
+
action="store_true"
|
|
339
|
+
)
|
|
328
340
|
parser.add_argument(
|
|
329
341
|
"--att_type",
|
|
330
342
|
dest="att_type",
|
|
331
343
|
action="store",
|
|
332
344
|
choices=[e.value for e in AttType],
|
|
333
345
|
)
|
|
346
|
+
parser.add_argument(
|
|
347
|
+
"--inpatient_att_type",
|
|
348
|
+
dest="inpatient_att_type",
|
|
349
|
+
action="store",
|
|
350
|
+
choices=[e.value for e in AttType],
|
|
351
|
+
)
|
|
334
352
|
|
|
335
353
|
ARGS = parser.parse_args()
|
|
336
354
|
|
|
@@ -352,10 +370,12 @@ if __name__ == "__main__":
|
|
|
352
370
|
ARGS.apply_age_filter,
|
|
353
371
|
ARGS.include_death,
|
|
354
372
|
AttType(ARGS.att_type),
|
|
373
|
+
AttType(ARGS.inpatient_att_type),
|
|
355
374
|
exclude_demographic=ARGS.exclude_demographic,
|
|
356
375
|
use_age_group=ARGS.use_age_group,
|
|
357
376
|
with_drug_rollup=ARGS.with_drug_rollup,
|
|
358
377
|
include_inpatient_hour_token=ARGS.include_inpatient_hour_token,
|
|
359
378
|
continue_from_events=ARGS.continue_from_events,
|
|
360
379
|
refresh_measurement=ARGS.refresh_measurement,
|
|
380
|
+
aggregate_by_hour=ARGS.aggregate_by_hour,
|
|
361
381
|
)
|
|
@@ -295,6 +295,7 @@ class NestedCohortBuilder:
|
|
|
295
295
|
is_drug_roll_up_concept: bool = True,
|
|
296
296
|
include_concept_list: bool = True,
|
|
297
297
|
refresh_measurement: bool = False,
|
|
298
|
+
aggregate_by_hour: bool = True,
|
|
298
299
|
is_new_patient_representation: bool = False,
|
|
299
300
|
gpt_patient_sequence: bool = False,
|
|
300
301
|
is_hierarchical_bert: bool = False,
|
|
@@ -306,9 +307,12 @@ class NestedCohortBuilder:
|
|
|
306
307
|
is_observation_window_unbounded: bool = False,
|
|
307
308
|
is_population_estimation: bool = False,
|
|
308
309
|
att_type: AttType = AttType.CEHR_BERT,
|
|
310
|
+
inpatient_att_type: AttType = AttType.MIX,
|
|
309
311
|
exclude_demographic: bool = True,
|
|
310
312
|
use_age_group: bool = False,
|
|
311
313
|
single_contribution: bool = False,
|
|
314
|
+
exclude_features: bool = True,
|
|
315
|
+
meds_format: bool = False,
|
|
312
316
|
):
|
|
313
317
|
self._cohort_name = cohort_name
|
|
314
318
|
self._input_folder = input_folder
|
|
@@ -340,15 +344,19 @@ class NestedCohortBuilder:
|
|
|
340
344
|
self._is_prediction_window_unbounded = is_prediction_window_unbounded
|
|
341
345
|
self._include_concept_list = include_concept_list
|
|
342
346
|
self._refresh_measurement = refresh_measurement
|
|
347
|
+
self._aggregate_by_hour = aggregate_by_hour
|
|
343
348
|
self._allow_measurement_only = allow_measurement_only
|
|
344
349
|
self._output_data_folder = os.path.join(
|
|
345
350
|
self._output_folder, re.sub("[^a-z0-9]+", "_", self._cohort_name.lower())
|
|
346
351
|
)
|
|
347
352
|
self._is_population_estimation = is_population_estimation
|
|
348
353
|
self._att_type = att_type
|
|
354
|
+
self._inpatient_att_type = inpatient_att_type
|
|
349
355
|
self._exclude_demographic = exclude_demographic
|
|
350
356
|
self._use_age_group = use_age_group
|
|
351
357
|
self._single_contribution = single_contribution
|
|
358
|
+
self._exclude_features = exclude_features
|
|
359
|
+
self._meds_format = meds_format
|
|
352
360
|
|
|
353
361
|
self.get_logger().info(
|
|
354
362
|
f"cohort_name: {cohort_name}\n"
|
|
@@ -377,12 +385,16 @@ class NestedCohortBuilder:
|
|
|
377
385
|
f"is_prediction_window_unbounded: {is_prediction_window_unbounded}\n"
|
|
378
386
|
f"include_concept_list: {include_concept_list}\n"
|
|
379
387
|
f"refresh_measurement: {refresh_measurement}\n"
|
|
388
|
+
f"aggregate_by_hour: {aggregate_by_hour}\n"
|
|
380
389
|
f"is_observation_window_unbounded: {is_observation_window_unbounded}\n"
|
|
381
390
|
f"is_population_estimation: {is_population_estimation}\n"
|
|
382
391
|
f"att_type: {att_type}\n"
|
|
392
|
+
f"inpatient_att_type: {inpatient_att_type}\n"
|
|
383
393
|
f"exclude_demographic: {exclude_demographic}\n"
|
|
384
394
|
f"use_age_group: {use_age_group}\n"
|
|
385
395
|
f"single_contribution: {single_contribution}\n"
|
|
396
|
+
f"extract_features: {exclude_features}\n"
|
|
397
|
+
f"meds_format: {meds_format}\n"
|
|
386
398
|
)
|
|
387
399
|
|
|
388
400
|
self.spark = SparkSession.builder.appName(f"Generate {self._cohort_name}").getOrCreate()
|
|
@@ -508,13 +520,30 @@ class NestedCohortBuilder:
|
|
|
508
520
|
)
|
|
509
521
|
cohort = cohort.withColumn("record_rank", record_rank).where("record_rank == 1").drop("record_rank")
|
|
510
522
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
523
|
+
if not self._exclude_features:
|
|
524
|
+
ehr_records_for_cohorts = self.extract_ehr_records_for_cohort(cohort)
|
|
525
|
+
cohort = (
|
|
526
|
+
cohort.join(ehr_records_for_cohorts, ["person_id", "cohort_member_id"])
|
|
527
|
+
.where(F.col("num_of_visits") >= self._num_of_visits)
|
|
528
|
+
.where(F.col("num_of_concepts") >= self._num_of_concepts)
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
person_id_column = "person_id"
|
|
532
|
+
index_date_column = "index_date"
|
|
533
|
+
if self._meds_format:
|
|
534
|
+
cohort = cohort.withColumnRenamed(
|
|
535
|
+
"person_id", "subject_id"
|
|
536
|
+
).withColumnRenamed(
|
|
537
|
+
"index_date", "prediction_time"
|
|
538
|
+
).withColumnRenamed(
|
|
539
|
+
"label", "boolean_value"
|
|
540
|
+
).withColumn(
|
|
541
|
+
"prediction_time", F.to_timestamp("prediction_time")
|
|
542
|
+
).withColumn(
|
|
543
|
+
"boolean_value", F.col("boolean_value").cast("boolean")
|
|
544
|
+
)
|
|
545
|
+
person_id_column = "subject_id"
|
|
546
|
+
index_date_column = "prediction_time"
|
|
518
547
|
|
|
519
548
|
if self._is_prediction_window_unbounded:
|
|
520
549
|
observation_period = self._dependency_dict[OBSERVATION_PERIOD]
|
|
@@ -529,9 +558,14 @@ class NestedCohortBuilder:
|
|
|
529
558
|
# Add time_to_event
|
|
530
559
|
cohort = cohort.withColumn(
|
|
531
560
|
"study_end_date",
|
|
532
|
-
F.coalesce(
|
|
561
|
+
F.coalesce(
|
|
562
|
+
F.col("outcome_date"),
|
|
563
|
+
F.date_add(
|
|
564
|
+
cohort[index_date_column], self._prediction_window
|
|
565
|
+
)
|
|
566
|
+
)
|
|
533
567
|
)
|
|
534
|
-
cohort = cohort.withColumn("time_to_event", F.datediff("study_end_date",
|
|
568
|
+
cohort = cohort.withColumn("time_to_event", F.datediff("study_end_date", index_date_column))
|
|
535
569
|
|
|
536
570
|
# if patient_splits is provided, we will
|
|
537
571
|
if self._patient_splits_folder:
|
|
@@ -547,7 +581,7 @@ class NestedCohortBuilder:
|
|
|
547
581
|
cohort.where('split="test"').write.mode("overwrite").parquet(os.path.join(self._output_data_folder, "test"))
|
|
548
582
|
shutil.rmtree(os.path.join(self._output_data_folder, "temp"))
|
|
549
583
|
else:
|
|
550
|
-
cohort.orderBy(
|
|
584
|
+
cohort.orderBy(person_id_column, index_date_column).write.mode("overwrite").parquet(self._output_data_folder)
|
|
551
585
|
|
|
552
586
|
def extract_ehr_records_for_cohort(self, cohort: DataFrame):
|
|
553
587
|
"""
|
|
@@ -566,47 +600,54 @@ class NestedCohortBuilder:
|
|
|
566
600
|
with_drug_rollup=self._is_drug_roll_up_concept,
|
|
567
601
|
include_concept_list=self._include_concept_list,
|
|
568
602
|
refresh_measurement=self._refresh_measurement,
|
|
603
|
+
aggregate_by_hour=self._aggregate_by_hour,
|
|
569
604
|
)
|
|
570
605
|
|
|
571
606
|
# Duplicate the records for cohorts that allow multiple entries
|
|
572
|
-
ehr_records = ehr_records.
|
|
573
|
-
|
|
574
|
-
)
|
|
607
|
+
ehr_records = ehr_records.alias("ehr").join(
|
|
608
|
+
cohort.alias("cohort"), F.col("ehr.person_id") == F.col("cohort.person_id")
|
|
609
|
+
).select(
|
|
610
|
+
[F.col("ehr." + col) for col in ehr_records.columns] + [F.col("cohort.cohort_member_id")]
|
|
611
|
+
).selectExpr("*")
|
|
575
612
|
|
|
576
613
|
# Only allow the data records that occurred between the index date and the prediction window
|
|
577
614
|
if self._is_population_estimation:
|
|
578
615
|
if self._is_prediction_window_unbounded:
|
|
579
|
-
record_window_filter =
|
|
616
|
+
record_window_filter = F.col("ehr.date") <= F.current_date()
|
|
580
617
|
else:
|
|
581
|
-
record_window_filter =
|
|
618
|
+
record_window_filter = F.col("ehr.date") <= F.date_add(
|
|
619
|
+
F.col("cohort.index_date"), self._prediction_window
|
|
620
|
+
)
|
|
582
621
|
else:
|
|
583
622
|
# For patient level prediction, we remove all records post index date
|
|
584
623
|
if self._is_observation_post_index:
|
|
585
|
-
record_window_filter =
|
|
586
|
-
cohort
|
|
587
|
-
F.date_add(cohort
|
|
624
|
+
record_window_filter = F.col("ehr.date").between(
|
|
625
|
+
F.col("cohort.index_date"),
|
|
626
|
+
F.date_add(F.col("cohort.index_date"), self._observation_window),
|
|
588
627
|
)
|
|
589
628
|
else:
|
|
590
629
|
if self._is_observation_window_unbounded:
|
|
591
|
-
record_window_filter =
|
|
592
|
-
cohort
|
|
630
|
+
record_window_filter = F.col("ehr.date") <= F.date_sub(
|
|
631
|
+
F.col("cohort.index_date"), self._hold_off_window
|
|
593
632
|
)
|
|
594
633
|
else:
|
|
595
|
-
record_window_filter =
|
|
634
|
+
record_window_filter = F.col("ehr.date").between(
|
|
596
635
|
F.date_sub(
|
|
597
|
-
cohort
|
|
636
|
+
F.col("cohort.index_date"),
|
|
598
637
|
self._observation_window + self._hold_off_window,
|
|
599
638
|
),
|
|
600
|
-
F.date_sub(cohort
|
|
639
|
+
F.date_sub(F.col("cohort.index_date"), self._hold_off_window),
|
|
601
640
|
)
|
|
602
641
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
)
|
|
608
|
-
|
|
609
|
-
|
|
642
|
+
# Somehow the dataframe join does not work without using the alias
|
|
643
|
+
cohort_ehr_records = ehr_records.alias("ehr").join(
|
|
644
|
+
cohort.alias("cohort"),
|
|
645
|
+
(F.col("ehr.person_id") == F.col("cohort.person_id")) &
|
|
646
|
+
(F.col("ehr.cohort_member_id") == F.col("cohort.cohort_member_id")),
|
|
647
|
+
).where(
|
|
648
|
+
record_window_filter
|
|
649
|
+
).select(
|
|
650
|
+
[F.col("ehr." + field_name) for field_name in ehr_records.schema.fieldNames()]
|
|
610
651
|
)
|
|
611
652
|
|
|
612
653
|
if self._is_hierarchical_bert:
|
|
@@ -647,6 +688,7 @@ class NestedCohortBuilder:
|
|
|
647
688
|
exclude_visit_tokens=self._exclude_visit_tokens,
|
|
648
689
|
patient_demographic=(patient_demographic if self._gpt_patient_sequence else None),
|
|
649
690
|
att_type=self._att_type,
|
|
691
|
+
inpatient_att_type=self._inpatient_att_type,
|
|
650
692
|
exclude_demographic=self._exclude_demographic,
|
|
651
693
|
use_age_group=self._use_age_group,
|
|
652
694
|
)
|
|
@@ -748,6 +790,7 @@ def create_prediction_cohort(
|
|
|
748
790
|
is_drug_roll_up_concept=spark_args.is_drug_roll_up_concept,
|
|
749
791
|
include_concept_list=spark_args.include_concept_list,
|
|
750
792
|
refresh_measurement=spark_args.refresh_measurement,
|
|
793
|
+
aggregate_by_hour=spark_args.aggregate_by_hour,
|
|
751
794
|
is_new_patient_representation=spark_args.is_new_patient_representation,
|
|
752
795
|
gpt_patient_sequence=spark_args.gpt_patient_sequence,
|
|
753
796
|
is_hierarchical_bert=spark_args.is_hierarchical_bert,
|
|
@@ -763,7 +806,10 @@ def create_prediction_cohort(
|
|
|
763
806
|
is_observation_window_unbounded=spark_args.is_observation_window_unbounded,
|
|
764
807
|
is_population_estimation=spark_args.is_population_estimation,
|
|
765
808
|
att_type=AttType(spark_args.att_type),
|
|
809
|
+
inpatient_att_type=AttType(spark_args.inpatient_att_type),
|
|
766
810
|
exclude_demographic=spark_args.exclude_demographic,
|
|
767
811
|
use_age_group=spark_args.use_age_group,
|
|
768
812
|
single_contribution=spark_args.single_contribution,
|
|
813
|
+
exclude_features=spark_args.exclude_features,
|
|
814
|
+
meds_format=spark_args.meds_format,
|
|
769
815
|
).build()
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import os.path
|
|
2
|
+
|
|
3
|
+
from pyspark.sql import SparkSession, DataFrame, functions as F, types as T, Window as W
|
|
2
4
|
|
|
3
5
|
from ..const.common import NA
|
|
4
6
|
from ..const.artificial_tokens import VS_TOKEN, VE_TOKEN
|
|
5
7
|
from .patient_event_decorator_base import (
|
|
6
|
-
PatientEventDecorator, AttType,
|
|
7
|
-
time_day_token,
|
|
8
|
-
time_week_token,
|
|
9
|
-
time_month_token,
|
|
10
|
-
time_mix_token,
|
|
11
|
-
time_token_func
|
|
8
|
+
PatientEventDecorator, AttType, get_att_function
|
|
12
9
|
)
|
|
13
10
|
from .token_priority import (
|
|
14
11
|
ATT_TOKEN_PRIORITY,
|
|
@@ -16,6 +13,7 @@ from .token_priority import (
|
|
|
16
13
|
VISIT_TYPE_TOKEN_PRIORITY,
|
|
17
14
|
DISCHARGE_TOKEN_PRIORITY,
|
|
18
15
|
VE_TOKEN_PRIORITY,
|
|
16
|
+
FIRST_VISIT_HOUR_TOKEN_PRIORITY,
|
|
19
17
|
get_inpatient_token_priority,
|
|
20
18
|
get_inpatient_att_token_priority
|
|
21
19
|
)
|
|
@@ -28,20 +26,28 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
28
26
|
include_visit_type,
|
|
29
27
|
exclude_visit_tokens,
|
|
30
28
|
att_type: AttType,
|
|
29
|
+
inpatient_att_type: AttType,
|
|
31
30
|
include_inpatient_hour_token: bool = False,
|
|
31
|
+
spark: SparkSession = None,
|
|
32
|
+
persistence_folder: str = None,
|
|
32
33
|
):
|
|
33
34
|
self._visit_occurrence = visit_occurrence
|
|
34
35
|
self._include_visit_type = include_visit_type
|
|
35
36
|
self._exclude_visit_tokens = exclude_visit_tokens
|
|
36
37
|
self._att_type = att_type
|
|
38
|
+
self._inpatient_att_type = inpatient_att_type
|
|
37
39
|
self._include_inpatient_hour_token = include_inpatient_hour_token
|
|
40
|
+
super().__init__(spark=spark, persistence_folder=persistence_folder)
|
|
41
|
+
|
|
42
|
+
def get_name(self):
|
|
43
|
+
return "att_events"
|
|
38
44
|
|
|
39
45
|
def _decorate(self, patient_events: DataFrame):
|
|
40
46
|
if self._att_type == AttType.NONE:
|
|
41
47
|
return patient_events
|
|
42
48
|
|
|
43
49
|
# visits should the following columns (person_id,
|
|
44
|
-
# visit_concept_id, visit_start_date, visit_occurrence_id, domain
|
|
50
|
+
# visit_concept_id, visit_start_date, visit_occurrence_id, domain)
|
|
45
51
|
cohort_member_person_pair = patient_events.select("person_id", "cohort_member_id").distinct()
|
|
46
52
|
valid_visit_ids = patient_events.groupby(
|
|
47
53
|
"cohort_member_id",
|
|
@@ -55,9 +61,21 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
55
61
|
F.max("concept_order").alias("max_concept_order"),
|
|
56
62
|
)
|
|
57
63
|
|
|
64
|
+
# The visit records are joined to the cohort members (there could be multiple entries for the same patient)
|
|
65
|
+
# if multiple entries are present, we duplicate the visit records for those. If the visit_occurrence dataframe
|
|
66
|
+
# contains visits for each cohort member, then we need to add cohort_member_id to the joined expression as well.
|
|
67
|
+
if "cohort_member_id" in self._visit_occurrence.columns:
|
|
68
|
+
joined_expr = ["person_id", "cohort_member_id"]
|
|
69
|
+
else:
|
|
70
|
+
joined_expr = ["person_id"]
|
|
71
|
+
|
|
58
72
|
visit_occurrence = (
|
|
59
|
-
self._visit_occurrence.
|
|
73
|
+
self._visit_occurrence.join(
|
|
74
|
+
cohort_member_person_pair,
|
|
75
|
+
joined_expr
|
|
76
|
+
).select(
|
|
60
77
|
"person_id",
|
|
78
|
+
"cohort_member_id",
|
|
61
79
|
F.col("visit_start_date").cast(T.DateType()).alias("date"),
|
|
62
80
|
F.col("visit_start_date").cast(T.DateType()).alias("visit_start_date"),
|
|
63
81
|
F.col("visit_start_datetime").cast(T.TimestampType()).alias("visit_start_datetime"),
|
|
@@ -65,14 +83,18 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
65
83
|
"visit_concept_id",
|
|
66
84
|
"visit_occurrence_id",
|
|
67
85
|
F.lit("visit").alias("domain"),
|
|
68
|
-
F.lit(
|
|
86
|
+
F.lit(None).cast("float").alias("number_as_value"),
|
|
87
|
+
F.lit(None).cast("string").alias("concept_as_value"),
|
|
88
|
+
F.lit(0).alias("is_numeric_type"),
|
|
69
89
|
F.lit(0).alias("concept_value_mask"),
|
|
70
90
|
F.lit(0).alias("mlm_skip_value"),
|
|
71
91
|
"age",
|
|
72
92
|
"discharged_to_concept_id",
|
|
73
93
|
)
|
|
74
|
-
.join(
|
|
75
|
-
|
|
94
|
+
.join(
|
|
95
|
+
valid_visit_ids,
|
|
96
|
+
["visit_occurrence_id", "cohort_member_id"]
|
|
97
|
+
)
|
|
76
98
|
)
|
|
77
99
|
|
|
78
100
|
# We assume outpatient visits end on the same day, therefore we start visit_end_date to visit_start_date due
|
|
@@ -89,7 +111,10 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
89
111
|
visit_occurrence = visit_occurrence.withColumn("date_in_week", weeks_since_epoch_udf)
|
|
90
112
|
|
|
91
113
|
# Cache visit for faster processing
|
|
92
|
-
visit_occurrence.
|
|
114
|
+
visit_occurrence = self.try_persist_data(
|
|
115
|
+
visit_occurrence,
|
|
116
|
+
os.path.join(self.get_name(), "visit_occurrence_temp"),
|
|
117
|
+
)
|
|
93
118
|
|
|
94
119
|
visits = visit_occurrence.drop("discharged_to_concept_id")
|
|
95
120
|
|
|
@@ -134,18 +159,7 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
134
159
|
)
|
|
135
160
|
|
|
136
161
|
# Udf for calculating the time token
|
|
137
|
-
|
|
138
|
-
att_func = time_day_token
|
|
139
|
-
elif self._att_type == AttType.WEEK:
|
|
140
|
-
att_func = time_week_token
|
|
141
|
-
elif self._att_type == AttType.MONTH:
|
|
142
|
-
att_func = time_month_token
|
|
143
|
-
elif self._att_type == AttType.MIX:
|
|
144
|
-
att_func = time_mix_token
|
|
145
|
-
else:
|
|
146
|
-
att_func = time_token_func
|
|
147
|
-
|
|
148
|
-
time_token_udf = F.udf(att_func, T.StringType())
|
|
162
|
+
time_token_udf = F.udf(get_att_function(self._att_type), T.StringType())
|
|
149
163
|
|
|
150
164
|
att_tokens = (
|
|
151
165
|
visits.withColumn("datetime", F.to_timestamp("date"))
|
|
@@ -191,6 +205,12 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
191
205
|
|
|
192
206
|
artificial_tokens = artificial_tokens.drop("visit_end_date")
|
|
193
207
|
|
|
208
|
+
# Try persisting artificial events
|
|
209
|
+
artificial_tokens = self.try_persist_data(
|
|
210
|
+
artificial_tokens,
|
|
211
|
+
os.path.join(self.get_name(), "artificial_tokens"),
|
|
212
|
+
)
|
|
213
|
+
|
|
194
214
|
# Retrieving the events that are ONLY linked to inpatient visits
|
|
195
215
|
inpatient_visits = (
|
|
196
216
|
visit_occurrence
|
|
@@ -201,6 +221,7 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
201
221
|
inpatient_visits, ["visit_occurrence_id", "cohort_member_id"]
|
|
202
222
|
)
|
|
203
223
|
|
|
224
|
+
inpatient_time_token_udf = F.udf(get_att_function(self._inpatient_att_type), T.StringType())
|
|
204
225
|
# Fill in the visit_end_date if null (because some visits are still ongoing at the time of data extraction)
|
|
205
226
|
# Bound the event dates within visit_start_date and visit_end_date
|
|
206
227
|
# Generate a span rank to indicate the position of the group of events
|
|
@@ -245,6 +266,11 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
245
266
|
# Add discharge events to the inpatient visits
|
|
246
267
|
inpatient_events = inpatient_events.unionByName(discharge_events)
|
|
247
268
|
|
|
269
|
+
# Try persisting the inpatient events for fasting processing
|
|
270
|
+
inpatient_events = self.try_persist_data(
|
|
271
|
+
inpatient_events, os.path.join(self.get_name(), "inpatient_events")
|
|
272
|
+
)
|
|
273
|
+
|
|
248
274
|
# Get the prev days_since_epoch
|
|
249
275
|
inpatient_prev_date_udf = F.lag("date").over(
|
|
250
276
|
W.partitionBy("cohort_member_id", "visit_occurrence_id").orderBy("concept_order")
|
|
@@ -264,16 +290,42 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
264
290
|
)
|
|
265
291
|
inpatient_att_token = F.when(
|
|
266
292
|
F.col("hour_delta") < 24, F.concat(F.lit("i-H"), F.col("hour_delta"))
|
|
267
|
-
).otherwise(F.concat(F.lit("i-"),
|
|
293
|
+
).otherwise(F.concat(F.lit("i-"), inpatient_time_token_udf("time_delta")))
|
|
294
|
+
|
|
295
|
+
# We need to insert an ATT token between midnight and the visit start datetime
|
|
296
|
+
first_inpatient_hour_delta_udf = (
|
|
297
|
+
F.floor((F.unix_timestamp("visit_start_datetime") - F.unix_timestamp(
|
|
298
|
+
F.col("visit_start_datetime").cast("date"))) / 3600)
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
first_hour_tokens = (
|
|
302
|
+
visits.where(F.col("visit_concept_id").isin([9201, 262, 8971, 8920]))
|
|
303
|
+
.withColumn("hour_delta", first_inpatient_hour_delta_udf)
|
|
304
|
+
.where(F.col("hour_delta") > 0)
|
|
305
|
+
.withColumn("date", F.col("visit_start_date"))
|
|
306
|
+
.withColumn("datetime", F.to_timestamp("date"))
|
|
307
|
+
.withColumn("standard_concept_id", F.concat(F.lit("i-H"), F.col("hour_delta")))
|
|
308
|
+
.withColumn("visit_concept_order", F.col("min_visit_concept_order"))
|
|
309
|
+
.withColumn("concept_order", F.lit(0))
|
|
310
|
+
.withColumn("priority", F.lit(FIRST_VISIT_HOUR_TOKEN_PRIORITY))
|
|
311
|
+
.withColumn("unit", F.lit(NA))
|
|
312
|
+
.withColumn("event_group_id", F.lit(NA))
|
|
313
|
+
.drop("min_visit_concept_order", "max_visit_concept_order")
|
|
314
|
+
.drop("min_concept_order", "max_concept_order")
|
|
315
|
+
.drop("hour_delta", "visit_end_date")
|
|
316
|
+
)
|
|
317
|
+
|
|
268
318
|
# Create ATT tokens within the inpatient visits
|
|
269
319
|
inpatient_att_events = (
|
|
270
320
|
inpatient_events.withColumn(
|
|
321
|
+
"time_stamp_hour", F.hour("datetime")
|
|
322
|
+
).withColumn(
|
|
271
323
|
"is_span_boundary",
|
|
272
324
|
F.row_number().over(
|
|
273
|
-
W.partitionBy("cohort_member_id", "visit_occurrence_id"
|
|
325
|
+
W.partitionBy("cohort_member_id", "visit_occurrence_id")
|
|
326
|
+
.orderBy("priority", "date", "time_stamp_hour")
|
|
274
327
|
),
|
|
275
328
|
)
|
|
276
|
-
.where(F.col("is_span_boundary") == 1)
|
|
277
329
|
.withColumn("prev_date", inpatient_prev_date_udf)
|
|
278
330
|
.withColumn("time_delta", inpatient_time_delta_udf)
|
|
279
331
|
.withColumn("prev_datetime", inpatient_prev_datetime_udf)
|
|
@@ -284,12 +336,17 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
284
336
|
.withColumn("visit_concept_order", F.col("visit_concept_order"))
|
|
285
337
|
.withColumn("priority", get_inpatient_att_token_priority())
|
|
286
338
|
.withColumn("concept_value_mask", F.lit(0))
|
|
287
|
-
.withColumn("
|
|
339
|
+
.withColumn("number_as_value", F.lit(None).cast("float"))
|
|
340
|
+
.withColumn("concept_as_value", F.lit(None).cast("string"))
|
|
341
|
+
.withColumn("is_numeric_type", F.lit(0))
|
|
288
342
|
.withColumn("unit", F.lit(NA))
|
|
289
343
|
.withColumn("event_group_id", F.lit(NA))
|
|
290
344
|
.drop("prev_date", "time_delta", "is_span_boundary")
|
|
291
|
-
.drop("prev_datetime", "hour_delta")
|
|
345
|
+
.drop("prev_datetime", "hour_delta", "time_stamp_hour")
|
|
292
346
|
)
|
|
347
|
+
|
|
348
|
+
# Insert the first hour tokens between the visit type and first medical event
|
|
349
|
+
inpatient_att_events = inpatient_att_events.unionByName(first_hour_tokens)
|
|
293
350
|
else:
|
|
294
351
|
# Create ATT tokens within the inpatient visits
|
|
295
352
|
inpatient_att_events = (
|
|
@@ -306,17 +363,24 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
306
363
|
.where(F.col("prev_date").isNotNull())
|
|
307
364
|
.withColumn(
|
|
308
365
|
"standard_concept_id",
|
|
309
|
-
F.concat(F.lit("i-"),
|
|
366
|
+
F.concat(F.lit("i-"), inpatient_time_token_udf("time_delta")),
|
|
310
367
|
)
|
|
311
368
|
.withColumn("visit_concept_order", F.col("visit_concept_order"))
|
|
312
369
|
.withColumn("priority", get_inpatient_att_token_priority())
|
|
313
370
|
.withColumn("concept_value_mask", F.lit(0))
|
|
314
|
-
.withColumn("
|
|
371
|
+
.withColumn("number_as_value", F.lit(None).cast("float"))
|
|
372
|
+
.withColumn("concept_as_value", F.lit(None).cast("string"))
|
|
373
|
+
.withColumn("is_numeric_type", F.lit(0))
|
|
315
374
|
.withColumn("unit", F.lit(NA))
|
|
316
375
|
.withColumn("event_group_id", F.lit(NA))
|
|
317
376
|
.drop("prev_date", "time_delta", "is_span_boundary")
|
|
318
377
|
)
|
|
319
378
|
|
|
379
|
+
# Try persisting the inpatient att events
|
|
380
|
+
inpatient_att_events = self.try_persist_data(
|
|
381
|
+
inpatient_att_events, os.path.join(self.get_name(), "inpatient_att_events")
|
|
382
|
+
)
|
|
383
|
+
|
|
320
384
|
self.validate(inpatient_events)
|
|
321
385
|
self.validate(inpatient_att_events)
|
|
322
386
|
|
|
@@ -326,6 +390,10 @@ class AttEventDecorator(PatientEventDecorator):
|
|
|
326
390
|
["visit_occurrence_id", "cohort_member_id"],
|
|
327
391
|
how="left_anti",
|
|
328
392
|
)
|
|
393
|
+
# Try persisting the other events
|
|
394
|
+
other_events = self.try_persist_data(
|
|
395
|
+
other_events, os.path.join(self.get_name(), "other_events")
|
|
396
|
+
)
|
|
329
397
|
|
|
330
398
|
patient_events = inpatient_events.unionByName(inpatient_att_events).unionByName(other_events)
|
|
331
399
|
|