Tutorial

Predicting Sepsis in the ICU with Recurrent Neural Networks (MIMIC-III)

Difficulty: Advanced Time: 25 min read

Introduction

Sepsis is a life-threatening condition that arises when the body's response to infection causes injury to its own tissues and organs. Early detection in the ICU is critical. In this tutorial, we will use the open-source MIMIC-III database to extract vital signs and lab results, and train a Recurrent Neural Network (GRU/LSTM) to predict the onset of sepsis hours before clinical recognition.

Prerequisites

  • Python 3.10+
  • PyTorch, Pandas, Numpy, Scikit-Learn
  • Credentialed access to the MIMIC-III database via PhysioNet

Step 1: Data Extraction via Google BigQuery

MIMIC-III can be hosted on BigQuery for rapid extraction. We extract hourly time-series data for Heart Rate, Blood Pressure, Temperature, Respiratory Rate, and WBC counts, along with the Sepsis-3 clinical label (based on SOFA score deterioration).

from google.cloud import bigquery
import pandas as pd

client = bigquery.Client()

query = """
SELECT icustay_id, charttime, 
       MAX(CASE WHEN itemid IN (211,220045) THEN valuenum ELSE NULL END) AS HeartRate,
       MAX(CASE WHEN itemid IN (678,223761) THEN valuenum ELSE NULL END) AS Temperature,
       -- Additional vitals and labs omitted for brevity
       sepsis_label
FROM `physionet-data.mimiciii_clinical.chartevents`
JOIN `physionet-data.mimiciii_derived.sepsis3` USING (icustay_id)
GROUP BY icustay_id, charttime
ORDER BY icustay_id, charttime
"""

df = client.query(query).to_dataframe()

Step 2: Preprocessing and Windowing

We convert the raw data into sliding windows (e.g., 6 hours of history to predict the next 4 hours). We also handle missing values using forward fill and mean imputation, as clinical data is highly irregular.

import numpy as np

def create_windows(df, window_size=6, horizon=4):
    X, y = [], []
    for stay_id, group in df.groupby('icustay_id'):
        group = group.sort_values('charttime').ffill().fillna(0)
        vitals = group[['HeartRate', 'Temperature']].values
        labels = group['sepsis_label'].values
        
        for i in range(len(vitals) - window_size - horizon):
            X.append(vitals[i : i + window_size])
            y.append(labels[i + window_size + horizon - 1])
            
    return np.array(X), np.array(y)

X, y = create_windows(df)

Step 3: Training the GRU Model

Gated Recurrent Units (GRUs) are highly effective at capturing temporal dependencies in clinical data without the vanishing gradient problem.

import torch
import torch.nn as nn

class SepsisGRU(nn.Module):
    def __init__(self, input_dim, hidden_dim):
        super(SepsisGRU, self).__init__()
        self.gru = nn.GRU(input_dim, hidden_dim, batch_first=True, num_layers=2, dropout=0.2)
        self.fc = nn.Linear(hidden_dim, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        _, h_n = self.gru(x)
        out = self.fc(h_n[-1]) # Take the last layer's hidden state
        return self.sigmoid(out)

model = SepsisGRU(input_dim=X.shape[2], hidden_dim=64)
# Standard PyTorch BCELoss training loop follows...

Conclusion

By leveraging sequential models like GRUs on rich ICU time-series data like MIMIC-III, hospitals can deploy early warning systems to flag high-risk patients long before physiological decompensation becomes obvious to the naked eye.