The EpiModel package provides tools for simulating mathematical models of infectious disease dynamics. It supports three model classes:
All three model classes share a unified API: configure inputs with
param.*(), init.*(), and
control.*(), then run simulations with dcm(),
icm(), or netsim().
This vignette walks through the full network model pipeline, from network estimation through epidemic simulation and analysis.
Network models begin with specifying and estimating the contact network. We define a network of 500 people, then estimate an ERGM that produces networks with a target mean degree of 0.7 (175 edges), limited concurrency (no more than 110 nodes with 2+ partners), and no one with 4+ partners. Partnerships last an average of 50 time steps.
library(EpiModel)
set.seed(12345)
nw <- network_initialize(n = 500)
formation <- ~edges + concurrent + degrange(from = 4)
target.stats <- c(175, 110, 0)
coef.diss <- dissolution_coefs(
dissolution = ~offset(edges),
duration = 50 # mean partnership duration in time steps
)
est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE)
Before using the estimated network in an epidemic model, we diagnose
the fit. netdx simulates dynamic networks from the fitted
model and compares summary statistics against targets. This is a
critical validation step.
dx <- netdx(est, nsims = 5, nsteps = 500, verbose = FALSE)
The formation diagnostic shows how well the simulated networks maintain the target statistics (dashed lines) over time. The mean across simulations (solid line) and the interquartile range (shaded band) should track the targets closely:
plot(dx)
The duration diagnostic confirms that partnership durations match the specified target of 50 time steps:
plot(dx, type = "duration")
With a validated network model, we layer on the epidemic. This SIS model uses a per-act transmission probability of 0.4, 2 acts per partnership per time step, and a recovery rate of 0.05. We seed 10 infections and run 5 stochastic simulations for 500 time steps.
param <- param.net(inf.prob = 0.4, act.rate = 2, rec.rate = 0.05)
init <- init.net(i.num = 10)
control <- control.net(type = "SIS", nsims = 5, nsteps = 500, verbose = FALSE)
sim <- netsim(est, param, init, control)
The default plot shows compartment sizes over time, with the mean across simulations (solid line), individual simulation traces, and a shaded interquartile range capturing stochastic variability:
plot(sim, sim.lines = TRUE, sim.alpha = 0.3,
mean.lwd = 3, qnts = 0.5, main = "SIS Epidemic on a Dynamic Network")
For prevalence (proportions rather than counts), use
popfrac = TRUE:
plot(sim, y = "i.num", popfrac = TRUE, sim.lines = TRUE, sim.alpha = 0.3,
mean.lwd = 3, qnts = 0.5, main = "Infection Prevalence",
ylab = "Prevalence", legend = FALSE)
summary reports means, standard deviations, and
proportions across simulations at a specified time step:
summary(sim, at = 500)
##
## EpiModel Summary
## =======================
## Model class: netsim
##
## Simulation Details
## -----------------------
## Model type: SIS
## No. simulations: 5
## No. time steps: 500
## No. NW groups: 1
##
## Model Statistics
## ------------------------------
## Time: 500
## ------------------------------
## mean sd pct
## Suscept. 277.6 11.194 0.555
## Infect. 222.4 11.194 0.445
## Total 500.0 0.000 1.000
## S -> I 11.8 3.564 NA
## I -> S 13.8 4.970 NA
## ------------------------------
All epidemic data can be extracted as a data.frame for
custom analysis—per-simulation values, means, or standard deviations
across simulations:
d <- as.data.frame(sim)
head(d)
## sim time s.num i.num num si.flow is.flow
## 1 1 1 490 10 500 NA NA
## 2 1 2 484 16 500 6 0
## 3 1 3 481 19 500 4 1
## 4 1 4 480 20 500 2 1
## 5 1 5 479 21 500 5 4
## 6 1 6 472 28 500 7 0
The transmission matrix records every infection event: who infected whom, when, and with what probability. This can be converted into a phylogenetic tree to visualize chains of transmission.
# Run a separate SI model seeded with a single infection for a cleaner tree
set.seed(42)
param2 <- param.net(inf.prob = 0.5, act.rate = 2)
init2 <- init.net(i.num = 5)
control2 <- control.net(type = "SI", nsims = 1, nsteps = 60, verbose = FALSE)
sim2 <- netsim(est, param2, init2, control2)
tm <- get_transmat(sim2)
head(tm)
## # A tibble: 6 × 8
## # Groups: at, sus [6]
## at sus inf network infDur transProb actRate finalProb
## <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
## 1 2 100 55 1 22 0.5 2 0.75
## 2 2 500 55 1 22 0.5 2 0.75
## 3 3 141 462 1 44 0.5 2 0.75
## 4 4 175 141 1 1 0.5 2 0.75
## 5 5 223 418 1 5 0.5 2 0.75
## 6 16 414 418 1 16 0.5 2 0.75
tmPhylo <- as.phylo.transmat(tm)
## found multiple trees, returning a list of 3phylo objects
par(mar = c(2, 1, 2, 1))
plot(tmPhylo, show.node.label = TRUE, root.edge = TRUE, cex = 0.5,
main = "Transmission Tree")
Each tip is an infected person; each internal node (labeled with the infector’s ID) is a transmission event. The horizontal axis shows time, revealing when and how the epidemic branched through the network.
The built-in SI, SIR, and SIS models are starting points. EpiModel’s
extension API allows you to define custom models with arbitrary disease
states, demographics, interventions, and feedback between the epidemic
and the network. A custom module is simply a function that takes the
simulation state (dat) and current time step
(at), modifies state, and returns it:
# Example: a custom progression module for an SEIR model
progress_module <- function(dat, at) {
active <- get_attr(dat, "active")
status <- get_attr(dat, "status")
# E -> I transition
ids.EtoI <- which(active == 1 & status == "e" & runif(length(status)) < 0.1)
status[ids.EtoI] <- "i"
# I -> R transition
ids.ItoR <- which(active == 1 & status == "i" & runif(length(status)) < 0.02)
status[ids.ItoR] <- "r"
dat <- set_attr(dat, "status", status)
dat <- set_epi(dat, "ei.flow", at, length(ids.EtoI))
dat <- set_epi(dat, "ir.flow", at, length(ids.ItoR))
return(dat)
}
Custom modules are passed to control.net and integrated
into the simulation loop. The EpiModel Gallery
provides a library of worked extension examples, and the advanced
vignettes in this package document the full API.
We recommend the following tiered sequence for learning EpiModel, consistent with the learning pathway on the EpiModel website. This is oriented towards those interested in stochastic network models, the primary focus of EpiModel.
netest, netdx,
netsim).The current version of EpiModel is v2.6.1. Within the package, consult the help documentation for each exported function:
help(package = "EpiModel")
To see the latest updates, consult the NEWS file in the
package or our GitHub Releases (https://github.com/EpiModel/EpiModel/releases).
Technical coding questions, conceptual modeling questions, and feature requests may be posted as GitHub issues at our main repository (https://github.com/EpiModel/EpiModel/issues).
If using EpiModel for teaching or research, please include a citation to our primary methods paper:
Jenness SM, Goodreau SM and Morris M. EpiModel: An R Package for Mathematical Modeling of Infectious Disease over Networks. Journal of Statistical Software. 2018; 84(8): 1-47. doi: 10.18637/jss.v084.i08 (https://doi.org/10.18637/jss.v084.i08).