Predicting Sepsis in the ICU with Recurrent Neural Networks (MIMIC-III)
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.