-
-
Save clarkevans/681daa7bb366c69404b4dd16572ef133 to your computer and use it in GitHub Desktop.
Implementing CMS165v6: Controlling High Blood Pressure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Implementing CMS165v6." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"This notebook demonstrates how _CMS165v6_ eCQM is calculated for 12 synthetic patients derived from the Cypress project encoded using FHIR and serialized with XML.\n", | |
"```\n", | |
"Measure: CMS165v5\n", | |
"Title: Controlling High Blood Pressure\n", | |
"Description: Percentage of patients 18-85 years \n", | |
" of age who had a diagnosis of hypertension and \n", | |
" whose blood pressure was adequately controlled \n", | |
" (<140/90mmHg) during the measurement period\n", | |
"```\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"cd(\"src\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"WARNING: Method definition cse(RBT.Query) in module RBT at /home/cce/.julia/v0.5/RBT/src/cse.jl:3 overwritten in module Main at /home/cce/ihm-fhir-ri/src/querycombinators.jl:84.\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"\"Data and source code loaded\"" | |
] | |
}, | |
"execution_count": 2, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"include(\"querycombinators.jl\") # ignore redefinition of \"cse\" warning\n", | |
"include(\"load-fhir.jl\") \n", | |
"include(\"interval.jl\")\n", | |
"include(\"load-valueset.jl\")\n", | |
"\"Data and source code loaded\"" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"First we need to define the ValueSets used in the measure. If one was implementing all the measures, you could do this independently. The ``ValueSet`` combinator here converts the identifier into a Vector of Concepts to be used in various calculations." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"RBT.Combinator(RBT.#201)" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"OfficeVisit = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.101.12.1001\")\n", | |
"FaceToFaceInteraction = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.101.12.1048\")\n", | |
"PreventiveCareServicesEstablishedOfficeVisit18AndUp = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.101.12.1025\")\n", | |
"PreventiveCareServicesInitialOfficeVisit18AndUp = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.101.12.1023\")\n", | |
"HomeHealthcareServices = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.101.12.1016\")\n", | |
"AnnualWellnessVisit = \n", | |
" ValueSet(\"2.16.840.1.113883.3.526.3.1240\")\n", | |
"\n", | |
"EssentialHypertension = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.104.12.1011\")\n", | |
"\n", | |
"Pregnancy = \n", | |
" ValueSet(\"2.16.840.1.113883.3.526.3.378\")\n", | |
"EndStageRenalDisease = \n", | |
" ValueSet(\"2.16.840.1.113883.3.526.3.353\")\n", | |
"ChronicKidneyDiseaseStage5 = \n", | |
" ValueSet(\"2.16.840.1.113883.3.526.3.1002\")\n", | |
"VascularAccessForDialysis = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.109.12.1011\")\n", | |
"ESRDMonthlyOutpatientServices = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.109.12.1014\")\n", | |
"KidneyTransplant = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.109.12.1012\")\n", | |
"DialysisEducation = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.109.12.1016\")\n", | |
"DialysisServices = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.109.12.1013\")\n", | |
"OtherServicesRelatedToDialysis = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.109.12.1015\")\n", | |
"\n", | |
"# new in v6\n", | |
"HospiceCareAmbulatory = \n", | |
" ValueSet(\"2.16.840.1.113762.1.4.1108.1\")\n", | |
"EncounterInpatient = \n", | |
" ValueSet(\"2.16.840.1.113883.3.666.5.307\")\n", | |
"DischargedHospiceHome =\n", | |
" ValueSet(\"2.16.840.1.113883.3.117.1.7.1.209\")\n", | |
"DischargedHospiceFacility = \n", | |
" ValueSet(\"2.16.840.1.113883.3.117.1.7.1.207\")\n", | |
" \n", | |
"AdultOutpatientVisit = \n", | |
" ValueSet(\"2.16.840.1.113883.3.464.1003.101.12.1065\")\n", | |
"SystolicBloodPressure = \n", | |
" ValueSet(\"2.16.840.1.113883.3.526.3.1032\")\n", | |
"DiastolicBloodPressure = \n", | |
" ValueSet(\"2.16.840.1.113883.3.526.3.1033\")\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The measure period for this sample data is 2016. Let's first define an *Interval* called measure period and define a few useful predicates which test an entry period against the measure period." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"RBT.Combinator(RBT.#201)" | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"MeasurePeriod = MakeInterval(\"2016-01-01T00:00\", \"2016-12-31T23:59:59\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Next, let's compute an ``AgeTest`` to translate the following logic:\n", | |
"\n", | |
"```\n", | |
"Population Criteria:\n", | |
" Initial Population =\n", | |
" AND: Age>= 18 year(s) at: \"Measurement Period\"\n", | |
" AND: Age< 85 year(s) at: \"Measurement Period\"\n", | |
"```\n", | |
"\n", | |
"We need to first retrieve the ``BirthDate`` from the sample data. Then, we use ``AgeAt`` which computes the number of years between a date provided and start of the interval. In a reusable module, ``BirthDate`` could be defined once and used as needed. As we can see by testing this query fragment independently, all of the sample patients in our database pass the age test." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"12-element composite vector of {String, DateTime, Int64, Bool}:\n", | |
" (\"2_N_GP_Adult\",1981-05-29T01:56:00,34,true) \n", | |
" (\"A_Heart_Adult\",1946-02-01T11:30:00,69,true) \n", | |
" (\"B_Heart_Adult\",1946-02-01T15:00:00,69,true) \n", | |
" (\"C_N_GP_Adult\",1941-01-02T15:30:00,74,true) \n", | |
" (\"Z14_N_GP_Adult\",1968-02-14T15:25:00,47,true) \n", | |
" (\"Z1_Pregnancy_Adult\",1992-10-01T15:00:00,23,true)\n", | |
" (\"Z2_N_Heart_Adult\",1946-02-01T11:30:00,69,true) \n", | |
" (\"Z4_Heart_Adult\",1946-02-01T15:00:00,69,true) \n", | |
" (\"Z5_Heart_Adult\",1969-08-26T15:30:00,46,true) \n", | |
" (\"Z6_N_Heart_Adult\",1967-01-24T00:00:00,48,true) \n", | |
" (\"Z7_Heart_Adult\",1959-01-26T00:00:00,56,true) \n", | |
" (\"Z9_GP_Geriatric\",1941-02-07T15:30:00,74,true) " | |
] | |
}, | |
"execution_count": 5, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"BirthDateConcept = ToConcept(\"SNOMED-CT\",\"184099003\")\n", | |
"BirthDate = (\n", | |
" Frame(\n", | |
" Observation\n", | |
" >> ThenFilter(AnyOf(Observable .== BirthDateConcept))\n", | |
" >> Initiation\n", | |
" >> ThenUnique\n", | |
" ) >> ThenExpectOne)\n", | |
"\n", | |
"AgeFrom(young, old) = (\n", | |
" AgeAt(BirthDate, MeasurePeriod) .>= Const(young) &\n", | |
" AgeAt(BirthDate, MeasurePeriod) .< Const(old)\n", | |
")\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient \n", | |
" >> ThenSelect(\n", | |
" Handle,\n", | |
" BirthDate,\n", | |
" AgeAt(BirthDate, MeasurePeriod),\n", | |
" AgeFrom(18,85)\n", | |
" )\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Let's create a ``VisitTest`` that computes the following:\n", | |
"\n", | |
"```\n", | |
"Initial Population =\n", | |
" ...\n", | |
" AND: Union of:\n", | |
" \"Encounter, Performed: Office Visit\"\n", | |
" \"Encounter, Performed: Face-to-Face Interaction\"\n", | |
" \"Encounter, Performed: Preventive Care Services -\n", | |
" Established Office Visit, 18 and Up\"\n", | |
" \"Encounter, Performed: Preventive Care Services -\n", | |
" Initial Office Visit, 18 and Up\"\n", | |
" \"Encounter, Performed: Home Healthcare Services\"\n", | |
" \"Encounter, Performed: Annual Wellness Visit\"\n", | |
" during \"Measurement Period\"\n", | |
"```\n", | |
"\n", | |
"As we'll see, all 12 sample patients meet this criteria as well. " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"12-element composite vector of {String, Int64, Date*}:\n", | |
" (\"2_N_GP_Adult\",2,Date[2016-04-03,2016-06-23]) \n", | |
" (\"A_Heart_Adult\",3,Date[2016-03-01,2016-07-01,2016-12-20])\n", | |
" (\"B_Heart_Adult\",2,Date[2016-03-01,2016-12-20]) \n", | |
" (\"C_N_GP_Adult\",3,Date[2016-03-01,2016-07-01,2016-10-01]) \n", | |
" (\"Z14_N_GP_Adult\",1,Date[2016-03-05]) \n", | |
" (\"Z1_Pregnancy_Adult\",2,Date[2016-02-11,2016-03-08]) \n", | |
" (\"Z2_N_Heart_Adult\",2,Date[2016-03-01,2016-06-10]) \n", | |
" (\"Z4_Heart_Adult\",2,Date[2016-03-01,2016-12-20]) \n", | |
" (\"Z5_Heart_Adult\",1,Date[2016-02-12]) \n", | |
" (\"Z6_N_Heart_Adult\",2,Date[2016-03-04,2016-05-01]) \n", | |
" (\"Z7_Heart_Adult\",2,Date[2016-03-04,2016-05-01]) \n", | |
" (\"Z9_GP_Geriatric\",2,Date[2016-01-07,2016-07-10]) " | |
] | |
}, | |
"execution_count": 6, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"EntryMatching(EntryKind, Temporality, \n", | |
" TheInterval, Sets...) = (\n", | |
" EntryKind\n", | |
" >> ThenFilter(\n", | |
" AnyOf(Category .== Merge(Sets...)))\n", | |
" >> ThenFilter(Temporality(TheInterval))\n", | |
")\n", | |
"\n", | |
"Interactions = EntryMatching(\n", | |
" Encounter, During, MeasurePeriod,\n", | |
" OfficeVisit,\n", | |
" FaceToFaceInteraction, \n", | |
" PreventiveCareServicesEstablishedOfficeVisit18AndUp,\n", | |
" PreventiveCareServicesInitialOfficeVisit18AndUp,\n", | |
" HomeHealthcareServices,\n", | |
" AnnualWellnessVisit)\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient \n", | |
" >> ThenFilter(Exists(Interactions))\n", | |
" >> ThenSelect(\n", | |
" Handle,\n", | |
" Count(Interactions),\n", | |
" Interactions >> PeriodStart >> AsDate\n", | |
" )\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Next, we need to define a particular *Occurance* of a diagnosis that is used later on to compare against exams and other encounters. Logically, the test below could be reframed more simply, that the Entry overlaps the ``FirstSixMonths`` of the measure period.\n", | |
"\n", | |
"```\n", | |
"Initial Population =\n", | |
" ...\n", | |
" AND: \"Occurrence A of Diagnosis: Essential Hypertension\" \n", | |
" satisfies any:\n", | |
" < 6 month(s) starts after start of \"Measurement Period\"\n", | |
" satisfies all:\n", | |
" starts before start of \"Measurement Period\"\n", | |
" overlaps \"Measurement Period\"\n", | |
"```\n", | |
"\n", | |
"Unsurprisingly, all 12 synthetic patients (which were designed to be in the denominator) match this criteria as well." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"12-element composite vector of {String, Int64, Date*}:\n", | |
" (\"2_N_GP_Adult\",1,Date[2003-06-03]) \n", | |
" (\"A_Heart_Adult\",1,Date[2016-03-01]) \n", | |
" (\"B_Heart_Adult\",1,Date[2016-03-01]) \n", | |
" (\"C_N_GP_Adult\",1,Date[2015-03-01]) \n", | |
" (\"Z14_N_GP_Adult\",1,Date[2016-03-05]) \n", | |
" (\"Z1_Pregnancy_Adult\",1,Date[2015-04-03])\n", | |
" (\"Z2_N_Heart_Adult\",1,Date[2016-03-01]) \n", | |
" (\"Z4_Heart_Adult\",1,Date[2016-03-01]) \n", | |
" (\"Z5_Heart_Adult\",1,Date[2015-08-01]) \n", | |
" (\"Z6_N_Heart_Adult\",1,Date[2008-08-07]) \n", | |
" (\"Z7_Heart_Adult\",1,Date[2008-08-07]) \n", | |
" (\"Z9_GP_Geriatric\",1,Date[1991-03-02]) " | |
] | |
}, | |
"execution_count": 7, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"FirstSixMonths = ToInterval(\n", | |
" MeasurePeriod >> ThenLeft,\n", | |
" MeasurePeriod >> ThenLeft \n", | |
" .+ Const(Dates.Month(6)) \n", | |
" .- Const(Dates.Second(1)))\n", | |
"\n", | |
"HypertensionDx = EntryMatching(\n", | |
" Observation, Overlaps, FirstSixMonths,\n", | |
" EssentialHypertension)\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient \n", | |
" >> ThenFilter(Exists(HypertensionDx))\n", | |
" >> ThenSelect(\n", | |
" Handle,\n", | |
" Count(HypertensionDx),\n", | |
" HypertensionDx >> Initiation >> AsDate\n", | |
" )\n", | |
")\n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Putting these together, we get our Denominator.\n", | |
"\n", | |
"```\n", | |
"Initial Population = \n", | |
" AND: <age-test as above>\n", | |
" AND: <occurance-of-diagnosis as above>\n", | |
" AND: <has-office-visit as above>\n", | |
"Denominator =\n", | |
" AND: Initial Population\n", | |
"```\n", | |
"\n", | |
"Since each of the 3 criteria above match, the overall denominator; as each patient in our test deck satisfies all 3 criteria, our whole test deck is in the denominator." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"12-element Array{String,1}:\n", | |
" \"2_N_GP_Adult\" \n", | |
" \"A_Heart_Adult\" \n", | |
" \"B_Heart_Adult\" \n", | |
" \"C_N_GP_Adult\" \n", | |
" \"Z14_N_GP_Adult\" \n", | |
" \"Z1_Pregnancy_Adult\"\n", | |
" \"Z2_N_Heart_Adult\" \n", | |
" \"Z4_Heart_Adult\" \n", | |
" \"Z5_Heart_Adult\" \n", | |
" \"Z6_N_Heart_Adult\" \n", | |
" \"Z7_Heart_Adult\" \n", | |
" \"Z9_GP_Geriatric\" " | |
] | |
}, | |
"execution_count": 8, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"InPopulation = (\n", | |
" AgeFrom(18, 85) & \n", | |
" Exists(Interactions) & \n", | |
" Exists(HypertensionDx)\n", | |
")\n", | |
"\n", | |
"InDenominator = InPopulation\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient\n", | |
" >> ThenFilter(InDenominator)\n", | |
" >> Handle\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The measure also defines a set of exclusions which do not count against the Physican even though they may fail the numerator (positive outcome) test.\n", | |
"\n", | |
"```\n", | |
"Denominator Exclusions =\n", | |
"OR: \"Encounter, Performed: Encounter Inpatient (discharge \n", | |
" status: Discharged to Home for Hospice Care)\" \n", | |
" ends during \"Measurement Period\"\n", | |
"OR: \"Encounter, Performed: Encounter Inpatient (discharge \n", | |
" status: Discharged to Health Care Facility for Hospice Care)\" \n", | |
" ends during \"Measurement Period\"\n", | |
"OR: Union of:\n", | |
" \"Intervention, Order: Hospice care ambulatory\"\n", | |
" \"Intervention, Performed: Hospice care ambulatory\"\n", | |
" overlaps \"Measurement Period\"\n", | |
"OR: Union of:\n", | |
" \"Diagnosis: Pregnancy\"\n", | |
" \"Diagnosis: End Stage Renal Disease\"\n", | |
" \"Diagnosis: Chronic Kidney Disease, Stage 5\"\n", | |
" overlaps \"Measurement Period\"\n", | |
"OR: Union of:\n", | |
" \"Procedure, Performed: Vascular Access for Dialysis\"\n", | |
" \"Encounter, Performed: ESRD Monthly Outpatient Services\"\n", | |
" \"Procedure, Performed: Kidney Transplant\"\n", | |
" \"Procedure, Performed: Dialysis Services\"\n", | |
" starts before end of \"Measurement Period\" \n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"6-element Array{String,1}:\n", | |
" \"2_N_GP_Adult\" \n", | |
" \"C_N_GP_Adult\" \n", | |
" \"Z1_Pregnancy_Adult\"\n", | |
" \"Z5_Heart_Adult\" \n", | |
" \"Z6_N_Heart_Adult\" \n", | |
" \"Z7_Heart_Adult\" " | |
] | |
}, | |
"execution_count": 9, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"InDenominatorExclusions = InDenominator & Exists(\n", | |
" Merge(\n", | |
" EntryMatching(\n", | |
" Encounter, EndsDuring, MeasurePeriod,\n", | |
" EncounterInpatient)\n", | |
" >> ThenFilter( Const(true)\n", | |
" # These didn't make it into the FHIR data?\n", | |
" # AnyOf(Discharge .== DischargedHospiceHome)\n", | |
" # | AnyOf(Discharge .== DischargedHospiceFacility)),\n", | |
" ),\n", | |
" EntryMatching(\n", | |
" Observation, Overlaps, MeasurePeriod,\n", | |
" Pregnancy, EndStageRenalDisease,\n", | |
" ChronicKidneyDiseaseStage5),\n", | |
" EntryMatching(\n", | |
" Action, StartsBeforeEndOf, MeasurePeriod,\n", | |
" HospiceCareAmbulatory),\n", | |
" EntryMatching(\n", | |
" Request, StartsBeforeEndOf, MeasurePeriod,\n", | |
" HospiceCareAmbulatory),\n", | |
" EntryMatching(\n", | |
" Encounter, StartsBeforeEndOf, MeasurePeriod,\n", | |
" ESRDMonthlyOutpatientServices), \n", | |
" EntryMatching(\n", | |
" Action, StartsBeforeEndOf, MeasurePeriod,\n", | |
" DialysisEducation, \n", | |
" OtherServicesRelatedToDialysis),\n", | |
" EntryMatching(\n", | |
" Action, StartsBeforeEndOf, MeasurePeriod,\n", | |
" KidneyTransplant, VascularAccessForDialysis, \n", | |
" DialysisServices)\n", | |
"))\n", | |
" \n", | |
"query_ihm(\n", | |
" Patient\n", | |
" >> ThenFilter(InDenominatorExclusions)\n", | |
" >> Handle\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The numerator condition identifies a successful outcome. This is a two stage criteria. First, it specifies that we're looking at only the most recent qualifying encounter where a physical exams were performed. Second, it tests the results of those exams.\n", | |
"```\n", | |
"Numerator =\n", | |
" AND: Most Recent:\n", | |
" \"Occurrence A of Encounter, Performed: Adult Outpatient Visit\"\n", | |
" satisfies all:\n", | |
" overlaps \"Occurrence A of Diagnosis: Essential Hypertension\"\n", | |
" during \"Measurement Period\"\n", | |
" overlaps \"Physical Exam, Performed: Diastolic Blood Pressure (result)\"\n", | |
" overlaps \"Physical Exam, Performed: Systolic Blood Pressure (result)\"\n", | |
" ...\n", | |
"```\n", | |
"\n", | |
"This is essentially a 4-way product of entries: the encounter, the diagnosis, and two physical exam records. We're after the latest encounter during the measure period that has these characteristics. In our context-sensitive language, we create sets of 3 time periods for the diagnosis and exams. Then we search for encounters that overlap. \n", | |
"\n", | |
"In this prototype, there is a current complication with this multi-pass query. We need effectively 4 cursors through the data and the normal combinator path is restricted to just one. The ``Using`` combinator permits 3 of the 4 to be given a name and referenced in the 4th. The ``Gnisu`` function simply retrives the cursor defined in the ``Using``. Further, only constants (ie, ``Interval``) can easily be used. In subsequent versions of this impementation a more elegant approach will be explored. " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"4-element composite vector of {String, DateTime*}:\n", | |
" (\"A_Heart_Adult\",DateTime[2016-03-01T17:00:00]) \n", | |
" (\"B_Heart_Adult\",DateTime[2016-12-20T17:00:00]) \n", | |
" (\"Z14_N_GP_Adult\",DateTime[2016-03-05T08:00:00])\n", | |
" (\"Z4_Heart_Adult\",DateTime[2016-12-20T17:00:00])" | |
] | |
}, | |
"execution_count": 10, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"\n", | |
"DiastolicExam = (\n", | |
" EntryMatching(\n", | |
" Observation, During, MeasurePeriod,\n", | |
" DiastolicBloodPressure)\n", | |
" >> ThenFilter(Exists(Result)))\n", | |
"\n", | |
"SystolicExam = (\n", | |
" EntryMatching(\n", | |
" Observation, During, MeasurePeriod,\n", | |
" SystolicBloodPressure)\n", | |
" >> ThenFilter(Exists(Result)))\n", | |
"\n", | |
"ThenMostRecent = (\n", | |
" ThenSort(PeriodStart) \n", | |
" >> ThenSkip(-1)\n", | |
")\n", | |
"\n", | |
"ExamVisit = WithThisPatient(\n", | |
" EntryMatching(\n", | |
" Encounter, During, MeasurePeriod,\n", | |
" AdultOutpatientVisit)\n", | |
" >> ThenFilter(\n", | |
" AnyOf(Overlaps(ThisPatient >> HypertensionDx)) &\n", | |
" AnyOf(Overlaps(ThisPatient >> DiastolicExam)) &\n", | |
" AnyOf(Overlaps(ThisPatient >> SystolicExam)))\n", | |
" >> ThenMostRecent\n", | |
")\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient\n", | |
" >> ThenFilter(Exists(ExamVisit))\n", | |
" >> ThenSelect(\n", | |
" Handle,\n", | |
" ExamVisit >> PeriodStart)\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Now that we have the target visit, let's extract the blood pressure readings." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"4-element composite vector of {String, Int64?, Int64?}:\n", | |
" (\"A_Heart_Adult\",150,90) \n", | |
" (\"B_Heart_Adult\",130,60) \n", | |
" (\"Z14_N_GP_Adult\",194,102)\n", | |
" (\"Z4_Heart_Adult\",130,60) " | |
] | |
}, | |
"execution_count": 11, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"GetReading(ExamType) = WithThisPatient(\n", | |
" ExamType\n", | |
" >> ThenFilter(\n", | |
" AnyOf(During(ThisPatient >> ExamVisit)))\n", | |
" >> ThenMostRecent\n", | |
" >> Result\n", | |
" >> Scalar\n", | |
" >> ThenExpectAtMostOne\n", | |
")\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient\n", | |
" >> ThenFilter(Exists(ExamVisit))\n", | |
" >> ThenSelect(\n", | |
" Handle,\n", | |
" GetReading(SystolicExam),\n", | |
" GetReading(DiastolicExam))\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Then, it's time to finish the Numerator.\n", | |
"\n", | |
"```\n", | |
"Numerator =\n", | |
" ... \n", | |
" AND: \"Physical Exam, Performed: Diastolic Blood Pressure\"\n", | |
" satisfies all:\n", | |
" Most Recent:\n", | |
" during \"Occurrence A of Encounter, Performed: Adult Outpatient Visit\"\n", | |
" (result < 90 mmHg)\n", | |
" AND: \"Physical Exam, Performed: Systolic Blood Pressure\"\n", | |
" satisfies all:\n", | |
" Most Recent:\n", | |
" during \"Occurrence A of Encounter, Performed: Adult Outpatient Visit\"\n", | |
" (result < 140 mmHg)\n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"12-element composite vector of {String, Bool, Bool, Bool}:\n", | |
" (\"2_N_GP_Adult\",false,true,true) \n", | |
" (\"A_Heart_Adult\",false,true,false) \n", | |
" (\"B_Heart_Adult\",true,true,false) \n", | |
" (\"C_N_GP_Adult\",false,true,true) \n", | |
" (\"Z14_N_GP_Adult\",false,true,false) \n", | |
" (\"Z1_Pregnancy_Adult\",false,true,true)\n", | |
" (\"Z2_N_Heart_Adult\",false,true,false) \n", | |
" (\"Z4_Heart_Adult\",true,true,false) \n", | |
" (\"Z5_Heart_Adult\",false,true,true) \n", | |
" (\"Z6_N_Heart_Adult\",false,true,true) \n", | |
" (\"Z7_Heart_Adult\",false,true,true) \n", | |
" (\"Z9_GP_Geriatric\",false,true,false) " | |
] | |
}, | |
"execution_count": 12, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"InNumerator = (\n", | |
" InDenominator &\n", | |
" ~InDenominatorExclusions &\n", | |
" AnyOf(GetReading(SystolicExam) .< 140) &\n", | |
" AnyOf(GetReading(DiastolicExam) .< 90)\n", | |
")\n", | |
"\n", | |
"query_ihm(\n", | |
" Patient \n", | |
" >> ThenSelect(\n", | |
" Handle,\n", | |
" InNumerator, \n", | |
" InDenominator,\n", | |
" InDenominatorExclusions)\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**Offical Results**\n", | |
"```\n", | |
"+--------------------------------------------------------+\n", | |
"|*Patient* |*Numerator*|*Denominator*|*Exclusion*|\n", | |
"|2_N_GP_Adult |false |true |true |\n", | |
"|A_Heart_Adult |false |true |false |\n", | |
"|B_Heart_Adult |true |true |false |\n", | |
"|C_N_GP_Adult |false |true |true |\n", | |
"|Z14_N_GP_Adult |false |true |false |\n", | |
"|Z1_Pregnancy_Adult|false |true |true |\n", | |
"|Z2_N_Heart_Adult |false |true |false |\n", | |
"|Z4_Heart_Adult |true |true |false |\n", | |
"|Z5_Heart_Adult |false |true |true |\n", | |
"|Z6_N_Heart_Adult |false |true |true |\n", | |
"|Z7_Heart_Adult |false |true |true |\n", | |
"|Z9_GP_Geriatric |false |true |false |\n", | |
"+--------------------------------------------------------+\n", | |
"```" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Julia 0.5.2", | |
"language": "julia", | |
"name": "julia-0.5" | |
}, | |
"language_info": { | |
"file_extension": ".jl", | |
"mimetype": "application/julia", | |
"name": "julia", | |
"version": "0.5.2" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment