Bayesian SIR
Posted on
Compartment models are commonly used in epidemiology to model epidemics. Compartmental model are composed of differential equations and captured some “knowns” regarding disease transmission. Because these models seek to simulate/ model the epidemic process directly, they are are somewhat more resistant to some biases (e.g. missing data). Strong-ish assumptions must be made regarding disease transmission and varying level of detail can be included in order to make the models closer to reality.
This post is largely an extension of Bayesian workflow for disease transmission modeling in Stan.
Data Generating Process
First we need to define our data generating process. Here we will start with a four compartment model with no births or deaths. This will represent an immunizing infection with a latent phase.
<-
%>%
%>%
%>%
%>%
%>%
%>%
%>%
a_graph
<script type="application/json" data-for="htmlwidget-088e44bc215058a6321c">{"x":{"diagram":"digraph {\n\ngraph [layout = \"neato\",\n outputorder = \"edgesfirst\",\n bgcolor = \"white\"]\n\nnode [fontname = \"Helvetica\",\n fontsize = \"10\",\n shape = \"circle\",\n fixedsize = \"true\",\n width = \"0.5\",\n style = \"filled\",\n fillcolor = \"aliceblue\",\n color = \"gray70\",\n fontcolor = \"gray50\"]\n\nedge [fontname = \"Helvetica\",\n fontsize = \"8\",\n len = \"1.5\",\n color = \"gray80\",\n arrowsize = \"0.5\"]\n\n \"1\" [label = \"S\", fillcolor = \"#FFA500\", fontcolor = \"#FFFFFF\", pos = \"-0.328318803243628,-2.21410603834674!\"] \n \"2\" [label = \"E\", fillcolor = \"#FFA500\", fontcolor = \"#FFFFFF\", pos = \"-0.719160158456506,-1.06013657993252!\"] \n \"3\" [label = \"I\", fillcolor = \"#FFA500\", fontcolor = \"#FFFFFF\", pos = \"-1.14817109805578,0.206529571496933!\"] \n \"4\" [label = \"R\", fillcolor = \"#FFA500\", fontcolor = \"#FFFFFF\", pos = \"-1.53748912027061,1.35600130943722!\"] \n \"1\"->\"2\" \n \"2\"->\"3\" \n \"3\"->\"4\" \n}","config":{"engine":"dot","options":null}},"evals":[],"jsHooks":[]}</script>
Simulate an Epidemic with Knowns
Now we can build this hypothetical epidemic using the “deSolve” package from R. Ideally, we will be able to recover our model parameters using our Bayesian model. This gives us confidence in fitting real data that we observe. This is a key step in the Bayesian workflow where we generate fake data, fit the fake data, and then examine the fit to ensure that we recover the real parameter before we fit our observed data.
{
# create state variables (local variables)
S = state_values # susceptibles
E = state_values # exposed
I = state_values # infectious
R = state_values # recovered
N = state_values + state_values + state_values +state_values
}
beta_value <- 1/3
gamma_value <- 1/10
delta_value <- 1/4
parameter_list <-
times <- 1:120
initial_values <-
output =
We can extract the daily incidence using the following equation. This represents what would typically be reported by authorities. To make it more realistic, it would be good to convolve the cases with a delay distribution to indicate the lag we observe in case reporting. A deconvolution step could then be written into Stan in order to account for this delay distribution.
cases <-
cases <- cases
Now let’s calculate our basic reproduction number or
beta_value/gamma_value
Build Model in Stan
Now we can build the model in Stan as shown below. Ideally, I would write the ODE solver using the new syntax, but I’ll leave that to next time. We can see that the differential equations have been built into the “sir” function.
mod <-
mod$
Build Dataset
Now we can prep our dataset for Stan.
# total count
N <- 1000;
# times
n_days <- +1
t <-
t0 = 0
t <- t
#initial conditions
i0 <- 1
e0 <- 0
s0 <- N - i0
r0 <- 0
y0 =
Run the Model
Then we can run it using CmdStanR.
# number of MCMC steps
niter <- 2000
n_pred <- 21
data_sir<-
fit <- mod$
fit_sir<- rstan::
rstan::->y_pred
med_estimates <-
Review Model Outputs
Let’s see if we recovered our actual parameters (yes, it appears so)!
pars=
fit$
Visualise the Epidemic Curve
Finally, we can visualise our model outputs and see if we capture our actual cases. Additionally, I am using ggdist to capture the full range of possibilities as discussed in in my previous blog post
%>%
%>%
%>%
tidyr:: %>%
%>%
%>%
%>%
+
+
+
+
+
+
Looks like this model adequately captured our fake data! Part 2 will fit some real data.
Citation
BibTex citation:
@online{dewitt2020
author = {Michael E. DeWitt},
title = {Bayesian SIR},
date = 2020-08-28,
url = {https://michaeldewittjr.com/articles/2020-08-28-bayesian-sir},
langid = {en}
}
For attribution, please cite this work as:
Michael E. DeWitt. 2020. "Bayesian SIR." August 28, 2020. https://michaeldewittjr.com/articles/2020-08-28-bayesian-sir