This project builds a deep learning framework that models the dynamics of ICU physiological variables within a dynamical systems framework. The core idea: rather than treating vital signs as independent snapshots, we learn a latent space in which the patient's trajectory evolves according to a linear (Koopman) operator — then use the structure of that operator to understand patient physiology and personalise outcome prediction.
Source: eICU Collaborative Research Database
Data/vitalPeriodic_filtered.csv.gz— Hourly-binned vital signs per ICU admission. Features used:heartrate,respiration,sao2. Observations are aggregated by median within each hour bin and forward-filled within each patient stay.Data/patient_filtered.csv.gz— Patient-level metadata: age, gender, ethnicity, unit type, and discharge status (alive / expired).
Script: train_vae.py
A β-VAE maps hourly vital sign snapshots to a low-dimensional latent space (LATENT_DIM = 8).
The encoder compresses each observation x_t → z_t; the decoder reconstructs it.
Reconstruction loss uses a missingness mask so that unobserved features do not contribute. KL divergence is warmed up gradually to encourage a well-structured latent space.
Outputs saved to checkpoints/vae_*.
Evaluation: evaluate_vae.py — plots actual vs reconstructed vitals for held-out test patients.
Script: train_koopman.py
A linear Koopman operator A is learned such that:
z_{t+1} = A · z_t + b
The VAE is fine-tuned jointly with A using a multi-step prediction loss: rolling A forward k = 1…K steps and matching the encoder's representation of the true future observation x_{t+k}.
An L2-SP anchor term prevents the fine-tuned VAE from drifting far from its pretrained weights.
This forces the latent space to be linearly predictable — a core requirement of the Koopman framework.
Outputs saved to checkpoints/ft_koopman_*.
Script: analyze_koopman.py
The eigendecomposition of A reveals the dynamical modes of the system:
- Eigenvalue plot — shows spectral radius and stability (eigenvalues inside the unit circle → stable decay; outside → growth).
- Mode dynamics — each eigenvector
v_mdefines a direction in latent space; evolvingz(t) = λ_m^t · v_mand decoding gives the physiological signature of that mode. - Multi-step MSE — quantifies how well the Koopman model predicts held-out patient trajectories at horizons 1–6 hours.
- Population rollout — mean ± SEM of actual vs Koopman-predicted vitals across all test patients.
Outputs saved to results/koopman_analysis/.
Script: mode_outcome_prediction.py
Each test patient's latent trajectory is compared to each Koopman mode trajectory via MSE:
distance(patient p, mode m) = mean_t || z_p(t) − Re[λ_m^t · v_m] ||²
This distance measures how much a patient's dynamics resemble each population-level mode. A univariate logistic regression is trained per mode to predict in-hospital death (expired vs alive), and modes are ranked by AUROC. A combined model using all mode distances is also reported as a reference.
This is the personalisation step: the same dynamical system is shared across patients, but each patient is characterised by their proximity to each mode — capturing individual deviation from population dynamics.
Outputs saved to results/mode_outcome/.
Build a deep learning dynamical model that captures the temporal structure of ICU physiological variables in a linear dynamical systems framework (Koopman theory), and use the geometry of that framework to personalise patient characterisation — quantifying how an individual's trajectory deviates from population-level modes and linking that deviation to clinical outcomes.
├── model.py # VitalVAE architecture
├── train_vae.py # Step 1: VAE training
├── evaluate_vae.py # VAE reconstruction plots
├── train_koopman.py # Step 2: Koopman fine-tuning
├── analyze_koopman.py # Step 3: Mode analysis & visualisation
├── mode_outcome_prediction.py # Step 4: Personalised outcome prediction
├── checkpoints/ # Saved model weights & normalisation stats
├── Data/ # Input data (not versioned)
└── results/ # Output plots and CSVs
pip install -r requirements.txt