knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  paged.print = TRUE,
  df_print = "paged"
)

Introduction

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.

Therapy episodes in Ramses

Motivating example

The diagrams below illustrates how to characterise prescribing events using Ramses.

Diagram A: raw (unprocessed) electronic prescribing records
Diagram B: linked (processed) electronic prescribing records
  1. Based on unprocessed medical records alone, it is hard to characterise the chain of prescribing events.

    Patient X was prescribed nitrofurantoin (single dose + 3 day course) during a first encounter.

    Patient X re-presented to hospital 24 hours later and was treated with amoxicillin (1 day), gentamicin (single dose), and meropenem (5 day course).

  2. Ramses links prescriptions together (by transitive closure) to reconstruct the therapy episode, allowing more sophisticated observations:

    This makes it possible to determine that Patient X took antibiotics without interruption for 7 days.

    On first encounter, patient X was given a first dose of nitrofurantoin for a suspected lower urinary tract infection (UTI), then reviewed by a senior doctor and prescribed a three day course of the same antibiotic. The patient only spent one day in hospital during this period.

    During the following 24h, patient X’s worsening condition led them to re-present to hospital. Patient X was prescribed combination therapy (amoxicillin and a single dose of gentamicin). Patient X was prescribed combination therapy (amoxicillin and a single dose of gentamicin). The patient was reviewed 24 hours later, diagnosed with pyelonephritis and prescribed a 5-day course of meropenem.

Therapy episodes objects

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.

Longitudinal analysis

Therapy tables

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:

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.

Encounter tables

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()

Extended longitudinal tables

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.

Adding clinical features

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:

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")

Methodology

Prescription linkage

Ramses links prescriptions together if:

Ramses links prescriptions into episodes and combinations in two instances:

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 | Overlap pattern 1{.patternDiagram} | Ordered a max of 6h apart AND administrations separated by at the most 24h | Separated by at the most 36h | 2 | Overlap pattern 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 | Overlap pattern 3{.patternDiagram} | Never | Separated by at the most 36h | 4 | Overlap pattern 4{.patternDiagram} | Never | Always | 5 | Overlap pattern 5{.patternDiagram} | Ordered a max of 6h apart AND first administrations separated by at the most 24h | Always, unless combinations | 6 | Overlap pattern 6{.patternDiagram} | Ordered a max of 6h apart AND first administrations separated by at the most 24h | Always, unless combinations | 7 | Overlap pattern 7{.patternDiagram} | Never | Separated by at the most 36h |

Notes:

References



ramses-antibiotics/ramses-package documentation built on Feb. 13, 2024, 1:01 p.m.