knitr::opts_chunk$set( collapse = TRUE, comment = "#>", paged.print = TRUE, df_print = "paged" )
Hospital patients with suspected infection are often treated with empirical antibiotics. Antibiotic treatment is usually reviewed 24--72 hours later. This often results in changes to the choice of drug, its dose, and/or route of administration. Ideally, these decisions are informed by microbial culture results from biological samples such as blood or urine.
Understanding how antibiotics are used in the hospital underpins effective antimicrobial stewardship. This requires knowledge of the sequence of prescribing events and requires information on:
Ramses reconstructs prescribing events relating to an individual: it creates antimicrobial therapy episodes, which link the set of antimicrobial prescriptions administered consecutively or concurrently in a given patient.
The diagrams below illustrates how to characterise prescribing events using Ramses.
Therapy episodes and therapy combinations are created automatically by Ramses when loading data (see methods). They are identified in the drug_prescriptions
table in variables therapy_id
and combination_id
.
library(Ramses) library(dplyr) ramses_db <- create_mock_database("ramses-db.duckdb") tbl(ramses_db, "drug_prescriptions") %>% filter(patient_id == "99999999998") %>% collect() %>% select(patient_id, prescription_id, combination_id, therapy_id, therapy_rank, prescription_text) %>% glimpse()
Therapy episodes are represented as objects of S4 class TherapyEpisode
.
uti_episode <- TherapyEpisode(ramses_db, "d7c0310a08cf9f0f318276125cd282ed") uti_episode
S4 class TherapyEpisode
is capable of handling multiple therapy episodes at once.
TherapyEpisode(ramses_db, c("d7c0310a08cf9f0f318276125cd282ed", "5528fc41106bb48eb4d48bc412e13e67"))
For more information on S4 classes used in Ramses and their associated methods, see the Objects and classes vignette.
Therapy episodes can be studied by creating a longitudinal, hour-by-hour matrix called 'longitudinal table'.
longitudinal_table(uti_episode, collect = TRUE) %>% select(t, therapy_start, therapy_end, t_start, t_end, parenteral)
longitudinal_table(uti_episode, collect = TRUE) %>% select(t, therapy_start, therapy_end, t_start, t_end, parenteral) %>% rmarkdown::paged_table()
This basic table can be enhanced with clinical features.
By default, route of therapy administration is indicated in the parenteral
field:
1
indicates that all drugs are administered via parenteral route (eg intravenously)0
indicates that at least one drug is administered via another route (eg orally)NA
marks short gaps between prescriptions.The parenteral_changes()
function extracts transitions from intravenous to oral therapy. The example below shows just one prescribing sequence that included intravenous therapy. This sequence was initiated at $t$ = 122, and ended at $t$ = 242, without ever being converted to oral administration (NA
).
parenteral_changes(uti_episode)
This function returns as many vectors as there are sequences of parenteral administration:
parenteral_changes(TherapyEpisode(ramses_db, "a028cf950c29ca73c01803b54642d513"))
In this example, parenteral therapy was first initiated at $t$ = 0, then converted to oral administration at $t$ = 97, until $t$ = 144. A new sequence of parenteral therapy begins at $t$ = 146, all within the same therapy episode.
Encounters (hospitalisations) can also be used to
generate longitudinal tables thanks to the Encounter()
function. In the example
below, an encounter table is created for the same patient 99999999998
for
encounter 8895465895
, which is the same admission during which antimicrobial
therapy episode d7c0310a08cf9f0f318276125cd282ed
was administered.
Like therapy tables, encounter tables can be enhanced with clinical features.
Encounter(ramses_db, "8895465895") %>% longitudinal_table(collect = TRUE) %>% select(t, admission_date, discharge_date, t_start, t_end)
Encounter(ramses_db, "8895465895") %>% longitudinal_table(collect = TRUE) %>% select(t, admission_date, discharge_date, t_start, t_end) %>% rmarkdown::paged_table()
Both therapy and encounter tables can be extended so they begin earlier than
the start of antimicrobial therapy, or the admission date, respectively. Doing
so is controlled by the TherapyEpisode()
and Encounter()
functions to
create the objects in the first place through an optional parameter
extend_table_start
. This parameter expresses how many hours earlier the table
should start.
For example, the encounter table can be made to begin 5 hours before admission. This can be very useful if the patient is known to have stayed in the Emergency Department before being admitted:
Encounter(ramses_db, "8895465895", extend_table_start = 5) %>% longitudinal_table(collect = TRUE) %>% select(t, admission_date, discharge_date, t_start, t_end)
Encounter(ramses_db, "8895465895", extend_table_start = 5) %>% longitudinal_table(collect = TRUE) %>% select(t, admission_date, discharge_date, t_start, t_end) %>% rmarkdown::paged_table()
The extend_table_start
parameter may also be used in the TherapyEpisode()
function.
Several functions can enhance both therapy and encounter tables with variables characterising the clinical state and trajectory of the patient. For instance, we may be interested in temperature:
clinical_feature_last()
fetches the most recent temperature value.clinical_feature_mean()
computes a running arithmetic mean of the temperature time series.clinical_feature_interval()
computes the number of observations falling within and outside a specified interval (eg 36°C--38°C) or lying below/above a specified threshold (eg 38°C).clinical_feature_ols_trend()
computes the Ordinary Least Square (OLS) trend; including the slope parameter, enabling to measure whether temperature has been rising/stable/falling.The example below demonstrates how to classify a patient as hypothermic/afebrile/febrile:
example_sepsis <- TherapyEpisode(ramses_db, "4d611fc8886c23ab047ad5f74e5080d7") %>% clinical_feature_last(observation_code = "8310-5", hours = 6) longitudinal_table(example_sepsis, collect = TRUE) %>% mutate( febrile = case_when( last_temperature_6h < 36 ~ "hypothermic", between(last_temperature_6h, 36, 38) ~ "afebrile", last_temperature_6h > 38 ~ "febrile", TRUE ~ NA_character_ ) ) %>% select(t, t_start, t_end, last_temperature_6h, febrile) %>% filter(t < 50)
Another example below tracks the blood neutrophil count, which provides insights into the patient's clinical progression following treatment. We want to know whether this parameter is going up, or down. The hours
parameter is set to 48 hours: the function will look at all neutrophil counts in the last 48 hours. This should ensure we capture two recent values and can compute a slope.
clinical_feature_ols_trend( x = example_sepsis, observation_code = "751-8", hours = 48 ) %>% longitudinal_table(collect = TRUE) %>% select(t, t_start, ols_neutrophils_48h_slope, ols_neutrophils_48h_intercept, ols_neutrophils_48h_N) %>% filter(between(t, 10, 14) | between(t, 80, 84))
Note that the intercept is defined for $t$ = t_start
. In other words, its value corresponds to the linear (straight line) extrapolation of the trend to t_start
.
We can see that, at the time of therapy initiation, the neutrophil count was increasing by an average 0.09 per nanoliter every hour (neutrophilia). After 80 hours (day 3), we find first evidence of the neutrophil count going down at a rate of 0.09 per nanoliter every hour, returning to a normal range (2--7.5 109/L). Depending on the patient's other vitals, this could indicate the infection is under control.
DBI::dbDisconnect(ramses_db, shutdown = TRUE) file.remove("ramses-db.duckdb")
Ramses links prescriptions together if:
antiinfective_type
: antibacterials are linked with antibacterials, antifungals with antifungals, etc.prescription_status
is not "draft"
, "entered-in-error"
, "cancelled"
, or "unknown"
.Ramses
links prescriptions into episodes and combinations in two instances:
load_medications()
functioncreate_therapy_episodes()
function.Both functions include a transitive_closure_controls
argument, which controls parameters for linking prescriptions together into episodes and/or combinations, based on patterns of overlap or time elapsed between prescriptions (see defaults in the table below).
To change the default settings, consult the documentation ?transitive_closure_control
.
Table: Prescription overlap pattern classification rules and default settings [@DuteyMagni2021]
Category | Pattern | Conditions for
combination therapy | Conditions for
continuation of therapy* |
:-: | :----: | ------------- | -------- |
1 | {.patternDiagram} | Ordered a max of 6h apart AND administrations separated by at the most 24h | Separated by at the most 36h |
2 | {.patternDiagram} | Ordered a max of 6h apart AND drug is identical AND first administrations separated by at the most 24h | Separated by at the most 36h |
3 | {.patternDiagram} | Never | Separated by at the most 36h |
4 | {.patternDiagram} | Never | Always |
5 | {.patternDiagram} | Ordered a max of 6h apart AND first administrations separated by at the most 24h | Always, unless combinations |
6 | {.patternDiagram} | Ordered a max of 6h apart AND first administrations separated by at the most 24h | Always, unless combinations |
7 | {.patternDiagram} | Never | Separated by at the most 36h |
Notes:
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.