Investigating dosing of vancomycin

This notebook aims to investigate dosing of vancomycin in MIMIC-III.


In [1]:
# Import libraries
from __future__ import print_function


import numpy as np
import pandas as pd
import psycopg2
import socket
import sys
import os
import getpass

from collections import OrderedDict

import matplotlib
import matplotlib.pyplot as plt

# colours for prettier plots
import colorsys
def gg_color_hue(n):
    hues = np.linspace(15, 375, n)
    hsv_tuples = [(x*1.0/360.0, 0.5, 0.8) for x in hues]
    rgb_tuples = map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)
    return rgb_tuples

marker = ['v','o','d','^','s','o','+']
ls = ['-','-','-','-','-','s','--','--']

from IPython.display import display, HTML

# plot settings
%matplotlib inline
plt.style.use('ggplot')
font = {'size'   : 20}
matplotlib.rc('font', **font)

In [2]:
sqluser = getpass.getuser()
print('Using username {}'.format(sqluser))

dbname = 'mimic'
schema_name = 'mimiciii'
query_schema = 'SET search_path to public,' + schema_name + ';'

# Connect to local postgres version of mimic
con = psycopg2.connect(dbname=dbname, user=sqluser)

print('Connected to postgres {}.{}.{}!'.format(int(con.server_version/10000),
                                              int((con.server_version - int(con.server_version/10000)*10000)/100),
                                              int(con.server_version - int(con.server_version/100)*100)))


Using username alistairewj
Connected to postgres 10.0.1!

Determine vancomycin drug names in prescriptions table


In [3]:
query = query_schema + """
SELECT drug_name_generic, drug_name_poe, drug, count(*) as numobs
FROM prescriptions
WHERE lower(drug) LIKE '%vanco%'
OR lower(drug_name_generic) LIKE '%vanco%'
OR lower(drug_name_poe) LIKE '%vanco%'
GROUP BY drug, drug_name_generic, drug_name_poe
ORDER BY drug_name_generic, drug_name_poe, drug;
"""
df = pd.read_sql_query(query, con)
df


Out[3]:
drug_name_generic drug_name_poe drug numobs
0 Vancocin Vancocin Vancocin 2
1 Vancomycin Vancomycin Vancomycin 7
2 Vancomycin 25mg/mL Ophth Soln Vancomycin 25mg/mL Ophth Soln Vancomycin 25mg/mL Ophth Soln 24
3 Vancomycin Desensitization Vancomycin Desensitization Vancomycin Desensitization 7
4 Vancomycin Enema Vancomycin Vancomycin 2
5 Vancomycin Enema Vancomycin Vancomycin 1
6 Vancomycin Enema Vancomycin Enema Vancomycin Enema 92
7 vancoMYCIN for inhalation vancoMYCIN for inhalation vancoMYCIN for inhalation 1
8 vancoMYCIN for nasal inhalation vancoMYCIN for nasal inhalation vancoMYCIN for nasal inhalation 1
9 Vancomycin fortified opthalmic Vancomycin fortified opthalmic Vancomycin fortified opthalmic 2
10 Vancomycin HCl Vancomycin Vancomycin 1
11 Vancomycin HCl Vancomycin HCl Vancomycin HCl 2
12 Vancomycin HCl None Vancomycin HCl 2
13 Vancomycin ophthalmic 50mg/ml Vancomycin ophthalmic 50mg/ml Vancomycin ophthalmic 50mg/ml 1
14 Vancomycin ophthalmic solution Vancomycin ophthalmic solution Vancomycin ophthalmic solution 1
15 Vancomycin Oral Liquid Vancomycin Vancomycin 7
16 Vancomycin Oral Liquid Vancomycin Oral Liquid Vancomycin Oral Liquid 2613
17 None None NEO*IV*Vancomycin 898
18 None None Vancomycin 42618
19 None None Vancomycin Antibiotic Lock 41
20 None None Vancomycin Desensitization 31
21 None None Vancomycin Enema 208
22 None None Vancomycin HCl 22287
23 None None Vancomycin Intrathecal 24
24 None None Vancomycin Intraventricular 4

The following will be deleted as we are only concerned with vancomycin administered intravenously:

  • 'Vancomycin 25mg/mL Ophth Soln', - eye use
  • 'Vancomycin Enema' - rectal use
  • 'Vancomycin Intrathecal', - cerebral spinal fluid injection
  • 'Vancomycin Intraventricular', - cerebral shunt injection
  • 'Vancomycin Oral Liquid', - oral use
  • 'Vancomycin fortified opthalmic', - eye use
  • 'Vancomycin ophthalmic 50mg/ml', - eye use
  • 'Vancomycin ophthalmic solution', - eye use
  • 'vancoMYCIN for inhalation', - nasal use
  • 'vancoMYCIN for nasal inhalation' - nasal use

From above we keep ...

drug in 
(
     'NEO*IV*Vancomycin', 'Vancocin', 'Vancomycin',
     'Vancomycin ', 'Vancomycin Antibiotic Lock',
     'Vancomycin Desensitization', 'Vancomycin HCl'
)

Next, we determine which itemids from labevents to keep.


In [22]:
query = query_schema + """
SELECT *
FROM d_labitems
WHERE lower(label) like '%vanco%'
"""
pd.read_sql_query(query, con)


Out[22]:
row_id itemid label fluid category loinc_code
0 209 51009 Vancomycin Blood Chemistry 20578-1

From above, we keep everything!

Next, we check which itemids from chartevents to keep.


In [26]:
query = query_schema + """
SELECT *
FROM d_items
WHERE lower(label) like '%vanco%'
AND dbsource = 'metavision'
"""
pd.read_sql_query(query, con)


Out[26]:
row_id itemid label abbreviation dbsource linksto category unitname param_type conceptid
0 14767 227453 Vancomycin (Peak) Vancomycin (Peak) metavision chartevents Labs None Numeric with tag None
1 14768 227454 Vancomycin (Random) Vancomycin (Random) metavision chartevents Labs None Numeric with tag None
2 14769 227455 Vancomycin (Trough) Vancomycin (Trough) metavision chartevents Labs None Numeric with tag None
3 13982 225798 Vancomycin Vancomycin metavision inputevents_mv Antibiotics dose Solution None
4 14134 225697 ZVancomycin (Peak) ZVancomycin (Peak) metavision chartevents Labs None Numeric None
5 14346 226064 ZVancomycin (Trough) ZVancomycin (Trough) metavision chartevents Labs None Numeric None
6 14347 226065 ZVancomycin (Random) ZVancomycin (Random) metavision chartevents Labs None Numeric None

In carevue, Alistair said they don't record vancomycin administration time so we will only consider data from metavision.

We also only care about trough values and vancomycin administration. So from above we keep ...

itemid in 
(
     227455, 225798, 226064
)

Define helper functions

The first function gets data from each table for a given subject_id. It outputs the data as a tuple of dataframes.


In [4]:
def get_data_for_subject(subject_id, query_schema, con):
    # lab data
    query = query_schema + """
    select
          subject_id, hadm_id, di.itemid, di.label
        , charttime, value, valuenum, valueuom, flag
    from labevents le
    inner join d_labitems di
      on le.itemid = di.itemid
    where subject_id = {}
    and di.itemid = 51009 order by charttime;
    """.format(subject_id)
    lab = pd.read_sql_query(query, con)

    # charted data
    query = query_schema + """
    select 
          subject_id, hadm_id, icustay_id
        , di.itemid, di.label
        , charttime, storetime
        , value, valuenum, valueuom
        , error, resultstatus
    from chartevents ce
    inner join d_items di
      on ce.itemid = di.itemid
    where subject_id = {}
    and di.itemid in
    (
      854, 855, 856, 1354, 5873, 3827, 3828, 2273, 3679, 6261
      , 227453, 227454, 227455, 225697, 226064, 226065
    )
    order by charttime;
    """.format(subject_id)
    ce = pd.read_sql_query(query, con)


    # input data (mv)
    query = query_schema + """
    select 
          subject_id, hadm_id, icustay_id
        , di.itemid, di.label
        , starttime, endtime, storetime
        , rate, rateuom
        , amount, amountuom
        , statusdescription
    from inputevents_mv mv
    inner join d_items di
      on mv.itemid = di.itemid
    where subject_id = {} 
    and di.itemid = 225798
    order by starttime;
    """.format(subject_id)
    imv = pd.read_sql_query(query, con)

    # no vanco data in CV

    # prescriptions
    query = query_schema + """
    select *
    from prescriptions
    where subject_id = {} 
    and drug in 
    (
          'Vancomycin HCl', 'Vancomycin Oral Liquid', 'NEO*IV*Vancomycin'
        , 'Vancomycin', 'Vancomycin Antibiotic Lock' , 'Vancomycin Desensitization'
        , 'Vancomycin HCl', 'Vancomycin Intrathecal', '    Vancomycin Intraventricular'
        , 'Vancocin'
    )
    order by startdate;
    """.format(subject_id)
    pr = pd.read_sql_query(query, con)

    # transfers info
    query = query_schema + """
    select * from transfers
    where subject_id = {};
    """.format(subject_id)
    tr = pd.read_sql_query(query, con)
    
    return lab, ce, imv, pr, tr

The second function combines the individual dataframes into a single dataframe. It does this by combining columns together - so while data in a single column no longer consistently represents the same concept, it is easier to read.


In [7]:
# union the above dataframes together by renaming columns etc
# column names are no longer 100% correct but it's easier to interpret the data this way
def combine_into_single_dataframe(lab, ce, imv, pr, tr):
    cols = ['subject_id', 'hadm_id', 'source', 'label', 'charttime', 'endtime', 'value', 'valuenum']

    lab['endtime'] = None
    lab['source'] = 'lab'

    ce['endtime'] = None
    ce['source'] = 'chart'
    
    imv['charttime'] = imv['starttime']
    imv['value'] = imv['amount'].astype(str)
    imv['valuenum'] = imv['rate']
    imv['source'] = 'inputs'

    pr['charttime'] = pr['startdate']
    pr['endtime'] = pr['enddate']
    pr['value'] = pr['route']
    pr['label'] = pr['drug']
    pr['valuenum'] = pr['dose_val_rx']
    pr['source'] = 'poe'

    # add in the start/end time of ICU
    icu_admit = tr.loc[ (~tr['curr_careunit'].isnull()), :].copy()
    icu_disch = tr.loc[ (~tr['curr_careunit'].isnull()), :].copy()

    icu_admit['source'] = 'icu admit'
    icu_disch['source'] = 'icu disch'
    icu_admit['endtime'] = None
    icu_disch['endtime'] = None
    icu_admit['valuenum'] = None
    icu_disch['valuenum'] = None
    
    icu_rename_dict = {'icustay_id': 'label', 'curr_careunit': 'value'}
    icu_admit.rename( icu_rename_dict, axis=1, inplace=True )
    icu_disch.rename( icu_rename_dict, axis=1, inplace=True )
    
    # set charttine - for admission, its intime, for discharge, its outtime
    icu_admit.rename({'intime': 'charttime'}, axis=1, inplace=True)
    icu_disch.rename({'outtime': 'charttime'}, axis=1, inplace=True)

    df = pd.concat([ lab[cols], ce[cols], imv[cols], pr[cols], icu_admit[cols], icu_disch[cols] ],
                   axis=0, ignore_index=True )

    df.sort_values('charttime', ascending=True, inplace=True)
    df.reset_index(drop=True, inplace=True)
    
    return df

In [8]:
# pick the subject
subject_id = 97920

# get data for this subject
lab, ce, imv, pr, tr = get_data_for_subject(subject_id, query_schema, con)
# combine dataframes together
df = combine_into_single_dataframe(lab, ce, imv, pr, tr)

# drop subject/hadm_id
df.drop(['subject_id', 'hadm_id'], axis=1, inplace=True)

# display dataframe
display(HTML(df.to_html().replace('None','')))


source label charttime endtime value valuenum
0 poe Vancomycin 2168-06-18 00:00:00 2168-06-19 00:00:00 IV 1000
1 icu admit 240678 2168-06-18 01:08:37 TSICU
2 inputs Vancomycin 2168-06-18 09:04:00 2168-06-18 09:05:00 1.0
3 inputs Vancomycin 2168-06-18 20:48:00 2168-06-18 20:49:00 1.0
4 poe Vancomycin 2168-06-19 00:00:00 2168-06-21 00:00:00 IV 1000
5 lab Vancomycin 2168-06-19 04:25:00 6.1 6.1
6 chart Vancomycin (Random) 2168-06-19 05:25:00 6.1 6.1
7 inputs Vancomycin 2168-06-19 08:29:00 2168-06-19 08:30:00 1.0
8 inputs Vancomycin 2168-06-19 16:24:00 2168-06-19 16:25:00 1.0
9 icu disch 240678 2168-06-19 22:20:01 TSICU
10 lab Vancomycin 2168-06-20 15:25:00 9.2 9.2
11 poe Vancomycin 2168-06-21 00:00:00 2168-06-24 00:00:00 IV 1250
12 lab Vancomycin 2168-06-22 18:30:00 10.6 10.6
13 lab Vancomycin 2168-06-24 04:58:00 57.4 57.4
14 lab Vancomycin 2168-06-25 04:14:00 35.4 35.4
15 poe Vancomycin 2168-06-28 00:00:00 2168-06-28 00:00:00 IV 1000
16 lab Vancomycin 2168-06-28 04:51:00 8.4 8.4

The above makes sense - summarizing the flow:

  • Prescription on the 18th
  • Admitted to the ICU on the 18th (1am)
  • IV infusion on the 18th (9am, 8pm)
  • Prescription on the 19th-21st
  • Measured vanco on 19th
  • IV on the 19th (8am, 4pm)
  • Discharged from the ICU
  • POE/lab measurements continue from 20th onward

We can try another subject.


In [9]:
# pick the subject
subject_id = 94864

# get data for this subject
lab, ce, imv, pr, tr = get_data_for_subject(subject_id, query_schema, con)
# combine dataframes together
df = combine_into_single_dataframe(lab, ce, imv, pr, tr)

# drop subject/hadm_id
df.drop(['subject_id', 'hadm_id'], axis=1, inplace=True)

# display dataframe
display(HTML(df.to_html().replace('None','')))


source label charttime endtime value valuenum
0 icu admit 288166 2179-12-10 20:15:49 MICU
1 poe Vancomycin 2179-12-11 00:00:00 2179-12-12 00:00:00 IV 1000
2 poe Vancomycin 2179-12-11 00:00:00 2179-12-12 00:00:00 IV 1000
3 inputs Vancomycin 2179-12-11 01:20:00 2179-12-11 01:21:00 1.0
4 lab Vancomycin 2179-12-11 03:44:00 43.9 43.9
5 chart Vancomycin (Random) 2179-12-11 03:44:00 43.9 43.9
6 poe Vancomycin 2179-12-12 00:00:00 2179-12-17 00:00:00 IV 1000
7 lab Vancomycin 2179-12-12 03:29:00 20.6 20.6
8 chart Vancomycin (Random) 2179-12-12 03:29:00 20.6 20.6
9 lab Vancomycin 2179-12-13 06:00:00 14.3 14.3
10 chart Vancomycin (Random) 2179-12-13 06:00:00 14.3 14.3
11 inputs Vancomycin 2179-12-13 08:00:00 2179-12-13 08:01:00 1.0
12 lab Vancomycin 2179-12-14 05:41:00 15.3 15.3
13 chart Vancomycin (Random) 2179-12-14 05:41:00 15.3 15.3
14 inputs Vancomycin 2179-12-14 08:30:00 2179-12-14 08:31:00 1.0
15 chart Vancomycin (Random) 2179-12-15 05:54:00 15.7 15.7
16 lab Vancomycin 2179-12-15 05:54:00 15.7 15.7
17 chart Vancomycin (Trough) 2179-12-16 06:07:00 16.8 16.8
18 lab Vancomycin 2179-12-16 06:07:00 16.8 16.8
19 inputs Vancomycin 2179-12-16 08:00:00 2179-12-16 08:01:00 1.0
20 poe Vancomycin 2179-12-17 00:00:00 2179-12-20 00:00:00 IV 1000
21 lab Vancomycin 2179-12-17 06:01:00 24.7 24.7
22 chart Vancomycin (Trough) 2179-12-17 06:01:00 24.7 24.7
23 chart Vancomycin (Random) 2179-12-18 05:43:00 7.4 7.4
24 lab Vancomycin 2179-12-18 05:43:00 7.4 7.4
25 icu disch 288166 2179-12-18 20:51:40 MICU
26 lab Vancomycin 2179-12-20 11:00:00 27.3 27.3

The above is mostly sensible - except perhaps for rows 16/17. Here, we can an increase in vancomycin levels, but we don't have an associated dose to explain it.


In [10]:
# pick the subject
subject_id = 357

# get data for this subject
lab, ce, imv, pr, tr = get_data_for_subject(subject_id, query_schema, con)
# combine dataframes together
df = combine_into_single_dataframe(lab, ce, imv, pr, tr)

# drop subject/hadm_id
df.drop(['subject_id', 'hadm_id'], axis=1, inplace=True)

# display dataframe

display(HTML(df.to_html().replace('None','')))


source label charttime endtime value valuenum
0 icu admit 228283 2197-12-06 07:13:48 MICU
1 poe Vancomycin HCl 2197-12-11 00:00:00 2197-12-15 00:00:00 IV 1000
2 chart Vancomycin/Random 2197-12-12 07:31:00 10.4 10.4
3 lab Vancomycin 2197-12-12 07:31:00 10.4 10.4
4 poe Vancomycin HCl 2197-12-14 00:00:00 2197-12-15 00:00:00 IV 1000
5 icu disch 228283 2197-12-26 15:26:37 MICU
6 icu admit 248896 2198-08-02 04:50:02 MICU
7 icu disch 248896 2198-08-04 01:55:49 MICU
8 icu admit 248896 2198-08-04 13:34:15 SICU
9 poe Vancomycin 2198-08-07 00:00:00 2198-08-10 00:00:00 IV 1000
10 chart Vancomycin/Random 2198-08-08 17:46:00 16.3 16.3
11 lab Vancomycin 2198-08-08 17:46:00 16.3 16.3
12 poe Vancomycin 2198-08-10 00:00:00 2198-08-14 00:00:00 IV 1000
13 lab Vancomycin 2198-08-11 05:00:00 22.0 22
14 chart Vancomycin/Random 2198-08-11 05:00:00 22 22
15 chart Vancomycin/Random 2198-08-12 06:59:00 11.5 11.5
16 lab Vancomycin 2198-08-12 06:59:00 11.5 11.5
17 lab Vancomycin 2198-08-13 05:33:00 11.6 11.6
18 chart Vancomycin/Random 2198-08-13 05:33:00 11.6 11.6
19 poe Vancomycin 2198-08-14 00:00:00 2198-08-21 00:00:00 IV 1000
20 chart Vancomycin/Random 2198-08-14 00:46:00 12.1 12.1
21 lab Vancomycin 2198-08-14 00:46:00 12.1 12.1
22 lab Vancomycin 2198-08-15 19:00:00 17.8 17.8
23 chart Vancomycin/Random 2198-08-15 19:00:00 17.8 17.8
24 icu disch 248896 2198-09-20 16:55:55 SICU
25 poe Vancomycin 2198-09-24 00:00:00 2198-10-15 00:00:00 IV 1000
26 lab Vancomycin 2198-09-26 05:15:00 15.3 15.3
27 icu admit 273842 2198-11-01 22:39:10 MICU
28 icu disch 273842 2198-11-12 00:07:12 MICU
29 poe Vancomycin 2199-10-20 00:00:00 2199-10-23 00:00:00 IV 1000
30 icu admit 259107 2199-10-20 12:06:08 CCU
31 inputs Vancomycin 2199-10-20 22:33:00 2199-10-20 22:34:00 1.0
32 icu disch 259107 2199-10-21 10:18:24 CCU
33 poe Vancomycin 2199-12-22 00:00:00 2199-12-23 00:00:00 IV 1000
34 icu admit 235292 2199-12-24 19:52:27 SICU
35 poe Vancomycin 2199-12-25 00:00:00 2199-12-26 00:00:00 IV 1000
36 inputs Vancomycin 2199-12-25 01:00:00 2199-12-25 01:01:00 1.0
37 inputs Vancomycin 2199-12-25 08:00:00 2199-12-25 08:01:00 1.0
38 inputs Vancomycin 2199-12-25 20:00:00 2199-12-25 20:01:00 1.0
39 inputs Vancomycin 2199-12-26 08:00:00 2199-12-26 08:01:00 1.0
40 icu disch 235292 2200-01-07 21:24:42 SICU

This patient is admitted under the carevue system, and unfortunately we do not have documentation of IV antibiotics for these patients. However, we note that the prescriptions ('poe') appear to match the charted data.

For the last few rows, it is odd that there is no measurement of vancomycin between the 25th-26th.

Conclusion

Care should be taken when comparing dosing of vancomycin given with the value measured. Reducing the time resolution required for a study (e.g. to the day) may help smooth over slight inconsistencies.


In [11]:
con.close()