Skip to content

Commit

Permalink
Merge pull request #86 from opensafely/viv3ckj/refactor-code
Browse files Browse the repository at this point in the history
Viv3ckj/refactor code (part 1)
  • Loading branch information
viv3ckj authored Dec 13, 2024
2 parents d23e050 + 9732aab commit c3ca045
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 95 deletions.
9 changes: 9 additions & 0 deletions analysis/codelists.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,12 @@
# Community Pharmacist Consultation Service for minor illness - 1577041000000109
# Pharmacy First service - 983341000000102
pharmacy_first_consultation_codelist = ["1577041000000109", "983341000000102"]

# PF codes separated for individual analysis
pharmacy_first_event_codes = {
# 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"],
}
15 changes: 15 additions & 0 deletions analysis/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# measures_definition_pf_breakdown.py
start_date_measure_pf_breakdown = "2023-11-01"
monthly_intervals_measure_pf_breakdown = 12

# measures_definition_pf_condition_provider.py
start_date_measure_condition_provider = "2023-01-01"
monthly_intervals_measure_condition_provider = 22

# measures_definition_pf_descriptive_stats.py
start_date_measure_descriptive_stats = "2024-02-01"
monthly_intervals_measure_descriptive_stats = 9

# measures_definition_pf_medications.py
start_date_measure_medications = "2023-11-01"
monthly_intervals_measure_medications = 9
23 changes: 11 additions & 12 deletions analysis/measures_definition_pf_breakdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
ethnicity_codelist,
)

from pf_dataset import pharmacy_first_event_codes, get_latest_ethnicity
from pf_dataset import get_latest_ethnicity
from codelists import pharmacy_first_event_codes, pharmacy_first_consultation_codelist
from config import start_date_measure_pf_breakdown, monthly_intervals_measure_pf_breakdown
from pf_variables_library import select_events

measures = create_measures()
measures.configure_dummy_data(population_size=1000)

start_date = "2023-11-01"
monthly_intervals = 12
start_date = start_date_measure_pf_breakdown
monthly_intervals = monthly_intervals_measure_pf_breakdown

registration = practice_registrations.for_patient_on(INTERVAL.end_date)
ethnicity_combined = get_latest_ethnicity(
Expand Down Expand Up @@ -56,16 +59,12 @@
otherwise="Missing",
)

pharmacy_first_ids = clinical_events.where(
clinical_events.snomedct_code.is_in(
pharmacy_first_event_codes["combined_pf_service"]
)
).consultation_id
pharmacy_first_ids = select_events(clinical_events, codelist=pharmacy_first_consultation_codelist).consultation_id

# Select clinical events in interval date range
selected_events = clinical_events.where(
clinical_events.date.is_on_or_between(INTERVAL.start_date, INTERVAL.end_date)
).where(clinical_events.consultation_id.is_in(pharmacy_first_ids))
# # Select clinical events in interval date range
selected_events = select_events(clinical_events, start_date=INTERVAL.start_date, end_date=INTERVAL.end_date).where(
clinical_events.consultation_id.is_in(pharmacy_first_ids)
)

# Breakdown metrics to be produced as graphs
breakdown_metrics = {
Expand Down
19 changes: 7 additions & 12 deletions analysis/measures_definition_pf_condition_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,22 @@
pharmacy_first_conditions_codes,
imd_quintile,
)
from pf_dataset import pharmacy_first_event_codes

from codelists import pharmacy_first_consultation_codelist
from config import start_date_measure_condition_provider, monthly_intervals_measure_condition_provider
from pf_variables_library import select_events

measures = create_measures()
measures.configure_dummy_data(population_size=1000)

start_date = "2023-01-01"
monthly_intervals = 22
start_date = start_date_measure_condition_provider
monthly_intervals = monthly_intervals_measure_condition_provider

registration = practice_registrations.for_patient_on(INTERVAL.end_date)

selected_events = clinical_events.where(
clinical_events.date.is_on_or_between(INTERVAL.start_date, INTERVAL. end_date)
)
selected_events = select_events(clinical_events, start_date=INTERVAL.start_date, end_date=INTERVAL.end_date)

# Create variable which contains boolean values of whether pharmacy first event exists for patient
has_pharmacy_first = selected_events.where(
selected_events.snomedct_code.is_in(
pharmacy_first_event_codes["combined_pf_service"]
)
).exists_for_patient()
has_pharmacy_first = select_events(selected_events, codelist=pharmacy_first_consultation_codelist).exists_for_patient()

for condition_name, condition_code in pharmacy_first_conditions_codes.items():
condition_events = selected_events.where(
Expand Down
23 changes: 10 additions & 13 deletions analysis/measures_definition_pf_descriptive_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,42 @@
from ehrql.tables.raw.tpp import medications
from ehrql.tables.tpp import practice_registrations, patients, clinical_events

from pf_variables_library import get_consultation_ids, get_consultationid_events
from pf_variables_library import select_events_from_codelist, select_events_by_consultation_id
from codelists import (
pharmacy_first_med_codelist,
pharmacy_first_consultation_codelist,
pharmacy_first_conditions_codelist,
)
from config import start_date_measure_descriptive_stats, monthly_intervals_measure_descriptive_stats

measures = create_measures()
measures.configure_dummy_data(population_size=1000)
measures.configure_disclosure_control(enabled=True)

start_date = "2024-02-01"
monthly_intervals = 9
start_date = start_date_measure_descriptive_stats
monthly_intervals = monthly_intervals_measure_descriptive_stats

registration = practice_registrations.for_patient_on(INTERVAL.end_date)

# Function to retrieve consultation ids from clinical events that are PF consultations
pharmacy_first_ids = get_consultation_ids(
pharmacy_first_ids = select_events_from_codelist(
clinical_events, pharmacy_first_consultation_codelist
)
).consultation_id

# Function to retrieve selected events using pharmacy first ids
selected_clinical_events = get_consultationid_events(
selected_clinical_events = select_events_by_consultation_id(
clinical_events, pharmacy_first_ids
).where(clinical_events.date.is_on_or_between(INTERVAL.start_date, INTERVAL.end_date))

selected_med_events = get_consultationid_events(medications, pharmacy_first_ids).where(
selected_med_events = select_events_by_consultation_id(medications, pharmacy_first_ids).where(
medications.date.is_on_or_between(INTERVAL.start_date, INTERVAL.end_date)
)

# Create variable which contains boolean values of whether pharmacy first event exists for patient
has_pf_consultation = selected_clinical_events.where(
selected_clinical_events.snomedct_code.is_in(pharmacy_first_consultation_codelist)
).exists_for_patient()
has_pf_consultation = select_events_from_codelist(selected_clinical_events, pharmacy_first_consultation_codelist).exists_for_patient()

# PF consultations with PF clinical condition
has_pf_condition = selected_clinical_events.where(
selected_clinical_events.snomedct_code.is_in(pharmacy_first_conditions_codelist)
).exists_for_patient()
has_pf_condition = select_events_from_codelist(selected_clinical_events, pharmacy_first_conditions_codelist).exists_for_patient()

# PF consultations with prescribed PF medication
has_pf_medication = selected_med_events.where(
Expand Down
36 changes: 11 additions & 25 deletions analysis/measures_definition_pf_medications.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,32 @@
practice_registrations,
)
from ehrql.tables.raw.tpp import medications

from pf_dataset import pharmacy_first_event_codes
from codelists import *

pharmacy_first_med_codes = (
acute_otitis_media_tx_cod
+ impetigo_treatment_tx_cod
+ infected_insect_bites_tx_cod
+ shingles_treatment_tx_cod
+ sinusitis_tx_cod
+ sore_throat_tx_cod
+ urinary_tract_infection_tx_cod
)
from codelists import pharmacy_first_consultation_codelist, pharmacy_first_med_codelist
from config import start_date_measure_medications, monthly_intervals_measure_medications
from pf_variables_library import select_events

measures = create_measures()
measures.configure_dummy_data(population_size=1000)
# Turn off during code development, but turn on before running against on the server
measures.configure_disclosure_control(enabled=True)

start_date = "2023-11-01"
monthly_intervals = 9
start_date = start_date_measure_medications
monthly_intervals = monthly_intervals_measure_medications

registration = practice_registrations.for_patient_on(INTERVAL.end_date)

# Select Pharmacy First consultations during interval date range
pharmacy_first_events = clinical_events.where(
clinical_events.date.is_on_or_between(INTERVAL.start_date, INTERVAL.end_date)
).where(
clinical_events.snomedct_code.is_in(
pharmacy_first_event_codes["combined_pf_service"]
)
pharmacy_first_events = select_events(clinical_events, start_date=INTERVAL.start_date, end_date=INTERVAL.end_date).where(
clinical_events.snomedct_code.is_in(pharmacy_first_consultation_codelist)
)

pharmacy_first_ids = pharmacy_first_events.consultation_id
has_pharmacy_first_consultation = pharmacy_first_events.exists_for_patient()

# Select medications prescribed with PF consultation ID
selected_medications = medications.where(
medications.date.is_on_or_between(INTERVAL.start_date, INTERVAL.end_date)
).where(medications.consultation_id.is_in(pharmacy_first_ids))
selected_medications = select_events(medications, start_date=INTERVAL.start_date, end_date=INTERVAL.end_date).where(
medications.consultation_id.is_in(pharmacy_first_ids)
)

# Select first medication for group_by argument in measures
first_selected_medication = (
Expand All @@ -53,7 +39,7 @@

# Check if a medication is from our PF codelists
has_pharmacy_first_medication = first_selected_medication.is_in(
pharmacy_first_med_codes
pharmacy_first_med_codelist
)

# Numerator, patients with a PF medication
Expand Down
10 changes: 0 additions & 10 deletions analysis/pf_codelist_functions.py

This file was deleted.

14 changes: 2 additions & 12 deletions analysis/pf_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,8 @@

from pf_variables_library import check_pregnancy_status, count_past_events

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"],
}

# This file contains functions for the denominators of the patient population for each clinical condition.
# It will be used to calculate rates, and is separate from pf_variables_library

# Create denominator variables for each clinical condition
# These are based on NHS England rules using sex, age, pregnancy status and repeated diagnoses
Expand Down
41 changes: 30 additions & 11 deletions analysis/pf_variables_library.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Function to check status of a condition within a specified time window
from ehrql import months


def check_pregnancy_status(index_date, selected_events, codelist):
return (
selected_events.where(selected_events.snomedct_code.is_in(codelist))
Expand All @@ -11,7 +10,6 @@ def check_pregnancy_status(index_date, selected_events, codelist):
.exists_for_patient()
)


# Function to count number of coded events within a specified time window
def count_past_events(index_date, selected_events, codelist, num_months):
return (
Expand All @@ -24,19 +22,40 @@ def count_past_events(index_date, selected_events, codelist, num_months):
.count_for_patient()
)

# Function to get events linked to a specified codelist
def select_events_from_codelist(event_frame, codelist):
selected_events = event_frame.where(
event_frame.snomedct_code.is_in(codelist)
)

# Function to get consultation IDs linked to a specified codelist
def get_consultation_ids(clinical_events, codelist):
consultation_ids = clinical_events.where(
clinical_events.snomedct_code.is_in(codelist)
).consultation_id

return consultation_ids

return selected_events

# Function to get events with specific consultation IDs
def get_consultationid_events(event_frame, consultation_ids):
def select_events_by_consultation_id(event_frame, consultation_ids):
selected_events = event_frame.where(
event_frame.consultation_id.is_in(consultation_ids)
)
return selected_events

# Function to get events within a time frame
def select_events_between(event_frame, start_date, end_date):
selected_events = event_frame.where(
event_frame.date.is_on_or_between(start_date, end_date)
)
return selected_events

def select_events(event_frame, codelist=None, consultation_ids=None, start_date=None, end_date=None):
"""
Wrapper function to select events based on codelist, consultation IDs, or a date range.
Allows combining multiple selection criteria.
"""
selected_events = event_frame

if codelist is not None:
selected_events = select_events_from_codelist(selected_events, codelist)
if consultation_ids is not None:
selected_events = select_events_by_consultation_id(selected_events, consultation_ids)
if start_date is not None and end_date is not None:
selected_events = select_events_between(selected_events, start_date, end_date)

return selected_events

0 comments on commit c3ca045

Please sign in to comment.