Implementing a sepsis definition motivated development of the constellation package. There is ongoing debate in the medical literature about what constitutes sepsis, but our local team of clinical experts agreed to define sepsis as the occurrence of all 3 following criteria:
For each criteria, there is both a threshold to signify dysfunction as well as a relevant time window to search for events. A major challenge of working with medical data is that the sampling rate varies across measurements. For example, vital signs are sampled more frequently than blood labs, so their information is carried forward for a shorter period of time than lab results.
There are 3 steps to identify sepsis and each step corresponds to a constellation function:
Lastly, it may be required to separate distinct sepsis episodes during a single inpatient admission. For example, you may consider that sepsis events separated by more than 72 hours are distinct episodes that require additional evaluation and treatment. Thus, instances within 72 hours of an incident event are considered to be the same episode and instances separated by a minimum of 72 hours are considered to be distinct episodes. This logic is implemented via the incidents() function.
The .Rmd version of the vignette will not show code output. If you'd like to see code output, please do the following:
library(constellation) vignette("identify_sepsis", package = "constellation")
First, load constellation and fasttime
library(constellation) library(data.table)
Next, prep the timestamps
for (dt in list(vitals, labs, orders)) { date_col <- grep("TIME", names(dt), value = TRUE) set(dt, j = date_col, value = as.POSIXct(dt[[date_col]], format = "%Y-%m-%dT%H:%M:%SZ", tz = "UTC")) }
Use this function to identify all instances of a drop in systolic blood pressure of greater than 40 within 6 hours.
systolic_bp <- vitals[VARIABLE == "SYSTOLIC_BP"] systolic_bp_drop <- value_change(systolic_bp, value = 40, direction = "down", window_hours = 6, join_key = "PAT_ID", time_var = "RECORDED_TIME", value_var = "VALUE", mult = "all") head(systolic_bp_drop)
First, break out all the SIRS component tables applying dysfunction thresholds
temp <- vitals[VARIABLE == "TEMPERATURE" & (VALUE > 100.4 | VALUE < 96.8)] pulse <- vitals[VARIABLE == "PULSE" & VALUE > 90] resp <- vitals[VARIABLE == "RESPIRATORY_RATE" & VALUE > 20] wbc <- labs[VARIABLE == "WBC" & (VALUE > 12 | VALUE < 4)]
Next, identify which criteria are met at every measurement time
sirs <- constellate_criteria(temp, pulse, resp, wbc, criteria_names = c("TEMPERATURE", "PULSE", "RESPIRATORY_RATE", "WBC"), window_hours = c(6, 6, 6, 24), join_key = "PAT_ID", time_var = "RECORDED_TIME") head(sirs)
Sum values in the 4 columns to calculate SIRS score at every measurement time and subset to instances where SIRS >= 2
sirs[, SIRS_SCORE := TEMPERATURE + PULSE + RESPIRATORY_RATE + WBC] sirs <- sirs[SIRS_SCORE >= 2] head(sirs)
First, build a table that combines all measurements for end organ damage:
## Subset values end_organ <- labs[ (VARIABLE == "CREATININE" & VALUE > 2.0) | (VARIABLE == "INR" & VALUE > 1.5) | (VARIABLE == "BILIRUBIN" & VALUE > 2.0) | (VARIABLE == "PLATELETS" & VALUE < 100) | (VARIABLE == "LACTATE" & VALUE >= 2.0) ] ## normalize systolic_bp_drop systolic_bp_drop <- systolic_bp_drop[,.(PAT_ID, CURRENT_RECORDED_TIME, CURRENT_VALUE)] systolic_bp_drop[, VARIABLE := "SYSTOLIC_BP_DROP"] setnames(systolic_bp_drop, c("CURRENT_RECORDED_TIME", "CURRENT_VALUE"), c("RECORDED_TIME", "VALUE")) ## subset low systolic_bp systolic_bp <- systolic_bp[VALUE < 90] ## Combine SBP drop and < 90 end_organ <- rbind(end_organ, systolic_bp, systolic_bp_drop)
Normalize blood culture order data to feed into constellate() function. The timestamp variable in all time series data frames passed to constellate() must be identical.
setnames(orders, "ORDER_TIME", "RECORDED_TIME")
Calculate the first instant in which all 3 criteria are met for every patient.
## Find first sepsis events sepsis <- constellate(sirs, orders, end_organ, window_hours = c(24, 24, 24), join_key = "PAT_ID", time_var = "RECORDED_TIME", event_name = "SEPSIS", mult = "first") head(sepsis)
Calculate the last instant in which all 3 criteria are met for every patient.
## Find last sepsis events sepsis <- constellate(sirs, orders, end_organ, window_hours = c(24, 24, 24), join_key = "PAT_ID", time_var = "RECORDED_TIME", event_name = "SEPSIS", mult = "last") head(sepsis)
Calculate every instance in which all 3 criteria are met for every patient.
## Find all sepsis events sepsis <- constellate(sirs, orders, end_organ, window_hours = c(24, 24, 24), join_key = "PAT_ID", time_var = "RECORDED_TIME", event_name = "SEPSIS", mult = "all") head(sepsis)
Separate sepsis events that occur more than 72 hours apart for each patient.
## Find incident sepsis events for each patient sepsis <- incidents(sepsis, window_hours = 72, time_var = "SEPSIS_TIME", join_key = "PAT_ID") head(sepsis)
If you'd like to learn more about our sepsis model, please see our publications from the International Conerence on Machine Learning and Machine Learning in Health Care.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.