diff --git a/analysis/pf_dataset.py b/analysis/pf_dataset.py index 4b195f9..28ea00d 100644 --- a/analysis/pf_dataset.py +++ b/analysis/pf_dataset.py @@ -1,35 +1,7 @@ -from ehrql.tables.tpp import patients, case, when, clinical_events +from ehrql.tables.tpp import patients, case, when from pf_variables_library import check_pregnancy_status, count_past_events -# Create dictionary of pharmacy first codes -pharmacy_first_event_codes = { - # # Community Pharmacy (CP) Blood Pressure (BP) Check Service (procedure) - # "blood_pressure_service": ["1659111000000107"], - # # Community Pharmacy (CP) Contraception Service (procedure) - # "contraception_service": ["1659121000000101"], - # Community Pharmacist (CP) Consultation Service for minor illness (procedure) - "consultation_service": ["1577041000000109"], - # Pharmacy First service (qualifier value) - "pharmacy_first_service": ["983341000000102"], - "combined_pf_service": ["1577041000000109", "983341000000102"], -} - - -def get_pf_consultation_ids_from_events(events, codelist): - pharmacy_first_ids = events.where( - events.snomedct_code.is_in(codelist) - ).consultation_id - return pharmacy_first_ids - - -def get_pf_clinical_events(pharmacy_first_ids): - selected_events = clinical_events.where( - clinical_events.consultation_id.is_in(pharmacy_first_ids) - ) - return selected_events - - # Create denominator variables for each clinical condition # These are based on NHS England rules using sex, age, pregnancy status and repeated diagnoses # NOTE: The following exclusions have not been added: @@ -38,12 +10,12 @@ def get_pf_clinical_events(pharmacy_first_ids): # - chronic sinusitis and immunosuppressed individuals for acute sinusitis def get_uncomplicated_uti_denominator(index_date, selected_events, pregnancy_codelist): urt_code = ["1090711000000102"] - count_urt_6m = count_past_events(index_date, clinical_events, urt_code, 6) - count_urt_12m = count_past_events(index_date, clinical_events, urt_code, 12) + count_urt_6m = count_past_events(index_date, selected_events, urt_code, 6) + count_urt_12m = count_past_events(index_date, selected_events, urt_code, 12) age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return ( @@ -58,7 +30,7 @@ def get_uncomplicated_uti_denominator(index_date, selected_events, pregnancy_cod def get_shingles_denominator(index_date, selected_events, pregnancy_codelist): age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return (age >= 18) & (pregnancy_status == False) @@ -67,12 +39,12 @@ def get_shingles_denominator(index_date, selected_events, pregnancy_codelist): def get_impetigo_denominator(index_date, selected_events, pregnancy_codelist): impetigo_code = ["48277006"] count_impetigo_12m = count_past_events( - index_date, clinical_events, impetigo_code, 12 + index_date, selected_events, impetigo_code, 12 ) age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return ((age >= 1) & (count_impetigo_12m < 2)) & ( @@ -93,7 +65,7 @@ def get_infected_insect_bites_denominator( ): age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return (age >= 1) & ( @@ -104,7 +76,7 @@ def get_infected_insect_bites_denominator( def get_acute_sore_throat_denominator(index_date, selected_events, pregnancy_codelist): age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return (age >= 5) & ( @@ -115,7 +87,7 @@ def get_acute_sore_throat_denominator(index_date, selected_events, pregnancy_cod def get_acute_sinusitis_denominator(index_date, selected_events, pregnancy_codelist): age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return (age >= 12) & ( @@ -126,15 +98,15 @@ def get_acute_sinusitis_denominator(index_date, selected_events, pregnancy_codel def get_acute_otitis_media_denominator(index_date, selected_events, pregnancy_codelist): acute_otitis_code = ["3110003"] count_acute_otitis_6m = count_past_events( - index_date, clinical_events, acute_otitis_code, 6 + index_date, selected_events, acute_otitis_code, 6 ) count_acute_otitis_12m = count_past_events( - index_date, clinical_events, acute_otitis_code, 12 + index_date, selected_events, acute_otitis_code, 12 ) age = patients.age_on(index_date) pregnancy_status = check_pregnancy_status( - index_date, clinical_events, pregnancy_codelist + index_date, selected_events, pregnancy_codelist ) return ( diff --git a/analysis/pf_dataset_definition.py b/analysis/pf_dataset_definition.py index c381448..7dca1cf 100644 --- a/analysis/pf_dataset_definition.py +++ b/analysis/pf_dataset_definition.py @@ -1,11 +1,10 @@ -from ehrql import INTERVAL, Measures, months, create_dataset +from ehrql import create_dataset from ehrql.tables.tpp import ( patients, clinical_events, practice_registrations, - ethnicity_from_sus, ) - +from pf_variables_library import check_pregnancy_status from pf_dataset import ( get_uncomplicated_uti_denominator, get_shingles_denominator, @@ -14,11 +13,6 @@ get_acute_sore_throat_denominator, get_acute_sinusitis_denominator, get_acute_otitis_media_denominator, - get_pf_clinical_events, - get_pf_consultation_ids_from_events, - get_latest_ethnicity, - check_pregnancy_status_for_debug, - pharmacy_first_event_codes, ) import codelists @@ -26,41 +20,41 @@ index_date = "2024-10-10" dataset = create_dataset() -pharmacy_first_ids = get_pf_consultation_ids_from_events( - clinical_events, pharmacy_first_event_codes["combined_pf_service"] -) -selected_events = get_pf_clinical_events(pharmacy_first_ids) - registration = practice_registrations.for_patient_on(index_date) # Create new columns for each denominator rule dataset.uti_denominator = get_uncomplicated_uti_denominator( - index_date, selected_events, codelists.pregnancy_codelist + index_date, clinical_events, codelists.pregnancy_codelist ) + dataset.shingles_denominator = get_shingles_denominator( - index_date, selected_events, codelists.pregnancy_codelist + index_date, clinical_events, codelists.pregnancy_codelist ) + dataset.impetigo_denominator = get_impetigo_denominator( - index_date, selected_events, codelists.pregnancy_codelist + index_date, clinical_events, codelists.pregnancy_codelist ) -dataset.insect_bite_denominator = get_infected_insect_bites_denominator( - index_date, selected_events, codelists.pregnancy_codelist + +dataset.insectbite_denominator = get_infected_insect_bites_denominator( + index_date, clinical_events, codelists.pregnancy_codelist ) -dataset.sore_throat_denominator = get_acute_sore_throat_denominator( - index_date, selected_events, codelists.pregnancy_codelist + +dataset.sorethroat_denominator = get_acute_sore_throat_denominator( + index_date, clinical_events, codelists.pregnancy_codelist ) + dataset.sinusitis_denominator = get_acute_sinusitis_denominator( - index_date, selected_events, codelists.pregnancy_codelist -) -dataset.otitis_media_denominator = get_acute_otitis_media_denominator( - index_date, selected_events, codelists.pregnancy_codelist + index_date, clinical_events, codelists.pregnancy_codelist ) -dataset.latest_ethnicity = get_latest_ethnicity( - index_date, clinical_events, codelists.ethnicity_codelist, ethnicity_from_sus + +dataset.otitismedia_denominator = get_acute_otitis_media_denominator( + index_date, clinical_events, codelists.pregnancy_codelist ) -dataset.pregnancy_status_check = check_pregnancy_status_for_debug( + +dataset.pregnancy_status = check_pregnancy_status( index_date, clinical_events, codelists.pregnancy_codelist ) + dataset.define_population( registration.exists_for_patient() & patients.sex.is_in(["male", "female"]) ) diff --git a/analysis/test_pf_dataset_definition.py b/analysis/test_pf_dataset_definition.py index 68bfd95..f1b146a 100644 --- a/analysis/test_pf_dataset_definition.py +++ b/analysis/test_pf_dataset_definition.py @@ -6,128 +6,54 @@ # Index date = "2024-10-10" test_data = { # Expected in population (test for age exclusions) - # Female patient, 1 year old + # Female patient, 16 year old 1: { - "patients": {"date_of_birth": date(2023, 1, 1), "sex": "female"}, + "patients": {"date_of_birth": date(2008, 1, 1), "sex": "female"}, "clinical_events": [ {}, ], - "ethnicity_from_sus": {"code": "A"}, + "ethnicity_from_sus": {}, "practice_registrations": [{"start_date": date(2024, 3, 1)}], "expected_in_population": True, "expected_columns": { - "uti_denominator": False, + "uti_denominator": True, "shingles_denominator": False, "impetigo_denominator": True, - "insect_bite_denominator": True, - "sore_throat_denominator": False, - "sinusitis_denominator": False, - "otitis_media_denominator": True, - "latest_ethnicity": "White", - "pregnancy_status_check": False, + "insectbite_denominator": True, + "sorethroat_denominator": True, + "sinusitis_denominator": True, + "otitismedia_denominator": True, + "pregnancy_status": False, }, }, # Expected in population (test for pregnancy exclusions) - # Female patient, 24 years old and PREGNANT + # Female patient, PREGNANT 15 year old 2: { - "patients": {"date_of_birth": date(2000, 1, 1), "sex": "female"}, + "patients": {"date_of_birth": date(2009, 1, 1), "sex": "female"}, "clinical_events": [ - { - # otitis media code - "date": date(2024, 10, 1), - "snomedct_code": "3110003", - }, { # Pregnancy code "date": date(2024, 10, 3), "snomedct_code": "77386006", }, ], - "ethnicity_from_sus": {"code": "J"}, - "practice_registrations": [{"start_date": date(2020, 3, 1)}], + "ethnicity_from_sus": {}, + "practice_registrations": [{"start_date": date(2024, 3, 1)}], "expected_in_population": True, "expected_columns": { "uti_denominator": False, "shingles_denominator": False, - "impetigo_denominator": True, - "insect_bite_denominator": True, - "sore_throat_denominator": True, - "sinusitis_denominator": True, - "otitis_media_denominator": False, - "latest_ethnicity": "Asian or Asian British", - "pregnancy_status_check": True, - }, - }, - # Expected in population (test for multiple diagnosis exclusion -impetigo) - # Male, 24 years old, TWO impetigo diagnoses - 3: { - "patients": {"date_of_birth": date(2000, 1, 1), "sex": "male"}, - "clinical_events": [ - { - # 1st impetigo diagnosis - "date": date(2024, 10, 8), - "snomedct_code": "48277006", - }, - { - # 2nd impetigo diagnosis - "date": date(2024, 10, 9), - "snomedct_code": "48277006", - }, - ], - "ethnicity_from_sus": {"code": "J"}, - "practice_registrations": [{"start_date": date(2020, 3, 1)}], - "expected_in_population": True, - "expected_columns": { - "uti_denominator": False, - "shingles_denominator": True, "impetigo_denominator": False, - "insect_bite_denominator": True, - "sore_throat_denominator": True, - "sinusitis_denominator": True, - "otitis_media_denominator": False, - "latest_ethnicity": "Asian or Asian British", - "pregnancy_status_check": False, - }, - }, - # Expected in population (test for multiple diagnosis exclusion -acute otitis) - # Male, 1 years old, THREE otitis media diagnoses - 4: { - "patients": {"date_of_birth": date(2023, 1, 1), "sex": "male"}, - "clinical_events": [ - { - # 1st otitis diagnosis - "date": date(2024, 10, 7), - "snomedct_code": "3110003", - }, - { - # 2nd otitis diagnosis - "date": date(2024, 10, 8), - "snomedct_code": "3110003", - }, - { - # 3rd otitis diagnosis - "date": date(2024, 10, 9), - "snomedct_code": "3110003", - }, - ], - "ethnicity_from_sus": {"code": "J"}, - "practice_registrations": [{"start_date": date(2020, 3, 1)}], - "expected_in_population": True, - "expected_columns": { - "uti_denominator": False, - "shingles_denominator": False, - "impetigo_denominator": True, - "insect_bite_denominator": True, - "sore_throat_denominator": False, + "insectbite_denominator": False, + "sorethroat_denominator": False, "sinusitis_denominator": False, - "otitis_media_denominator": False, - "latest_ethnicity": "Asian or Asian British", - "pregnancy_status_check": False, + "otitismedia_denominator": False, + "pregnancy_status": True, }, }, - # Expected in population (test for multiple diagnosis exclusion - uti) - # Female, 24 year old with 3 uti diagnoses - 4: { + # Expected in population (test for multiple diagnoses exclusions) + # Female patient, 24 year old + 3: { "patients": {"date_of_birth": date(2000, 1, 1), "sex": "female"}, "clinical_events": [ { @@ -146,45 +72,18 @@ "snomedct_code": "1090711000000102", }, ], - "ethnicity_from_sus": {"code": "J"}, - "practice_registrations": [{"start_date": date(2020, 3, 1)}], + "ethnicity_from_sus": {}, + "practice_registrations": [{"start_date": date(2024, 3, 1)}], "expected_in_population": True, "expected_columns": { "uti_denominator": False, "shingles_denominator": True, "impetigo_denominator": True, - "insect_bite_denominator": True, - "sore_throat_denominator": True, + "insectbite_denominator": True, + "sorethroat_denominator": True, "sinusitis_denominator": True, - "otitis_media_denominator": False, - "latest_ethnicity": "Asian or Asian British", - "pregnancy_status_check": False, - }, - }, - # Expected in population (test for under 16 pregnancy exclusion) - # Female, 14 years old, PREGNANT - 5: { - "patients": {"date_of_birth": date(2010, 1, 1), "sex": "female"}, - "clinical_events": [ - { - # Pregnancy code - "date": date(2024, 10, 3), - "snomedct_code": "77386006", - } - ], - "ethnicity_from_sus": {"code": "J"}, - "practice_registrations": [{"start_date": date(2020, 3, 1)}], - "expected_in_population": True, - "expected_columns": { - "uti_denominator": False, - "shingles_denominator": False, - "impetigo_denominator": False, - "insect_bite_denominator": False, - "sore_throat_denominator": False, - "sinusitis_denominator": False, - "otitis_media_denominator": False, - "latest_ethnicity": "Asian or Asian British", - "pregnancy_status_check": True, + "otitismedia_denominator": False, + "pregnancy_status": False, }, }, }