-
Notifications
You must be signed in to change notification settings - Fork 154
Quality measure definitions
popHealth is a open source software tool that automates population health reporting quality measures. popHealth integrates with a healthcare provider's electronic health record (EHR) system to produce summary quality measures on the provider's patient population.
popHealth demonstrates how a provider can use popHealth to analyze the quality of care provided as part of their existing workflow. popHealth helps providers easily understand the logic behind clinical quality measures and easily identifies patients requiring follow-up care. The transmission of summary quality data is simple and scalable, representing an alternative to traditional methods of data analysis and reporting. popHealth’s design leverages the generation of Continuity of Care records from a provider’s EHR to produce the clinical quality measure reports. Specifically, popHealth accepts patient data via either the HITSP CCD/C32 XML or ASTM CCR XML continuity of care standards. popHealth provides a streamlined mechanism for sending data on summary quality measures from individual providers to public health organizations, via the PQRI reporting standard.
Calculation of quality measures in popHealth proceeds in two stages. In the first stage patient records are imported from their native format (CCR or C32) and measure-specific properties are extracted to build a denormalized record optimized for the second stage of calculation.
Patient summaries (CCRs and C32s) are imported into popHealth by using HTTP to POST the XML documents to a specific URL in the web application. popHealth will then examine the contents of the file and determine whether to use the CCR or C32 normalization logic. While the implementations for these routines are different, conceptually they are the same. Each section of a patient summary, such as medications or vital signs, is reduced to a set of "entries." An entry represents a single point of data in a patient summary and the term is borrowed from CDA parlance. Entries contain the following data fields:
- Times - such as start, end or point in time values
- Codes - including the vocabulary used - if multiple codes are provided, they are all retained
- Status (optional) - appears in certain sections, such as conditions
- Value (optional) - sometimes required for vital signs or results
popHealth's C32 normalizer used XPath expressions to search the XML and create entries. An XPath expression is created for each section. The CCR normalizer uses Java code that has been generated from the CCR XML Schema. These codes is are then used to create entries. Entries are grouped by the section that they correspond to.
Each quality measure has a JSON definition, where each piece of data needed for the measure is defined in a "property". Measure properties contain the following information:
- Name - a name for the property, such as "outpatient encounter"
- Standard category - These categories are obtained from the measure definition spreadsheets. It is a description of where the information may be found, such as "medications" or "condition / diagnosis / problem"
- Schema - The structure of the information needed for the property. This may be a point in time value, such as an outpatient encounter. It may be a time and a value, such as a blood pressure reading. Finally, it can be a date range, such as the duration of a condition
- Codes - Lists of codes that are relevant for this property, grouped by code set The standard categories and codes can be used to examine the normalized record to extract measure specific information.
Each measure property has a standard category. Based on this standard category, popHealth will examine groups of entries in an attempt to find data points of interest. For instance, a measure property may check to see if a patient is a tobacco user. This property would fall into the "characteristic" standard category and entries in the conditions and social history groups will be examined.
popHealth will check codes in entries to see if they match codes for the property. Going back to the tobacco user example, there will be a list of codes that are associated with tobacco use. popHealth will check entries in conditions and social history to see if any of them have codes that match. If codes match a value will be generated according to the property schema.
All of the measure properties are grouped together and output as part of a JSON patient record. At the top level, the patient record contains basic demographic information: name, date of birth and gender. Then denormalized measure information grouped by measure. Each measure group has its set of properties with values extracted from the patient summary document.
A resulting record will have the following form: { "first": "Irma", "last": "Bloggs", "gender": "F", "birthdate": -290390400, "measures": { "0018": { "encounter_outpatient": [1266537600, 1277856000], "hypertension": 1266537600, "systolic_blood_pressure": [ { "date": 1266537600, "value": 180 }, { "date": 1277856000, "value": 138 } ], "diastolic_blood_pressure": [ { "date": 1266537600, "value": 100 }, { "date": 1277856000, "value": 85 } ] } } }
In this example, we are showing a patient with a single measure. Dates and times in the measures are represented in seconds since the epoch. This is a female patient born on October 18, 1960. Her record lists two outpatient encounters (February 19, 2010 and June 30, 2010). This means that her patient summary document had two encounter entries with codes that matched codes listed for outpatient encounters for the measure. Her patient summary had a condition of hypertension and two blood pressure readings taken at her outpatient encounters.
In the second stage of quality measure calculation in popHealth, each denormalized patient record is compared against the measure criteria for the population, denominator, numerator and exclusions using a runtime-supplied measurement period end date. popHealth uses the popular map-reduce approach when calculating quality measure results for a set of patient records.
Map-reduce is an algorithm that is used to calculate summary results over a large set of input data. It is widely used in "big data" problems, most notably by Google as the foundation of their Web search engine. As its name suggests, map-reduce proceeds in two distinct steps, the first 'map' step takes as input a single item of raw data and maps it to a summary data format. The second 'reduce' step takes a set of summary data produced by the 'map' step and outputs a summary of that set. This is perhaps best explained by a simple example: consider a set of patients that we need to summarize based on eye color, the input to the map function would be a single native patient record, the output of the map function would be a data structure containing a map of eye-color to count of patients with that color.
Since the map function only 'sees' a single patient record at a time, typically only one color value would be non-zero and that value would be one. The reduce function would take as input a list of map function output data structures and simply sum the values for each eye-color over the list, producing the same data structure but now with summary data for a set of patients. The reduce operation can be applied iteratively since its output format is the same as its input. E.g. you could evaluate the reduce function on groups of 100 results of the map function and then evaluate the reduce function a second time on the outputs of the first set of reduce functions to summarize over all groups. Map-reduce has some important properties that make it suitable for large-scale calculations:
- Each map function evaluation is isolated and only requires access to a single input record to proceed. This allows many map functions to be run in parallel, either using separate threads within a process or distributing the work amongst a set of processes on a server farm.
- Reduce functions can be applied iteratively allowing the work of reducing the output of map functions to be split amongst a set of workers and easily combined by a coordinator using a final reduce function execution. The net result of (1) and (2) is that native input data can easily be sharded across a set of servers and a map-reduce calculation made across all shards with minimal coordination. Each shard can work in isolation and the results for each shard are easily combined.
See the Map-Reduce Wikipedia article for more information on map-reduce.
In popHealth each measure is expressed as a map function whose output indicates whether a particular patient met the population, denominator, numerator and exclusion criteria for that measure. popHealth is built on MongoDB, a document oriented database which has a native map-reduce capability based on JavaScript. Each measure is expressed as an anonymous JavaScript function template, a simple example is the Pneumonia Vaccination measure
popHealth also supplies a set of JavaScript library functions that ensure consistency of output and simplify working with the de-normalized patient data. Function templates are converted into actual JavaScript functions at runtime by substituting a value for the effective date and inserting the popHealth-supplied library function definitions.
popHealth uses the same reduce function for all measures, it simply sums the patients that meet each of the population, denominator, numerator and exclusion criteria.
For performance reasons, measure results are cached after calculation in the MongoDB database using the measure number and effective date as keys. If new patient records are added the results are recalculated on demand.