Jointly fitting multiple data sources

Nowcasting and forecasting of infectious disease dynamics

Building models iteratively

In this course we have been building models iteratively — each session added a piece and checked it.

This is the Bayesian workflow

A Bayesian workflow is the iterative loop of building, checking, and revising a model.

Bayesian Workflow (Gelman et al., 2026)

The workflow loop

Build Check Revise

A workflow for infectious disease modelling

A workflow for infectious disease modelling. Figure by Abbott et al. (MIT licence).

Reading the workflow

  1. Question & estimands — infections and \(R_t\)

Process model

  1. Process model — one shared renewal process

Data source selection

  1. Data source selection — catalogue each data source and how it is biased

Observation model per source

  1. Observation model per source — a delay + a scaling + a likelihood

What is a DAG?

A directed acyclic graph draws a model as a picture. Each quantity is a node, and an arrow runs from a quantity to whatever it generates.

  • Read top to bottom, it traces how the data come about
  • The arrows make the model’s conditional independence assumptions explicit

The DAG is the TLDR of the model.

Modularise

  1. Modularise — split into sub-models that can be checked on their own

Inference & computation choices

  1. Inference & computation choices — how to fit the model

Implementation

  1. Implementation — write the model

Model validation

  1. Model validation — check each piece against data

Data integration

  1. Data integration — how to combine the data sources; conflict reveals misspecification

The question

Our target is unchanged: recover the latent infections and \(R_t\) as quickly and with as little bias as we can.

Now we introduce our data sources

To answer that question we bring in several data sources at once, each a delayed, scaled view of the same infections:

  • Cases — timely, but depend on testing; only a fraction ascertained
  • Deaths — stable, but long-delayed and severity-dependent
  • Wastewater — independent of care-seeking; thought to lead cases, but indirect, noisy, and on its own scale

Wastewater: a tangent

What is wastewater surveillance?

Measuring pathogen RNA shed into sewage — a population-level signal.

Why people are interested:

  • Does not depend on testing, care-seeking, or ascertainment
  • Thought to lead case reports, and picks up asymptomatic infection
  • Relatively cheap at scale (one sample covers a whole catchment)

Challenges: it is noisy and indirect, and needs scaling / normalisation before it can be compared to infections.

A DAG for wastewater

From infections to what we measure:

Infections Shedding (viral load, delayed) Sewer transport (dilution, decay) Sampling & assay (sub-sample, measure) Observed concentration ~ LogNormal

Back to joint modelling

Three data sources from one trajectory

Each data source is a delayed, rescaled echo of the same infection curve.

Steps 2–4 in one picture

We defined the question (step 1). This is steps 2–4: the shared process, the data sources, and an observation model for each — every data source a convolution of the shared latent infections, conditionally independent given \(I\).

\[ \text{cases}_t \sim f\big(\text{convolve}(I, p_\text{cases})\big), \quad \text{deaths}_t \sim g\big(\text{convolve}(I, p_\text{deaths})\big) \]

delay + ascertainment delay + IFR delay + scaling Rt (geometric random walk) Shared latent infections I Cases Deaths Wastewater

Build it in parts

  1. Each data source on its own — does it recover infections through its delay and scaling?
  2. Link two data sources — cases + deaths share one infection process
  3. Add the third — wastewater too; infections and \(R_t\) informed by all
  4. Stress-test — what happens when data sources conflict?

Each data source implies its own answer to “what did infections look like?”

  • changing ascertainment (testing policy)
  • mis-specified delays or scalings (e.g. drifting IFR)
  • truly different populations

Conflict distorts the joint fit

A single shared \(I\) can’t be both falling (cases, wastewater) and rising (deaths), so the model splits the difference.

Your Turn

  1. Simulate parallel data sources from one shared infection trajectory
  2. Fit each data source alone, then link them through the shared infections
  3. Recover infections and \(R_t\) from the joint fit
  4. Make the deaths conflict, see the joint model surface it, then resolve it by modelling the mechanism

Return to the session