| Title: | Mathematical Modeling of Infectious Disease Dynamics |
|---|---|
| Description: | Tools for simulating mathematical models of infectious disease dynamics. Epidemic model classes include deterministic compartmental models, stochastic individual-contact models, and stochastic network models. Network models use the robust statistical methods of exponential-family random graph models (ERGMs) from the Statnet suite of software packages in R. Standard templates for epidemic modeling include SI, SIR, and SIS disease types. EpiModel features an API for extending these templates to address novel scientific research aims. Full methods for EpiModel are detailed in Jenness et al. (2018, <doi:10.18637/jss.v084.i08>). |
| Authors: | Samuel Jenness [cre, aut], Steven M. Goodreau [aut], Martina Morris [aut], Adrien Le Guillou [aut], Chad Klumb [aut], Skye Bender-deMoll [ctb] |
| Maintainer: | Samuel Jenness <samuel.m.jenness@emory.edu> |
| License: | GPL-3 |
| Version: | 2.7.0 |
| Built: | 2026-10-17 13:57:39 UTC |
| Source: | https://github.com/epimodel/epimodel |
Tools for simulating mathematical models of infectious disease dynamics. Epidemic model classes include deterministic compartmental models, stochastic individual-contact models, and stochastic network models. Network models use the robust statistical methods of exponential-family random graph models (ERGMs) from the Statnet suite of software packages in R. Standard templates for epidemic modeling include SI, SIR, and SIS disease types. EpiModel features an API for extending these templates to address novel scientific research aims. Full methods for EpiModel are detailed in Jenness et al. (2018, doi:10.18637/jss.v084.i08).
EpiModel provides tools for building, simulating, and analyzing mathematical models of infectious disease dynamics. Models may be built for pedagogical purposes using the built-in disease types, or for research purposes using the extension API to define arbitrary disease states and processes.
The distinguishing capability of EpiModel is stochastic network modeling, in which partnerships form, persist, and dissolve according to a statistical model estimated from network data. Simpler compartmental and individual-based classes are also provided, both for teaching and for comparison against the network results.
EpiModel provides functionality for three classes of epidemic models:
Deterministic Compartmental Models (DCMs): continuous-time models
solved with ordinary differential equations, under an assumption of
random mixing within the population. Sensitivity analyses across
parameter values or initial conditions are specified by passing
vectors to param.dcm() or init.dcm().
Stochastic Individual Contact Models (ICMs): discrete-time, individual-based analogs of the DCM class, which add random variation to each component of the transmission system, from infection to recovery to vital dynamics (arrivals and departures). Contacts are randomly mixed, with no persistent partnership structure.
Stochastic Network Models: discrete-time, individual-based models in which the contact structure is represented explicitly as a dynamic network. Partnership formation and dissolution are simulated from a temporal exponential-family random graph model (TERGM), using the statistical framework implemented in the Statnet suite of R packages. Disease then spreads across the edges of that evolving network. This class represents features that random mixing cannot, including degree distributions, partnership duration, concurrency, assortative mixing, and feedback between network structure and epidemic dynamics.
EpiModel supports three built-in infectious disease types, available across all three model classes, in one-group and two-group configurations and with or without demography:
Susceptible-Infectious (SI): a two-state disease with life-long infection and no recovery. HIV is one example, although for that case it is common to model infection stages as separate compartments.
Susceptible-Infectious-Recovered (SIR): a three-state disease with life-long immunity following infection. Measles is one example, although modern models for measles also require consideration of vaccination patterns in the population.
Susceptible-Infectious-Susceptible (SIS): a two-state disease in which one may transition back and forth between the susceptible and infected states throughout life. Examples include bacterial sexually transmitted infections such as gonorrhea.
These built-in types are starting points. The extension API described below allows them to be replaced with arbitrarily complex disease systems.
Each model class uses three setup functions to collect the epidemic parameters, initial conditions, and control settings:
param.dcm(), param.icm(), and param.net() set the epidemic
parameters, such as the rate of contacts or acts between agents, the
probability of transmission per act, and the recovery and demographic
rates for models that include those transitions.
init.dcm(), init.icm(), and init.net() set the initial
conditions, which for built-in types are the numbers or, where
applicable, the specific agents infected or recovered at the outset.
control.dcm(), control.icm(), and control.net() set the remaining
simulation controls, including the disease type, the number of time
steps, and the number of simulations or runs.
With the model parameterized, the simulation functions are:
dcm() for deterministic compartmental models.
icm() for stochastic individual contact models.
Network models are simulated in a three-step process:
netest() estimates the statistical model for the network structure
itself, that is, how partnerships form and dissolve over time. This
function wraps the estimation routines in the ergm and tergm
packages. The typical input is a set of target statistics summarizing
the formation process together with a mean partnership duration,
an approach known as egocentric inference because those targets may be
calculated from an egocentric sample of the population. Dissolution
coefficients are calculated with dissolution_coefs().
netdx() runs diagnostics on the fitted model by simulating the
network forward in time without disease, to check that the simulated
network recovers the formation and dissolution targets. The
net-controls page covers the estimation and simulation settings to
adjust when it does not.
netsim() simulates the stochastic network epidemic model, given the
fitted network model from netest() along with the parameters,
initial conditions, and controls defined above.
Network models may also use multiple network layers over a shared node set,
for example separate sexual and needle-sharing contact networks. Each layer
is estimated separately and the fits are passed together to netsim(), with
multilayer() specifying any controls that vary by layer.
Research applications typically require disease states or processes beyond
the built-in types. The extension API supports this for the network class:
setting type = NULL in control.net() and supplying module functions
(for example, infection.FUN = my_infection_module) replaces or supplements
the built-in modules. A module is a function with the signature
function(dat, at) that reads from and returns the netsim_dat object
holding all simulation state.
Modules should use the accessor functions rather than manipulating that
object directly. These include get_attr() and set_attr() for nodal
attributes, get_param() for parameters, get_epi() and set_epi() for
epidemic summary statistics, append_core_attr() and append_attr() for
new arrivals, discord_edgelist() for serodiscordant pairs, and
set_transmat() for recording transmission events.
Extension support is specific to the network class. ICMs support the
built-in SI, SIR, and SIS types only; users needing custom individual-based
dynamics should use netsim(). DCMs accept an original system of
differential equations through the new.mod argument to control.dcm().
All three model classes return objects with print, summary, plot, and
as.data.frame methods, so the same analysis workflow applies throughout.
Simulation output may be converted to a long data frame with
as.data.frame.dcm(), as.data.frame.icm(), or as.data.frame.netsim(),
extended with derived statistics using mutate_epi(), subset with
get_sims(), and combined across runs with merge.icm() or
merge.netsim().
Network models additionally record the simulated networks, retrieved with
get_network(); the network statistics, retrieved with get_nwstats();
and the transmission tree, retrieved with get_transmat() and convertible
to a phylogeny with as.phylo.transmat(). Partnership histories may be
tracked over time with the cumulative edgelist and queried with
get_partners(), get_forward_reachable(), and get_backward_reachable().
The package vignettes cover getting started (Intro) and then working with
model parameters, network objects, and nodal attributes and summary
statistics in extension models.
Beyond the package documentation:
The Network Modeling for Epidemics course materials provide a full treatment of network model theory, estimation, diagnostics, and epidemic simulation, followed by the extension API and advanced topics such as multi-layer networks and epidemics over fully observed networks, at https://epimodel.github.io/sismid/.
The EpiModel Gallery provides worked extension models, from adding a single compartment through multi-stage disease models with interventions and cost-effectiveness analysis, at https://epimodel.github.io/EpiModel-Gallery/.
The EpiModel website collects these resources and a suggested learning pathway, at https://www.epimodel.org/.
Maintainer: Samuel Jenness samuel.m.jenness@emory.edu
Authors:
Samuel Jenness samuel.m.jenness@emory.edu
Steven M. Goodreau goodreau@uw.edu
Martina Morris morrism@uw.edu
Adrien Le Guillou contact@aleguillou.org
Chad Klumb cklumb@gmail.com
Other contributors:
Skye Bender-deMoll skyebend@uw.edu [contributor]
The EpiModel website is at https://www.epimodel.org/, and the source code is at https://github.com/EpiModel/EpiModel. Bug reports and feature requests are welcome.
Our primary methods paper on EpiModel is published in the Journal of Statistical Software. If you use EpiModel for any research or teaching purposes, please cite this reference:
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.
EpiModel is the foundation for a set of extension packages maintained by our
group. EpiModelHIV (https://github.com/EpiModel/EpiModelHIV) models HIV
and bacterial sexually transmitted infections, and EpiModelCOVID
(https://github.com/EpiModel/EpiModelCOVID) models SARS-CoV-2. Simulation
on high-performance computing clusters is supported by EpiModelHPC
(https://github.com/EpiModel/EpiModelHPC).
Useful links:
Report bugs at https://github.com/EpiModel/EpiModel/issues/
This function performs a simple operation of updating the
edgelist attribute n that tracks the total network
size implicit in an edgelist representation of the network.
add_vertices(el, nv)add_vertices(el, nv)
el |
A two-column matrix of current edges (edgelist) with an attribute
variable |
nv |
A integer equal to the number of nodes to add to the network size at the given time step. |
This function is used in EpiModel modules to add vertices (nodes) to
the edgelist object to account for entries into the population (e.g., births
and in-migration).
Returns the matrix of current edges, el, with the population size
attribute updated based on the number of new vertices specified in nv.
library("EpiModel") nw <- network_initialize(100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) x <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, tergmLite = TRUE, resimulate.network = TRUE) # Edgelist representation after initialization crosscheck.net(x, param, init, control) dat <- initialize.net(x, param, init, control, s = 1) el <- get_edgelist(dat, network = 1) # Check current network size attributes(el)$n # Add 10 vertices el <- add_vertices(el, 10) # Check new network size attributes(el)$nlibrary("EpiModel") nw <- network_initialize(100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) x <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, tergmLite = TRUE, resimulate.network = TRUE) # Edgelist representation after initialization crosscheck.net(x, param, init, control) dat <- initialize.net(x, param, init, control, s = 1) el <- get_edgelist(dat, network = 1) # Check current network size attributes(el)$n # Add 10 vertices el <- add_vertices(el, 10) # Check new network size attributes(el)$n
Apportions a vector of values given a specified frequency distribution of those values such that the length of the output is robust to rounding and other instabilities.
apportion_lr(vector.length, values, proportions, shuffled = FALSE)apportion_lr(vector.length, values, proportions, shuffled = FALSE)
vector.length |
Length for the output vector. |
values |
Values for the output vector. |
proportions |
Proportion distribution with one number for each value. This must sum to 1. |
shuffled |
If |
A vector of length vector.length containing the apportioned
values from values.
## Not run: ## Example 1: Without rounding apportioned_vec_1 <- apportion_lr(4, c(1, 2, 3, 4, 5), c(0.25, 0, 0.25, 0.25, 0.25)) ## Example 2: With rounding apportioned_vec_2 <- apportion_lr(5, c(1, 2, 3, 4, 5), c(0.21, 0, 0.29, 0.25, 0.25)) ## End(Not run)## Not run: ## Example 1: Without rounding apportioned_vec_1 <- apportion_lr(4, c(1, 2, 3, 4, 5), c(0.25, 0, 0.25, 0.25, 0.25)) ## Example 2: With rounding apportioned_vec_2 <- apportion_lr(5, c(1, 2, 3, 4, 5), c(0.21, 0, 0.29, 0.25, 0.25)) ## End(Not run)
Arrive New Nodes to the netsim_dat Object
arrive_nodes(dat, nArrivals)arrive_nodes(dat, nArrivals)
dat |
the |
nArrivals |
number of new nodes to arrive |
nArrivals new nodes are added to the network data stored on
the netsim_dat object. If tergmLite is FALSE, these
nodes are activated from the current timestep onward. Attributes for the new
nodes must be set separately. On each clique layer (see netclique()), the
new nodes are then placed under the layer's arrivals rule, which may set
the layer's grouping attribute for them and add their edges. A model with
an observed network layer (see netcensus()) has a fixed node set, and
both this function and depart_nodes() stop if asked to change it.
Note that this function only supports arriving new nodes; returning to an active state nodes that were previously active in the network is not supported.
the updated netsim_dat object with nArrivals new nodes
added
Converts an object that carries timed-edge information into a
cumulative_edgelist: a data.frame with head, tail, start, stop
columns matching the format used elsewhere in EpiModel. The typical use
is feeding a networkDynamic object (from a non-tergmLite simulation,
an external source, or a post-hoc construction) into the reachability
tools.
as_cumulative_edgelist(x)as_cumulative_edgelist(x)
x |
An object to be converted to a cumulative edgelist. |
The networkDynamic method subtracts 1 from each spell's terminus so
that the resulting start/stop range is inclusive on both ends,
matching the convention used by get_cumulative_edgelist() and the
reachability functions.
A cumulative_edgelist object: a data.frame with at least the
columns head, tail, start, stop. Edges are active from time
start to time stop inclusive; NA in stop means the edge was
never observed to dissolve.
get_forward_reachable() / get_backward_reachable() for
typical downstream uses; dedup_cumulative_edgelist() when the source
contains overlapping spells for the same pair of nodes.
Other cumulative_edgelist:
dedup_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelist(),
get_cumulative_edgelists_df(),
get_partners(),
reachable-nodes,
update_cumulative_edgelist()
## Not run: # Convert a saved networkDynamic from a non-tergmLite netsim run nd <- get_network(sim, sim = 1, network = 1) el_cuml <- as_cumulative_edgelist(nd) fwd <- get_forward_reachable(el_cuml, from_step = 1, to_step = 100) ## End(Not run)## Not run: # Convert a saved networkDynamic from a non-tergmLite netsim run nd <- get_network(sim, sim = 1, network = 1) el_cuml <- as_cumulative_edgelist(nd) fwd <- get_forward_reachable(el_cuml, from_step = 1, to_step = 100) ## End(Not run)
Convert an Edgelist into a Tibble
as_tibble_edgelist(el)as_tibble_edgelist(el)
el |
An edgelist in matrix or data frame form. |
The edgelist in tibble form with two columns named head and tail.
This function extracts a model run from an object of class
dcm into a data frame using the generic
as.data.frame function.
## S3 method for class 'dcm' as.data.frame(x, row.names = NULL, optional = FALSE, run = NULL, ...)## S3 method for class 'dcm' as.data.frame(x, row.names = NULL, optional = FALSE, run = NULL, ...)
x |
An |
row.names |
|
optional |
|
run |
Run number for model; used for multiple-run sensitivity models. If
|
... |
Model output from dcm() simulations are available as a data
frame with this helper function. The output data frame will include
columns for time, the size of each compartment, the overall population
size (the sum of compartment sizes), and the size of each flow.
For models with multiple runs (i.e., varying parameters - see example below),
the default with the run parameter not specified will output all runs
in a single stacked data frame.
A data frame containing the data from x.
## Example 1: One-group SIS model with varying act.rate param <- param.dcm(inf.prob = 0.2, act.rate = seq(0.05, 0.5, 0.05), rec.rate = 1/50) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SIS", nsteps = 10) mod1 <- dcm(param, init, control) as.data.frame(mod1) as.data.frame(mod1, run = 1) as.data.frame(mod1, run = 10) ## Example 2: Two-group SIR model with vital dynamics param <- param.dcm(inf.prob = 0.2, inf.prob.g2 = 0.1, act.rate = 3, balance = "g1", rec.rate = 1/50, rec.rate.g2 = 1/50, a.rate = 1/100, a.rate.g2 = NA, ds.rate = 1/100, ds.rate.g2 = 1/100, di.rate = 1/90, di.rate.g2 = 1/90, dr.rate = 1/100, dr.rate.g2 = 1/100) init <- init.dcm(s.num = 500, i.num = 1, r.num = 0, s.num.g2 = 500, i.num.g2 = 1, r.num.g2 = 0) control <- control.dcm(type = "SIR", nsteps = 10) mod2 <- dcm(param, init, control) as.data.frame(mod2)## Example 1: One-group SIS model with varying act.rate param <- param.dcm(inf.prob = 0.2, act.rate = seq(0.05, 0.5, 0.05), rec.rate = 1/50) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SIS", nsteps = 10) mod1 <- dcm(param, init, control) as.data.frame(mod1) as.data.frame(mod1, run = 1) as.data.frame(mod1, run = 10) ## Example 2: Two-group SIR model with vital dynamics param <- param.dcm(inf.prob = 0.2, inf.prob.g2 = 0.1, act.rate = 3, balance = "g1", rec.rate = 1/50, rec.rate.g2 = 1/50, a.rate = 1/100, a.rate.g2 = NA, ds.rate = 1/100, ds.rate.g2 = 1/100, di.rate = 1/90, di.rate.g2 = 1/90, dr.rate = 1/100, dr.rate.g2 = 1/100) init <- init.dcm(s.num = 500, i.num = 1, r.num = 0, s.num.g2 = 500, i.num.g2 = 1, r.num.g2 = 0) control <- control.dcm(type = "SIR", nsteps = 10) mod2 <- dcm(param, init, control) as.data.frame(mod2)
This function extracts model simulations for objects of classes
icm and netsim into a data frame using
the generic as.data.frame function.
## S3 method for class 'icm' as.data.frame( x, row.names = NULL, optional = FALSE, out = "vals", sim = NULL, qval = NULL, repair = "drop", ... ) ## S3 method for class 'netsim' as.data.frame( x, row.names = NULL, optional = FALSE, out = "vals", sim = NULL, repair = "drop", ... )## S3 method for class 'icm' as.data.frame( x, row.names = NULL, optional = FALSE, out = "vals", sim = NULL, qval = NULL, repair = "drop", ... ) ## S3 method for class 'netsim' as.data.frame( x, row.names = NULL, optional = FALSE, out = "vals", sim = NULL, repair = "drop", ... )
x |
An |
row.names |
|
optional |
|
out |
Data output to data frame: |
sim |
If |
qval |
Quantile value required when |
repair |
What to do with epi trackers that are too short. "drop" will
remove them from the output, "pad" will add |
... |
These methods work for both icm and netsim class models. The
available output includes time-specific means, standard deviations,
quantiles, and simulation values (compartment and flow sizes) from these
stochastic model classes. Means, standard deviations, and quantiles are
calculated by taking the row summary (i.e., each row of data corresponds
to a time step) across all simulations in the model output.
A data frame containing the data from x.
## Stochastic ICM SIS model param <- param.icm(inf.prob = 0.8, act.rate = 2, rec.rate = 0.1) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SIS", nsteps = 10, nsims = 3, verbose = FALSE) mod <- icm(param, init, control) # Default output all simulation runs, default to all in stacked data.frame as.data.frame(mod) as.data.frame(mod, sim = 2) # Time-specific means across simulations as.data.frame(mod, out = "mean") # Time-specific standard deviations across simulations as.data.frame(mod, out = "sd") # Time-specific quantile values across simulations as.data.frame(mod, out = "qnt", qval = 0.25) as.data.frame(mod, out = "qnt", qval = 0.75) ## Not run: ## Stochastic SI Network Model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.5) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod <- netsim(est, param, init, control) # Same data extraction methods as with ICMs as.data.frame(mod) as.data.frame(mod, sim = 2) as.data.frame(mod, out = "mean") as.data.frame(mod, out = "sd") as.data.frame(mod, out = "qnt", qval = 0.25) as.data.frame(mod, out = "qnt", qval = 0.75) ## End(Not run)## Stochastic ICM SIS model param <- param.icm(inf.prob = 0.8, act.rate = 2, rec.rate = 0.1) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SIS", nsteps = 10, nsims = 3, verbose = FALSE) mod <- icm(param, init, control) # Default output all simulation runs, default to all in stacked data.frame as.data.frame(mod) as.data.frame(mod, sim = 2) # Time-specific means across simulations as.data.frame(mod, out = "mean") # Time-specific standard deviations across simulations as.data.frame(mod, out = "sd") # Time-specific quantile values across simulations as.data.frame(mod, out = "qnt", qval = 0.25) as.data.frame(mod, out = "qnt", qval = 0.75) ## Not run: ## Stochastic SI Network Model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.5) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod <- netsim(est, param, init, control) # Same data extraction methods as with ICMs as.data.frame(mod) as.data.frame(mod, sim = 2) as.data.frame(mod, out = "mean") as.data.frame(mod, out = "sd") as.data.frame(mod, out = "qnt", qval = 0.25) as.data.frame(mod, out = "qnt", qval = 0.75) ## End(Not run)
This function extracts timed edgelists for objects of class
netdx into a data frame using the generic
as.data.frame function.
## S3 method for class 'netdx' as.data.frame(x, row.names = NULL, optional = FALSE, sim = NULL, ...)## S3 method for class 'netdx' as.data.frame(x, row.names = NULL, optional = FALSE, sim = NULL, ...)
x |
An |
row.names |
|
optional |
|
sim |
The simulation number to output. If |
... |
A data frame containing the data from x.
# Initialize and parameterize the network model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Model estimation est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Simulate the network with netdx dx <- netdx(est, nsims = 3, nsteps = 10, keep.tedgelist = TRUE, verbose = FALSE) # Extract data from the first simulation as.data.frame(dx, sim = 1) # Extract data from all simulations as.data.frame(dx)# Initialize and parameterize the network model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Model estimation est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Simulate the network with netdx dx <- netdx(est, nsims = 3, nsteps = 10, keep.tedgelist = TRUE, verbose = FALSE) # Extract data from the first simulation as.data.frame(dx, sim = 1) # Extract data from all simulations as.data.frame(dx)
This methods ensures that the data.frame is correctly formatted as an
epi.data.frame
as.epi.data.frame(df)as.epi.data.frame(df)
df |
A |
Converts a transmission matrix from the get_transmat
function into a network::network class object.
## S3 method for class 'transmat' as.network(x, ...)## S3 method for class 'transmat' as.network(x, ...)
x |
An object of class |
... |
Unused. |
When converting from a transmat to a network object, this
functions copies the edge attributes within the transmission matrix
('at', 'infDur', 'transProb', 'actRate', and
'finalProb') into edge attributes on the network.
A network::network object.
Converts a transmission matrix from the get_transmat
function into a phylo class object.
## S3 method for class 'transmat' as.phylo(x, vertex.exit.times = NULL, ...)## S3 method for class 'transmat' as.phylo(x, vertex.exit.times = NULL, ...)
x |
An object of class |
vertex.exit.times |
Optional numeric vector providing the time of departure of vertices, to be used to scale the lengths of branches reaching to the tips. Index position on vector corresponds to network id. NA indicates no departure, so branch will extend to the end of the tree. |
... |
Further arguments (unused). |
Converts a transmat() object containing information about the
history of a simulated infection into a ape::phylo object
representation suitable for plotting as a tree with
ape::plot.phylo(). Each infection event becomes a 'node'
(horizontal branch) in the resulting phylo tree, and each network
vertex becomes a 'tip' of the tree. The infection events are labeled with the
vertex ID of the infector to make it possible to trace the path of infection.
The infection timing information is included to position the phylo-nodes,
with the lines to the tips drawn to the max time value +1 (unless
vertex.exit.times are passed in it effectively assumes all vertices
are active until the end of the simulation).
If the transmat contains multiple infection seeds (there are multiple
trees with separate root nodes), this function will return a list of class
multiPhylo, each element of which is a phylo object. See
ape::read.tree().
A phylo class object.
set.seed(13) # Fit a random mixing TERGM with mean degree of 1 and mean edge # duration of 20 time steps nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Parameterize the epidemic model as SI with one infected seed param <- param.net(inf.prob = 0.5) init <- init.net(i.num = 1) control <- control.net(type = "SI", nsteps = 40, nsims = 1, verbose = FALSE) # Simulate the model mod1 <- netsim(est, param, init, control) # Extract the transmission matrix tm <- get_transmat(mod1) head(tm, 15) # Convert to phylo object and plot tmPhylo <- as.phylo.transmat(tm) oldpar <- par(mar = c(1,1,1,1)) plot(tmPhylo, show.node.label = TRUE, root.edge = TRUE, cex = 0.75) par(oldpar)set.seed(13) # Fit a random mixing TERGM with mean degree of 1 and mean edge # duration of 20 time steps nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Parameterize the epidemic model as SI with one infected seed param <- param.net(inf.prob = 0.5) init <- init.net(i.num = 1) control <- control.net(type = "SI", nsteps = 40, nsims = 1, verbose = FALSE) # Simulate the model mod1 <- netsim(est, param, init, control) # Extract the transmission matrix tm <- get_transmat(mod1) head(tm, 15) # Convert to phylo object and plot tmPhylo <- as.phylo.transmat(tm) oldpar <- par(mar = c(1,1,1,1)) plot(tmPhylo, show.node.label = TRUE, root.edge = TRUE, cex = 0.75) par(oldpar)
Assigns nodes to groups of a target size distribution, subject
to a composition rule that keeps dependent members (such as
children) in groups that contain an anchor member (such as an
adult). This is the reverse of sample_groups(): the nodal
attributes already exist, from a census age distribution for
example, and the group ids are built to match them.
assign_groups( size.dist, role = NULL, anchor = NULL, dependent = NULL, n = NULL )assign_groups( size.dist, role = NULL, anchor = NULL, dependent = NULL, n = NULL )
size.dist |
Distribution of group sizes: a numeric vector of weights
named by group size, such as |
role |
Optional vector of node roles, one per node, such as an age group. Its length sets the population size. |
anchor |
Values of |
dependent |
Values of |
n |
Population size when |
The algorithm has four steps:
Group sizes are drawn from size.dist until they sum to at least n;
the last group is trimmed so that the sizes sum to exactly n.
One anchor is placed in each group, in random order, until either the groups or the anchors run out. When there are fewer anchors than groups, the groups without an anchor cannot receive dependents.
Dependents are placed in the open slots of anchored groups, each open
slot being equally likely, so that a group receives dependents in
proportion to its remaining size. When the dependents outnumber those
slots, the surplus is added to random anchored groups, which then
exceed their drawn size; this is the only case in which the realized
size distribution departs from size.dist, and a message reports it.
All remaining nodes (further anchors, and roles that are neither) fill the remaining open slots in the same way.
Without role, or without anchor, nodes are assigned to the drawn group
sizes at random and no composition rule applies.
The rule guarantees cross-generational contact for every dependent. It does
not otherwise control group composition: the number of dependents per
group, the pairing of anchors, and whether a third role (older adults, for
example) lives alone or with others all follow from the size distribution
and the population shares of the roles. When the composition itself is the
quantity to control, build the population from a table of group types with
sample_groups() instead.
An integer vector of group ids, one per node, with ids running from
1 to the number of groups.
sample_groups() and netclique().
# Ages from a census-like distribution, then households around them set.seed(1) n <- 1000 age <- sample(c("child", "adult", "elderly"), n, replace = TRUE, prob = c(0.22, 0.60, 0.18)) size.dist <- c("1" = 0.28, "2" = 0.34, "3" = 0.15, "4" = 0.14, "5" = 0.09) hh_id <- assign_groups(size.dist, role = age, anchor = c("adult", "elderly"), dependent = "child") table(tabulate(hh_id)) # realized size distribution has_anchor <- tapply(age %in% c("adult", "elderly"), hh_id, any) all(has_anchor[as.character(hh_id[age == "child"])]) # every child has one nw <- network_initialize(n) nw <- set_vertex_attribute(nw, "age", age) nw <- set_vertex_attribute(nw, "hh_id", hh_id) est_hh <- netclique(nw, group.attr = "hh_id") print(est_hh, by = "age")# Ages from a census-like distribution, then households around them set.seed(1) n <- 1000 age <- sample(c("child", "adult", "elderly"), n, replace = TRUE, prob = c(0.22, 0.60, 0.18)) size.dist <- c("1" = 0.28, "2" = 0.34, "3" = 0.15, "4" = 0.14, "5" = 0.09) hh_id <- assign_groups(size.dist, role = age, anchor = c("adult", "elderly"), dependent = "child") table(tabulate(hh_id)) # realized size distribution has_anchor <- tapply(age %in% c("adult", "elderly"), hh_id, any) all(has_anchor[as.character(hh_id[age == "child"])]) # every child has one nw <- network_initialize(n) nw <- set_vertex_attribute(nw, "age", age) nw <- set_vertex_attribute(nw, "hh_id", hh_id) est_hh <- netclique(nw, group.attr = "hh_id") print(est_hh, by = "age")
Marks transmission probabilities, act rates, or recovery rates
as varying with the time since infection, for the inf.prob,
inf.prob.g2, act.rate, rec.rate, and rec.rate.g2
arguments of param.net(). The values are given either by
stage, with the length of each stage in time steps, or one per
time step since infection. The built-in netsim() modules
apply the value at each infected node's current duration of
infection.
by_infection_duration(x, durations = NULL)by_infection_duration(x, durations = NULL)
x |
A numeric vector of values. With |
durations |
Optional numeric vector of the same length as |
A duration of infection is the number of time steps since the infected node was infected, counted from 1: a node infected at time step 10 is in its first step of infection at time steps 10 and 11, its second at time step 12, and so on. For transmission, the duration is that of the infected partner; for recovery, that of the recovering node.
The two forms describe the same thing.
by_infection_duration(c(acute = 0.25, chronic = 0.02), durations = c(10, Inf))
gives 0.25 in the first ten time steps of an infection and 0.02 from the
eleventh on, which can represent an acute stage of high infectiousness;
by_infection_duration(c(rep(0.25, 10), 0.02)) is the same parameter given
per time step. The stage form suits parameters reported by stage of
infection; the per-step form suits a profile computed elsewhere, such as an
infectiousness curve.
This is variation over the course of each infection, not over calendar
time: to change a parameter at a given time step of the simulation, use
scenarios or parameter updaters (see vignette("model-parameters", package = "EpiModel")).
In multi-layer models, an entry of a multilayer() parameter may itself be
a by_infection_duration object:
inf.prob = multilayer(by_infection_duration(c(0.5, 0.1)), 0.05).
Arithmetic on the object, such as x * 2, scales the values and keeps the
stages.
With the built-in modules, a plain vector passed to these arguments stops
netsim() with an error, since a plain vector carries no record of what its
positions mean; custom modules keep their own reading of plain vectors, such
as values by group or by layer. Parameter tables cannot represent these
objects yet, so param.net_to_table() stops on them.
An object of class by_infection_duration: the numeric vector of
values x, with the stage durations in its durations attribute.
Without durations, every stage lasts one time step but the last.
# An acute stage of ten time steps with a higher transmission probability inf.prob <- by_infection_duration(c(acute = 0.25, chronic = 0.02), durations = c(10, Inf)) inf.prob # Recovery impossible in the first 20 time steps of an infection, then # certain by_infection_duration(c(0, 1), durations = c(20, Inf)) # One value per time step, here an infectiousness profile by_infection_duration(round(dgamma(1:15, shape = 3, rate = 0.5), 3)) param <- param.net(inf.prob = inf.prob, act.rate = 1) param nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) sim <- netsim(est, param, init.net(i.num = 10), control.net(type = "SI", nsteps = 25, nsims = 1, verbose = FALSE)) tm <- get_transmat(sim) table(tm$infDur, tm$transProb)# An acute stage of ten time steps with a higher transmission probability inf.prob <- by_infection_duration(c(acute = 0.25, chronic = 0.02), durations = c(10, Inf)) inf.prob # Recovery impossible in the first 20 time steps of an infection, then # certain by_infection_duration(c(0, 1), durations = c(20, Inf)) # One value per time step, here an infectiousness profile by_infection_duration(round(dgamma(1:15, shape = 3, rate = 0.5), 3)) param <- param.net(inf.prob = inf.prob, act.rate = 1) param nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) sim <- netsim(est, param, init.net(i.num = 10), control.net(type = "SI", nsteps = 25, nsims = 1, verbose = FALSE)) tm <- get_transmat(sim) table(tm$infDur, tm$transProb)
Checks for consistency in the implied network statistics of a two-group network in which the group size and group-specific degree distributions are specified.
check_degdist_bal(num.g1, num.g2, deg.dist.g1, deg.dist.g2)check_degdist_bal(num.g1, num.g2, deg.dist.g1, deg.dist.g2)
num.g1 |
Number of nodes in group 1. |
num.g2 |
Number of nodes in group 2. |
deg.dist.g1 |
Vector with fractional degree distribution for group 1. |
deg.dist.g2 |
Vector with fractional degree distribution for group 2. |
This function outputs the number of nodes of degree 0 to g, where g is the length of a fractional degree distribution vector, given that vector and the size of the group. This utility is used to check for balance in implied degree given that fractional distribution within two-group network simulations, in which the degree-constrained counts must be equal across groups.
# An unbalanced distribution check_degdist_bal(num.g1 = 500, num.g2 = 500, deg.dist.g2 = c(0.40, 0.55, 0.03, 0.02), deg.dist.g1 = c(0.48, 0.41, 0.08, 0.03)) # A balanced distribution check_degdist_bal(num.g1 = 500, num.g2 = 500, deg.dist.g1 = c(0.40, 0.55, 0.04, 0.01), deg.dist.g2 = c(0.48, 0.41, 0.08, 0.03))# An unbalanced distribution check_degdist_bal(num.g1 = 500, num.g2 = 500, deg.dist.g2 = c(0.40, 0.55, 0.03, 0.02), deg.dist.g1 = c(0.48, 0.41, 0.08, 0.03)) # A balanced distribution check_degdist_bal(num.g1 = 500, num.g2 = 500, deg.dist.g1 = c(0.40, 0.55, 0.04, 0.01), deg.dist.g2 = c(0.48, 0.41, 0.08, 0.03))
ndtv AnimationsCreates a new color-named temporally-extended attribute (TEA)
variable in a networkDynamic object containing a disease
status TEA in numeric format.
color_tea( nd, old.var = "testatus", old.sus = "s", old.inf = "i", old.rec = "r", new.var = "ndtvcol", new.sus = NULL, new.inf = NULL, new.rec = NULL, verbose = TRUE )color_tea( nd, old.var = "testatus", old.sus = "s", old.inf = "i", old.rec = "r", new.var = "ndtvcol", new.sus = NULL, new.inf = NULL, new.rec = NULL, verbose = TRUE )
nd |
An object of class |
old.var |
Old TEA variable name. |
old.sus |
Status value for susceptible in old TEA variable. |
old.inf |
Status value for infected in old TEA variable. |
old.rec |
Status value for recovered in old TEA variable. |
new.var |
New TEA variable name to be stored in |
new.sus |
Status value for susceptible in new TEA variable. |
new.inf |
Status value for infected in new TEA variable. |
new.rec |
Status value for recovered in new TEA variable. |
verbose |
If |
The ndtv package (https://cran.r-project.org/package=ndtv)
produces animated visuals for dynamic networks with evolving edge structures
and nodal attributes. Nodal attribute dynamics in ndtv movies require
a temporally extended attribute (TEA) containing a standard R color for each
node at each time step. By default, the EpiModel package uses TEAs to
store disease status history in network model simulations run in
netsim(). But that status TEA is in numeric format (0, 1, 2).
The color_tea function transforms those numeric values of that disease
status TEA into a TEA with color values in order to visualize status changes
in ndtv.
The convention in plot.netsim() is to color the susceptible
nodes as blue, infected nodes as red, and recovered nodes as green. Alternate
colors may be specified using the new.sus, new.inf, and
new.rec parameters, respectively.
Using the color_tea function with a netsim object requires that
TEAs for disease status be used and that the networkDynamic object be
saved in the output: tergmListe must be set to FALSE in
control.net().
The updated object of class networkDynamic.
netsim() and the ndtv package documentation.
Plots a compartment flow diagram for deterministic compartmental models, stochastic individual contact models, and stochastic network models.
comp_plot(x, at, digits, ...) ## S3 method for class 'netsim' comp_plot(x, at = 1, digits = 3, ...) ## S3 method for class 'icm' comp_plot(x, at = 1, digits = 3, ...) ## S3 method for class 'dcm' comp_plot(x, at = 1, digits = 3, run = 1, ...)comp_plot(x, at, digits, ...) ## S3 method for class 'netsim' comp_plot(x, at = 1, digits = 3, ...) ## S3 method for class 'icm' comp_plot(x, at = 1, digits = 3, ...) ## S3 method for class 'dcm' comp_plot(x, at = 1, digits = 3, run = 1, ...)
x |
An |
at |
Time step for model statistics. For |
digits |
Number of significant digits to print. |
... |
Additional arguments passed to plot (not currently used). |
run |
Model run number, for |
The comp_plot function provides a visual summary of an epidemic model
at a specific time step. The information contained in comp_plot is the
same as in the summary functions for a model, but presented
graphically as a compartment flow diagram.
For dcm class plots, specify the model run number if the model
contains multiple runs, as in a sensitivity analysis. For icm and
netsim class plots, the run argument is not used; the plots
show the means and standard deviations across simulations at the specified
time step.
These plots are currently limited to one-group models for each of the three model classes. That functionality may be expanded in future software releases.
## Example 1: DCM SIR model with varying act.rate param <- param.dcm(inf.prob = 0.2, act.rate = 5:7, rec.rate = 1/3, a.rate = 1/90, ds.rate = 1/100, di.rate = 1/35, dr.rate = 1/100) init <- init.dcm(s.num = 1000, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 25, verbose = FALSE) mod1 <- dcm(param, init, control) comp_plot(mod1, at = 25, run = 3) ## Example 2: ICM SIR model with 3 simulations param <- param.icm(inf.prob = 0.2, act.rate = 3, rec.rate = 1/50, a.rate = 1/100, ds.rate = 1/100, di.rate = 1/90, dr.rate = 1/100) init <- init.icm(s.num = 500, i.num = 1, r.num = 0) control <- control.icm(type = "SIR", nsteps = 25, nsims = 3, verbose = FALSE) mod2 <- icm(param, init, control) comp_plot(mod2, at = 25, digits = 1)## Example 1: DCM SIR model with varying act.rate param <- param.dcm(inf.prob = 0.2, act.rate = 5:7, rec.rate = 1/3, a.rate = 1/90, ds.rate = 1/100, di.rate = 1/35, dr.rate = 1/100) init <- init.dcm(s.num = 1000, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 25, verbose = FALSE) mod1 <- dcm(param, init, control) comp_plot(mod1, at = 25, run = 3) ## Example 2: ICM SIR model with 3 simulations param <- param.icm(inf.prob = 0.2, act.rate = 3, rec.rate = 1/50, a.rate = 1/100, ds.rate = 1/100, di.rate = 1/90, dr.rate = 1/100) init <- init.icm(s.num = 500, i.num = 1, r.num = 0) control <- control.icm(type = "SIR", nsteps = 25, nsims = 3, verbose = FALSE) mod2 <- icm(param, init, control) comp_plot(mod2, at = 25, digits = 1)
Sets the controls for deterministic compartmental models
simulated with dcm().
control.dcm( type, nsteps, dt = 1, odemethod = "lsoda", dede = FALSE, new.mod = NULL, sens.param = TRUE, print.mod = FALSE, verbose = FALSE, ode.args = NULL, solver = NULL, ... )control.dcm( type, nsteps, dt = 1, odemethod = "lsoda", dede = FALSE, new.mod = NULL, sens.param = TRUE, print.mod = FALSE, verbose = FALSE, ode.args = NULL, solver = NULL, ... )
type |
Disease type to be modeled, with the choice of |
nsteps |
Number of time steps to solve the model over or vector of times to solve the model over. If the number of time steps, then this must be a positive integer of length 1. |
dt |
Time unit for model solutions, with the default of 1. Model solutions for fractional time steps may be obtained by setting this to a number between 0 and 1. |
odemethod |
Ordinary differential equation (ODE) integration method,
with the default of |
dede |
If |
new.mod |
If not running a base model type, a function with a new model to be simulated (see details). |
sens.param |
If |
print.mod |
If |
verbose |
If |
ode.args |
A named list of further arguments passed to
|
solver |
An optional function that solves the model in place of
|
... |
additional control settings passed to model. |
control.dcm sets the required control settings for any deterministic
compartmental models solved with the dcm() function. Controls are
required for both base model types and original models. For all base models,
the type argument is a necessary parameter and it has no default.
An EpiModel object of class control.dcm.
As of EpiModel 2.5.5, the default ODE solver was changed from "rk4"
(fixed-step Runge-Kutta 4) to "lsoda" (adaptive step-size). The "lsoda"
method automatically adjusts its internal step size, providing numerical
stability across a wide range of parameter values. The fixed-step "rk4"
solver could produce numerical instability (negative compartment sizes, NaN
values) for models with high transmission rates or stiff dynamics. Users who
require the previous behavior can set odemethod = "rk4" explicitly.
The form of the model function for base models may be displayed with the
print.mod argument set to TRUE. In this case, the model will
not be run. These model forms may be used as templates to write original
model functions.
These new models may be input and solved with dcm() using the
new.mod argument, which requires as input a model function.
By default, dcm() solves the model with one call to deSolve::ode
over all time steps, passing odemethod and any ode.args. A model whose
rates change abruptly (an intervention that starts on a given day, for
example) is solved more accurately by restarting the solver at each change.
The solver argument allows this, or any other solver, for base and new
models alike. It is called with the initial state y, the solution times
times, the model function func, the parameters parms, and the control
settings control, and must return a matrix or data frame with time in the
first column and one named column per state variable, as ode does. Any
further columns it returns, such as derived outputs, are kept as model
outputs. Columns whose names contain .flow are converted from cumulative
counts to counts per time step after the solver returns, as for the default
solver.
Use param.dcm() to specify model parameters and
init.dcm() to specify the initial conditions. Run the
parameterized model with dcm().
Sets the controls for stochastic individual contact models
simulated with icm().
control.icm(type, nsteps, nsims = 1, verbose = FALSE, verbose.int = 0)control.icm(type, nsteps, nsims = 1, verbose = FALSE, verbose.int = 0)
type |
Disease type to be modeled, with the choice of |
nsteps |
Number of time steps to solve the model over. This must be a positive integer. |
nsims |
Number of simulations to run. |
verbose |
If |
verbose.int |
Time step interval for printing progress to console, where
0 (the default) prints completion status of entire simulation and
positive integer |
control.icm sets the required control settings for any stochastic
individual contact model solved with the icm() function. ICM simulations
use the built-in SI, SIR, and SIS disease types only. The type argument
is required and has no default. For custom or extension epidemic models, use
the network model class via control.net() instead.
An EpiModel object of class control.icm.
Use param.icm() to specify model parameters and
init.icm() to specify the initial conditions. Run the
parameterized model with icm().
Sets the controls for stochastic network models simulated with
netsim.
control.net( type, nsteps, start = 1, nsims = 1, ncores = 1, resimulate.network = FALSE, tergmLite = FALSE, edges.correct.attr = NULL, cumulative.edgelist = FALSE, truncate.el.cuml = 0, tracked.attributes = NULL, tracked.attributes.once = NULL, attr.rules, epi.by, initialize.FUN = initialize.net, resim_nets.FUN = resim_nets, summary_nets.FUN = summary_nets, infection.FUN = NULL, recovery.FUN = NULL, departures.FUN = NULL, arrivals.FUN = NULL, nwupdate.FUN = nwupdate.net, prevalence.FUN = prevalence.net, verbose.FUN = verbose.net, module.order = NULL, save.nwstats = TRUE, nwstats.formula = "formation", save.transmat = TRUE, save.network, save.run = FALSE, save.cumulative.edgelist = FALSE, save.other, verbose = TRUE, verbose.int = 1, skip.check = FALSE, raw.output = FALSE, future.use.plan = FALSE, tergmLite.track.duration = FALSE, set.control.ergm = control.simulate.formula(MCMC.burnin = 2e+05), set.control.tergm = control.simulate.formula.tergm(MCMC.maxchanges = .Machine$integer.max), save.diss.stats = TRUE, dat.updates = NULL, ... )control.net( type, nsteps, start = 1, nsims = 1, ncores = 1, resimulate.network = FALSE, tergmLite = FALSE, edges.correct.attr = NULL, cumulative.edgelist = FALSE, truncate.el.cuml = 0, tracked.attributes = NULL, tracked.attributes.once = NULL, attr.rules, epi.by, initialize.FUN = initialize.net, resim_nets.FUN = resim_nets, summary_nets.FUN = summary_nets, infection.FUN = NULL, recovery.FUN = NULL, departures.FUN = NULL, arrivals.FUN = NULL, nwupdate.FUN = nwupdate.net, prevalence.FUN = prevalence.net, verbose.FUN = verbose.net, module.order = NULL, save.nwstats = TRUE, nwstats.formula = "formation", save.transmat = TRUE, save.network, save.run = FALSE, save.cumulative.edgelist = FALSE, save.other, verbose = TRUE, verbose.int = 1, skip.check = FALSE, raw.output = FALSE, future.use.plan = FALSE, tergmLite.track.duration = FALSE, set.control.ergm = control.simulate.formula(MCMC.burnin = 2e+05), set.control.tergm = control.simulate.formula.tergm(MCMC.maxchanges = .Machine$integer.max), save.diss.stats = TRUE, dat.updates = NULL, ... )
type |
Disease type to be modeled, with the choice of |
nsteps |
Number of time steps to simulate the model over. This must be a positive integer
that is equal to the final step of a simulation. If a simulation is restarted with |
start |
For models with network resimulation, time point to start up the simulation. For
restarted simulations, this must be one greater than the final time step in the prior
simulation and must be less than the value in |
nsims |
The total number of disease simulations. |
ncores |
Number of processor cores to run multiple simulations on, using
the |
resimulate.network |
If |
tergmLite |
Logical indicating usage of either |
edges.correct.attr |
Name of a binary nodal attribute marking the nodes
eligible to form ties, used by |
cumulative.edgelist |
If |
truncate.el.cuml |
Number of time steps of the cumulative edgelist to
retain, passed as the |
tracked.attributes |
A character vector of nodal attribute names whose
changes should be automatically recorded at each time step. The
|
tracked.attributes.once |
A character vector of nodal attribute names
to record only in the initial snapshot and for newly arriving nodes.
Unlike |
attr.rules |
A list containing the rules for setting the attributes of incoming nodes, with one list element per attribute to be set (see details below). |
epi.by |
A character vector of length 1 containing a nodal attribute for which subgroup stratified prevalence summary statistics are calculated. This nodal attribute must be contained in the network model formation formula, otherwise it is ignored. |
initialize.FUN |
Module to initialize the model at time 1, with the default function of
|
resim_nets.FUN |
Module to resimulate the network at each time step, with the default
function of |
summary_nets.FUN |
Module to extract summary statistics of the network
at each time step, with the default function of |
infection.FUN |
Module to simulate disease infection, with the default function of
|
recovery.FUN |
Module to simulate disease recovery, with the default function of
|
departures.FUN |
Module to simulate departure or exit, with the default function of
|
arrivals.FUN |
Module to simulate arrivals or entries, with the default function of
|
nwupdate.FUN |
Module to handle updating of network structure and nodal attributes due to
exogenous epidemic model processes, with the default function of |
prevalence.FUN |
Module to calculate disease prevalence at each time step, with the default
function of |
verbose.FUN |
Module to print simulation progress to screen, with the default function of
|
module.order |
A character vector of module names that lists modules in the order in which
they should be evaluated within each time step. If |
save.nwstats |
If |
nwstats.formula |
A right-hand sided ERGM formula that includes network statistics of
interest, with the default to the formation formula terms. Supports |
save.transmat |
If |
save.network |
If |
save.run |
If |
save.cumulative.edgelist |
If |
save.other |
A character vector of elements on the |
verbose |
If |
verbose.int |
Time step interval for printing progress to console, where |
skip.check |
If |
raw.output |
If |
future.use.plan |
If |
tergmLite.track.duration |
If |
set.control.ergm |
Control arguments passed to |
set.control.tergm |
Control arguments passed to |
save.diss.stats |
If |
dat.updates |
Either |
... |
Additional control settings passed to model. |
control.net sets the required control settings for any network model solved with the netsim
function. Controls are required for both base model types and when passing original process
modules. For an overview of control settings for base models, consult the
Network Modeling for Epidemics course materials For
all base models, the type argument is a necessary parameter and it has no default.
An EpiModel object of class control.net.
The attr.rules parameter is used to specify the rules for how nodal attribute values for
incoming nodes should be set. These rules are only necessary for models in which there are
incoming nodes (i.e., arrivals). There are three rules available for each attribute value:
current: new nodes will be assigned this attribute in proportion to the distribution of
that attribute among existing nodes at that current time step.
t1: new nodes will be assigned this attribute in proportion to the distribution of that
attribute among nodes at time 1 (that is, the proportions set in the original network for
netest).
Value: all new nodes will be assigned this specific value, with no variation.
For example, the rules list attr.rules = list(race = "t1", sex = "current", status = "s")
specifies how the race, sex, and status attributes should be set for incoming nodes. By default,
the rule is "current" for all attributes except status, in which case it is "s" (that is, all
incoming nodes are susceptible).
netsim has a built-in checkpoint system to prevent losing computation work if the function is
interrupted (SIGINT, power loss, time limit exceeded on a computation cluster). When enabled,
each simulation will be saved every .checkpoint.steps time steps. Then, if a checkpoint enabled
simulation is launched again with netsim, it will restart at the last checkpoint available in
the saved data.
To enable the checkpoint capabilities of netsim, two control arguments have to be set:
.checkpoint.steps, which is a positive number of time steps to be run between each file save;
and .checkpoint.dir, which is the path to a directory to save the checkpointed data. If
.checkpoint.dir directory does not exist, netsim will attempt to create it on the first
checkpoint save. With these two controls defined, one can simply re-run netsim with the same
arguments to restart a set of simulations that were interrupted.
Simulations are checkpointed individually: for example, if 3 simulations are run on a single core,
the first 2 are finished, then the interruption occurs during the third, netsim will only
restart the third one from the last checkpoint.
A .checkpoint.compress argument sets the compress argument of saveRDS used to save the
checkpointed data. It defaults to TRUE, which is gzip compression and usually works well on
netsim objects. Any value accepted by the compress argument of saveRDS may be used
instead, such as "xz" or "bzip2" for smaller but slower files, or FALSE for no compression.
By default, if netsim reaches the end of all simulations, the checkpoint data directory and its
content are removed before returning the netsim object. The .checkpoint.keep argument can be
set to TRUE to prevent this removal to inspect the raw simulation objects.
Base network models use a set of module functions that specify how the individual nodes in the
network are subjected to infection, recovery, demographics, and other processes. Core modules are
those listed in the .FUN arguments. For each module, there is a default function used in
the simulation. The default infection module, for example, is contained in the infection.net
function.
For original models, one may substitute replacement module functions for any of the default
functions. New modules may be added to the workflow at each time step by passing a module function
via the ... argument. Consult the
Extending EpiModel
section of the Network Modeling for Epidemics course materials.
One may remove existing modules, such as arrivals.FUN, from the workflow by setting
the parameter value for that argument to NULL.
netsim implements an "End Horizon" mechanism, where a set of modules are
removed from the simulation at a specific time step. This is enabled through
the end.horizon parameter to control.net.
This parameter must receive a list with fields at, the time step at which
the end horizon occurs, and modules, a character vector with the names of
the modules to remove. For example, list(at = 208, modules = c("arrivals.FUN", "infections.FUN")).
Use param.net to specify model parameters and init.net to specify the initial conditions.
Run the parameterized model with netsim.
This helper function populates a netsim_dat main list
object with the minimal required elements. All parameters are
optional. When none are given the resulting object is only a
shell list of class netsim_dat with the different named
elements defined as empty lists.
create_dat_object( param = list(), init = list(), control = list(), run = list() )create_dat_object( param = list(), init = list(), control = list(), run = list() )
param |
An |
init |
An |
control |
An |
run |
A |
A netsim_dat main list object.
An EpiModel scenario allows one or multiple set of parameters to be applied to a model a predefined timesteps. They are usually used by a researcher who wants to model counterfactuals using a pre calibrated model.
create_scenario_list(scenarios.df)create_scenario_list(scenarios.df)
scenarios.df |
a |
a list of EpiModel scenarios
The scenarios.df is a data.frame of values to be used as
parameters.
It must contain a ".at" column, specifying when the changes should occur. It requires the "updater" module of EpiModel. See, vignette. If the ".at" value of a row is less than two, the changes will be applied to the parameter list iteself. The second mandatory column is ".scenario.id". It is used to distinguish the different scenarios. If multiple rows share the same ".scenario.id", the resulting scenario will contain one updater per row. This permits modifying parameters at multiple points in time. (e.g. an intervention limited in time).
The other column names must correspond either to: the name of one parameter if this parameter is of size 1 or the name of the parameter with "_1", "_2", "N" with the second part being the position of the value for a parameter of size > 1. This means that the parameter names cannot contain any underscore "". (e.g "a.rate", "d.rate_1", "d.rate_2")
A column with a position suffix sets that position of the current value of
the parameter and leaves the other positions as they are. For example, with
prep.start.rate = c(0.0055, 0.0042, 0.0066) in param, a scenario with
only a prep.start.rate_1 column of 0.5 gives
prep.start.rate = c(0.5, 0.0042, 0.0066), both when it is applied before
the simulation by use_scenario() and when it is applied by an updater
during the simulation. Before EpiModel 2.7.0, the parameter was replaced by
a vector built from the scenario columns alone (0.5 here), so every
position had to be given.
A column without a suffix (prep.start.rate) still replaces the whole
parameter with its single value. Positions past the end of the current
vector extend it when they leave no gap: with a vector of length 3,
prep.start.rate_4 alone extends it to length 4, while
prep.start.rate_5 alone is an error. A scenario cannot shorten a vector.
Only plain vectors can be set by position: a parameter given as a
multilayer() or by_infection_duration() object, or as a list, is an
error. Use a parameter updater that sets the whole value instead.
Solves deterministic compartmental epidemic models for infectious disease.
dcm(param, init, control)dcm(param, init, control)
param |
Model parameters, as an object of class |
init |
Initial conditions, as an object of class |
control |
Control settings, as an object of class
|
The dcm function uses the ordinary differential equation solver in
the deSolve package to model disease as a deterministic compartmental
system. The parameterization for these models follows the standard approach
in EpiModel, with epidemic parameters, initial conditions, and control
settings.
The dcm function performs modeling of both base model types and
original models with new structures. Base model types include one-group
and two-group models with disease types for Susceptible-Infected (SI),
Susceptible-Infected-Recovered (SIR), and Susceptible-Infected-Susceptible
(SIS). Both base and original models require the param,
init, and control inputs.
Solver settings such as tolerances are passed to deSolve through the
ode.args argument of control.dcm(), and the solver argument replaces
the solver altogether, for example to restart it at abrupt changes in a
model's rates.
A list of class dcm with the following elements:
param: the epidemic parameters passed into the model through
param, with additional parameters added as necessary.
control: the control settings passed into the model through
control, with additional controls added as necessary.
epi: a list of data frames, one for each epidemiological output from the model. Outputs for base models always include the size of each compartment, as well as flows in, out of, and between compartments.
Soetaert K, Petzoldt T, Setzer W. Solving Differential Equations in R: Package deSolve. Journal of Statistical Software. 2010; 33(9): 1-25. doi:10.18637/jss.v033.i09.
Extract the model results with as.data.frame.dcm().
Summarize the time-specific model results with summary.dcm().
Plot the model results with plot.dcm(). Plot a compartment flow
diagram with comp_plot().
## Example 1: SI Model (One-Group) # Set parameters param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SI", nsteps = 500) mod1 <- dcm(param, init, control) mod1 plot(mod1) ## Example 2: SIR Model with Vital Dynamics (One-Group) param <- param.dcm(inf.prob = 0.2, act.rate = 5, rec.rate = 1/3, a.rate = 1/90, ds.rate = 1/100, di.rate = 1/35, dr.rate = 1/100) init <- init.dcm(s.num = 500, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 500) mod2 <- dcm(param, init, control) mod2 plot(mod2) ## Example 3: SIS Model with act.rate Sensitivity Parameter param <- param.dcm(inf.prob = 0.2, act.rate = seq(0.1, 0.5, 0.1), rec.rate = 1/50) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SIS", nsteps = 500) mod3 <- dcm(param, init, control) mod3 plot(mod3) ## Example 4: SI Model with Vital Dynamics (Two-Group) param <- param.dcm(inf.prob = 0.4, inf.prob.g2 = 0.1, act.rate = 0.25, balance = "g1", a.rate = 1/100, a.rate.g2 = NA, ds.rate = 1/100, ds.rate.g2 = 1/100, di.rate = 1/50, di.rate.g2 = 1/50) init <- init.dcm(s.num = 500, i.num = 1, s.num.g2 = 500, i.num.g2 = 0) control <- control.dcm(type = "SI", nsteps = 500) mod4 <- dcm(param, init, control) mod4 plot(mod4) ## Example 5: SI Model with Varying Initial Conditions param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = c(1, 5, 25)) control <- control.dcm(type = "SI", nsteps = 500) mod5 <- dcm(param, init, control) mod5 plot(mod5)## Example 1: SI Model (One-Group) # Set parameters param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SI", nsteps = 500) mod1 <- dcm(param, init, control) mod1 plot(mod1) ## Example 2: SIR Model with Vital Dynamics (One-Group) param <- param.dcm(inf.prob = 0.2, act.rate = 5, rec.rate = 1/3, a.rate = 1/90, ds.rate = 1/100, di.rate = 1/35, dr.rate = 1/100) init <- init.dcm(s.num = 500, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 500) mod2 <- dcm(param, init, control) mod2 plot(mod2) ## Example 3: SIS Model with act.rate Sensitivity Parameter param <- param.dcm(inf.prob = 0.2, act.rate = seq(0.1, 0.5, 0.1), rec.rate = 1/50) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SIS", nsteps = 500) mod3 <- dcm(param, init, control) mod3 plot(mod3) ## Example 4: SI Model with Vital Dynamics (Two-Group) param <- param.dcm(inf.prob = 0.4, inf.prob.g2 = 0.1, act.rate = 0.25, balance = "g1", a.rate = 1/100, a.rate.g2 = NA, ds.rate = 1/100, ds.rate.g2 = 1/100, di.rate = 1/50, di.rate.g2 = 1/50) init <- init.dcm(s.num = 500, i.num = 1, s.num.g2 = 500, i.num.g2 = 0) control <- control.dcm(type = "SI", nsteps = 500) mod4 <- dcm(param, init, control) mod4 plot(mod4) ## Example 5: SI Model with Varying Initial Conditions param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = c(1, 5, 25)) control <- control.dcm(type = "SI", nsteps = 500) mod5 <- dcm(param, init, control) mod5 plot(mod5)
Merges overlapping spells for the same (head, tail) pair into a single
row. Useful when concatenating cumulative edgelists across multiple
simulations or sources, where the same partnership can appear in more
than one segment. The reachability functions assume non-overlapping
input.
dedup_cumulative_edgelist(el)dedup_cumulative_edgelist(el)
el |
A cumulative edgelist with potentially overlapping edges. |
A cumulative edgelist with no overlapping edges for the same
(head, tail) pair.
as_cumulative_edgelist() for one source of duplicates;
get_forward_reachable() / get_backward_reachable(), which expect
non-overlapping input.
Other cumulative_edgelist:
as_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelist(),
get_cumulative_edgelists_df(),
get_partners(),
reachable-nodes,
update_cumulative_edgelist()
## Not run: el_cuml <- dedup_cumulative_edgelist(el_raw) ## End(Not run)## Not run: el_cuml <- dedup_cumulative_edgelist(el_raw) ## End(Not run)
Given a current two-column matrix of edges and a vector of vertex IDs, this function removes any rows of the edgelist in which the IDs are present.
delete_edges(el, vid)delete_edges(el, vid)
el |
A two-column matrix of current edges (edgelist). |
vid |
A vector of vertex IDs whose edges are to be deleted from the edgelist. |
Returns an updated edgelist object, with any edges including the specified vertices removed.
Given a current two-column matrix of edges and a vector of IDs to delete from the matrix, this function first removes any rows of the edgelist in which the IDs are present and then permutes downward the index of IDs on the edgelist that were numerically larger than the IDs deleted.
delete_vertices(el, vid)delete_vertices(el, vid)
el |
A two-column matrix of current edges (edgelist) with an attribute
variable |
vid |
A vector of IDs to delete from the edgelist. |
This function is used in EpiModel modules to remove vertices (nodes)
from the edgelist object to account for exits from the population (e.g.,
deaths and out-migration).
Returns an updated edgelist object, el, with the edges of deleted
vertices removed from the edgelist and the ID numbers of the remaining edges
permuted downward.
library("EpiModel") set.seed(12345) nw <- network_initialize(100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) x <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, tergmLite = TRUE, resimulate.network = TRUE) # Set seed for reproducibility set.seed(123456) # Edgelist representation after initialization crosscheck.net(x, param, init, control) dat <- initialize.net(x, param, init, control, s = 1) el <- get_edgelist(dat, network = 1) # Current edges head(el, 20) # Remove nodes 1 and 2 nodes.to.delete <- 1:2 el <- delete_vertices(el, nodes.to.delete) # Newly permuted edges head(el, 20)library("EpiModel") set.seed(12345) nw <- network_initialize(100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) x <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, tergmLite = TRUE, resimulate.network = TRUE) # Set seed for reproducibility set.seed(123456) # Edgelist representation after initialization crosscheck.net(x, param, init, control) dat <- initialize.net(x, param, init, control, s = 1) el <- get_edgelist(dat, network = 1) # Current edges head(el, 20) # Remove nodes 1 and 2 nodes.to.delete <- 1:2 el <- delete_vertices(el, nodes.to.delete) # Newly permuted edges head(el, 20)
Depart Nodes from the netsim_dat Object
depart_nodes(dat, departures)depart_nodes(dat, departures)
dat |
the |
departures |
the vertex ids of nodes to depart |
If tergmLite is FALSE, the vertex ids
departures are deactivated (from the current timestep onward) in each
networkDynamic stored in dat$run$nw. If tergmLite is
TRUE, the vertex ids departures are deleted from dat$run$el,
dat$run$attr, and dat$run$net_attr.
the updated netsim_dat object with the nodes in
departures departed
Calculates dissolution coefficients, given a dissolution model
and average edge duration, to pass as offsets to an ERGM/TERGM
model fit in netest.
dissolution_coefs(dissolution, duration, d.rate = 0)dissolution_coefs(dissolution, duration, d.rate = 0)
dissolution |
Right-hand sided STERGM dissolution formula
(see |
duration |
A vector of mean edge durations in arbitrary time units. |
d.rate |
Departure or exit rate from the population, as a single homogeneous rate that applies to the entire population. |
This function performs two calculations for dissolution coefficients
used in a network model estimated with netest():
Transformation: the mean durations of edges in a network are mathematically transformed to logit coefficients.
Adjustment: in a dynamic network simulation in an open population (in which there are departures), it is further necessary to adjust these coefficients; this upward adjustment accounts for departure as a competing risk to edge dissolution.
The current dissolution models supported by this function and in network
model estimation in netest() are as follows:
~offset(edges): a homogeneous dissolution model in which the
edge duration is the same for all partnerships. This requires
specifying one duration value.
~offset(edges) + offset(nodematch("<attr>")): a heterogeneous
model in which the edge duration varies by whether the nodes in the
dyad have similar values of a specified attribute. The duration
vector should now contain two values: the first is the mean edge
duration of non-matched dyads, and the second is the duration of the
matched dyads.
~offset(edges) + offset(nodemix("<attr>")): a heterogeneous
model that extends the nodematch model to include non-binary
attributes for homophily. The duration vector should first contain
the base value, then the values for every other possible combination
in the term.
A list of class disscoef with the following elements:
dissolution: right-hand sided STERGM dissolution formula passed in the function call.
duration: mean edge durations passed into the function.
coef.crude: mean durations transformed into logit coefficients.
coef.adj: crude coefficients adjusted for the risk of
departure on edge persistence, if the d.rate argument is
supplied.
coef.form.corr: corrections to be subtracted from formation coefficients.
d.rate: the departure rate.
diss.model.type: the form of the dissolution model; options
include edgesonly, nodematch, and nodemix.
## Homogeneous dissolution model with no departures dissolution_coefs(dissolution = ~offset(edges), duration = 25) ## Homogeneous dissolution model with departures dissolution_coefs(dissolution = ~offset(edges), duration = 25, d.rate = 0.001) ## Heterogeneous dissolution model in which same-race edges have ## shorter duration compared to mixed-race edges, with no departures dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("race")), duration = c(20, 10)) ## Heterogeneous dissolution model in which same-race edges have ## shorter duration compared to mixed-race edges, with departures dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("race")), duration = c(20, 10), d.rate = 0.001) ## Not run: ## Extended example for differential homophily by age group # Set up the network with nodes categorized into 5 age groups nw <- network_initialize(n = 1000) age.grp <- sample(1:5, 1000, TRUE) nw <- set_vertex_attribute(nw, "age.grp", age.grp) # durations = non-matched, age.grp1 & age.grp1, age.grp2 & age.grp2, ... # TERGM will include differential homophily by age group with nodematch term # Target stats for the formation model are overall edges, and then the number # matched within age.grp 1, age.grp 2, ..., age.grp 5 form <- ~edges + nodematch("age.grp", diff = TRUE) target.stats <- c(450, 100, 125, 40, 80, 100) # Target stats for the dissolution model are duration of non-matched edges, # then duration of edges matched within age.grp 1, age.grp 2, ..., age.grp 5 durs <- c(60, 30, 80, 100, 125, 160) diss <- dissolution_coefs(~offset(edges) + offset(nodematch("age.grp", diff = TRUE)), duration = durs) # Fit the TERGM fit <- netest(nw, form, target.stats, diss) # Full diagnostics to evaluate model fit dx <- netdx(fit, nsims = 10, ncores = 4, nsteps = 300) print(dx) # Simulate one long time series to examine timed edgelist dx <- netdx(fit, nsims = 1, nsteps = 5000, keep.tedgelist = TRUE) # Extract timed-edgelist te <- as.data.frame(dx) head(te) # Limit to non-censored edges te <- te[which(te$onset.censored == FALSE & te$terminus.censored == FALSE), c("head", "tail", "duration")] head(te) # Look up the age group of head and tail nodes te$ag.head <- age.grp[te$head] te$ag.tail <- age.grp[te$tail] head(te) # Recover average edge durations for age-group pairing mean(te$duration[te$ag.head != te$ag.tail]) mean(te$duration[te$ag.head == 1 & te$ag.tail == 1]) mean(te$duration[te$ag.head == 2 & te$ag.tail == 2]) mean(te$duration[te$ag.head == 3 & te$ag.tail == 3]) mean(te$duration[te$ag.head == 4 & te$ag.tail == 4]) mean(te$duration[te$ag.head == 5 & te$ag.tail == 5]) durs ## End(Not run)## Homogeneous dissolution model with no departures dissolution_coefs(dissolution = ~offset(edges), duration = 25) ## Homogeneous dissolution model with departures dissolution_coefs(dissolution = ~offset(edges), duration = 25, d.rate = 0.001) ## Heterogeneous dissolution model in which same-race edges have ## shorter duration compared to mixed-race edges, with no departures dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("race")), duration = c(20, 10)) ## Heterogeneous dissolution model in which same-race edges have ## shorter duration compared to mixed-race edges, with departures dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("race")), duration = c(20, 10), d.rate = 0.001) ## Not run: ## Extended example for differential homophily by age group # Set up the network with nodes categorized into 5 age groups nw <- network_initialize(n = 1000) age.grp <- sample(1:5, 1000, TRUE) nw <- set_vertex_attribute(nw, "age.grp", age.grp) # durations = non-matched, age.grp1 & age.grp1, age.grp2 & age.grp2, ... # TERGM will include differential homophily by age group with nodematch term # Target stats for the formation model are overall edges, and then the number # matched within age.grp 1, age.grp 2, ..., age.grp 5 form <- ~edges + nodematch("age.grp", diff = TRUE) target.stats <- c(450, 100, 125, 40, 80, 100) # Target stats for the dissolution model are duration of non-matched edges, # then duration of edges matched within age.grp 1, age.grp 2, ..., age.grp 5 durs <- c(60, 30, 80, 100, 125, 160) diss <- dissolution_coefs(~offset(edges) + offset(nodematch("age.grp", diff = TRUE)), duration = durs) # Fit the TERGM fit <- netest(nw, form, target.stats, diss) # Full diagnostics to evaluate model fit dx <- netdx(fit, nsims = 10, ncores = 4, nsteps = 300) print(dx) # Simulate one long time series to examine timed edgelist dx <- netdx(fit, nsims = 1, nsteps = 5000, keep.tedgelist = TRUE) # Extract timed-edgelist te <- as.data.frame(dx) head(te) # Limit to non-censored edges te <- te[which(te$onset.censored == FALSE & te$terminus.censored == FALSE), c("head", "tail", "duration")] head(te) # Look up the age group of head and tail nodes te$ag.head <- age.grp[te$head] te$ag.tail <- age.grp[te$tail] head(te) # Recover average edge durations for age-group pairing mean(te$duration[te$ag.head != te$ag.tail]) mean(te$duration[te$ag.head == 1 & te$ag.tail == 1]) mean(te$duration[te$ag.head == 2 & te$ag.tail == 2]) mean(te$duration[te$ag.head == 3 & te$ag.tail == 3]) mean(te$duration[te$ag.head == 4 & te$ag.tail == 4]) mean(te$duration[te$ag.head == 5 & te$ag.tail == 5]) durs ## End(Not run)
Outputs a table of the number and percent of edges that are
left-censored, right-censored, both-censored, or uncensored for
a networkDynamic object.
edgelist_censor(el)edgelist_censor(el)
el |
A timed edgelist with start and end times extracted from a
|
Given a STERGM simulation over a specified number of time steps, the edges within that simulation may be left-censored (started before the first step), right-censored (continued after the last step), right and left-censored, or uncensored. The amount of censoring will increase when the average edge duration approaches the length of the simulation.
A 4 x 2 table containing the number and percent of edges in el
that are left-censored, right-censored, both-censored, or uncensored.
# Initialize and parameterize network model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Model estimation est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Simulate the network and extract a timed edgelist dx <- netdx(est, nsims = 1, nsteps = 100, keep.tedgelist = TRUE, verbose = FALSE) el <- as.data.frame(dx) # Calculate censoring edgelist_censor(el)# Initialize and parameterize network model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Model estimation est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Simulate the network and extract a timed edgelist dx <- netdx(est, nsims = 1, nsteps = 100, keep.tedgelist = TRUE, verbose = FALSE) el <- as.data.frame(dx) # Calculate censoring edgelist_censor(el)
Launches interactive Shiny applications for exploring deterministic compartmental models (DCMs) and stochastic individual contact models (ICMs) of infectious disease transmission.
epiweb(class, ...)epiweb(class, ...)
class |
Model class, with options of |
... |
Additional arguments passed to shiny::runApp, such as
|
epiweb launches a web-based graphical interface for configuring, running,
and analyzing epidemic models built on EpiModel. Each application provides
interactive controls for model parameters, real-time (or on-demand)
visualization with plotly, narrative model summaries, and downloadable
data tables. Both applications include a Guide tab with a comprehensive
user manual covering the underlying theory, parameter definitions, and
instructions for interpreting output.
class = "dcm")The DCM app solves systems of ordinary differential equations for one-group SI, SIR, and SIS models. Models run instantly and the interface is fully reactive (no run button). Features include:
Scenario presets: Flu-like (SIR), STI-like (SIS), and Measles-like (SIR) configurations that set all parameters to epidemiologically plausible values.
Interventions: An optional mid-epidemic intervention that reduces the transmission probability by a user-specified efficacy, shown as a vertical dashed line on the plot.
Sensitivity analysis: Vary any epidemic parameter across a range of values to compare trajectories side by side with a blue-to-red color ramp.
Vital dynamics: Optional births and deaths to model endemic equilibria over longer time horizons.
Summary tab: Displays the basic reproduction number (R0), peak timing, cumulative infections, attack rate, and contextual interpretation.
Data tab: Searchable table of model output with CSV download.
class = "icm")The ICM app runs agent-based stochastic microsimulations for one-group SI, SIR, and SIS models. Because ICMs are computationally more expensive, a Run Model button controls when simulations execute. Features include:
Stochastic visualization: Multiple simulations are summarized with mean trajectory lines and interquartile range (IQR) ribbons showing the middle 50\ individual trajectories.
Scenario presets: The same Flu-like, STI-like, and Measles-like configurations as the DCM app, adapted for smaller populations suitable for agent-based simulation.
Interventions: Same intervention system as DCM, natively supported by param.icm.
Vital dynamics: Optional births and deaths, as in DCM.
Summary tab: Displays R0, epidemic timeline from the mean trajectory, and a stochastic variation section showing the range and standard deviation of peak infections and final prevalence across simulations.
Data tab: View simulation output as means, standard deviations, or individual simulation values, with CSV download.
Both applications require the shiny, bslib, DT, and plotly packages.
Install any missing packages with
install.packages(c("shiny", "bslib", "DT", "plotly")).
dcm and param.dcm for the DCM modeling API; icm and param.icm for the ICM modeling API.
## Not run: ## Deterministic compartmental models epiweb(class = "dcm") ## Stochastic individual contact models epiweb(class = "icm") ## End(Not run)## Not run: ## Deterministic compartmental models epiweb(class = "dcm") ## Stochastic individual contact models epiweb(class = "icm") ## End(Not run)
Plots quantile bands given a data.frame with stochastic model
results from icm() or netsim().
geom_bands(mapping, lower = 0.25, upper = 0.75, alpha = 0.25, ...)geom_bands(mapping, lower = 0.25, upper = 0.75, alpha = 0.25, ...)
mapping |
Standard aesthetic mapping |
lower |
Lower quantile for the time series. |
upper |
Upper quantile for the time series. |
alpha |
Transparency of the ribbon fill. |
... |
Additional arguments passed to |
This is a wrapper around ggplot::stat_summary with a ribbon geom as
aesthetic output.
param <- param.icm(inf.prob = 0.2, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 250, nsims = 5) mod1 <- icm(param, init, control) df <- as.data.frame(mod1) df.mean <- as.data.frame(mod1, out = "mean") library(ggplot2) ggplot() + geom_line(data = df, mapping = aes(time, i.num, group = sim), alpha = 0.25, lwd = 0.25, color = "firebrick") + geom_bands(data = df, mapping = aes(time, i.num), lower = 0.1, upper = 0.9, fill = "firebrick") + geom_line(data = df.mean, mapping = aes(time, i.num)) + theme_minimal()param <- param.icm(inf.prob = 0.2, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 250, nsims = 5) mod1 <- icm(param, init, control) df <- as.data.frame(mod1) df.mean <- as.data.frame(mod1, out = "mean") library(ggplot2) ggplot() + geom_line(data = df, mapping = aes(time, i.num, group = sim), alpha = 0.25, lwd = 0.25, color = "firebrick") + geom_bands(data = df, mapping = aes(time, i.num), lower = 0.1, upper = 0.9, fill = "firebrick") + geom_line(data = df.mean, mapping = aes(time, i.num)) + theme_minimal()
Returns an adjacency list from an edge list
get_adj_list(el, n_nodes)get_adj_list(el, n_nodes)
el |
An edge list as a data.frame with columns |
n_nodes |
The size number of node in the network |
The adjacency list is a list of length n_nodes. The entry for each node
is a integer vector containing the index of all the nodes connected to it.
This layout makes it directly subsetable in O(1) at the expanse of memory
usage.
To get all connections to the nodes 10 and 15 : unlist(adj_list[c(10, 15)]
An adjacency list for the network
Retrieve, create, and edit the nodal attributes of the main
netsim_dat object of network models, from inside module
functions. Each nodal attribute is a vector with one value per
node, indexed by the positional identifiers of the nodes
(posit_ids).
get_attr() returns one attribute, for all nodes or for the nodes in
posit_ids. get_attr_list() returns several attributes as a named
list.
set_attr() replaces the values of an attribute, for all nodes or for
the nodes in posit_ids, and creates the attribute if it does not
exist. add_attr() creates an attribute set to NA for all nodes.
append_core_attr() adds n.new nodes and sets their core
attributes. append_attr() then adds the values of each other
attribute for the same nodes.
remove_node_attr() removes the nodes in posit_ids from every
attribute.
get_core_attributes() lists the core attributes with their types.
See net-accessor for an overview of the accessors.
get_attr(dat, item, posit_ids = NULL, override.null.error = FALSE) get_attr_list(dat, item = NULL) set_attr(dat, item, value, posit_ids = NULL, override.length.check = FALSE) add_attr(dat, item) append_attr(dat, item, value, n.new) append_core_attr(dat, at, n.new) remove_node_attr(dat, posit_ids) get_core_attributes()get_attr(dat, item, posit_ids = NULL, override.null.error = FALSE) get_attr_list(dat, item = NULL) set_attr(dat, item, value, posit_ids = NULL, override.length.check = FALSE) add_attr(dat, item) append_attr(dat, item, value, n.new) append_core_attr(dat, at, n.new) remove_node_attr(dat, posit_ids) get_core_attributes()
dat |
Main |
item |
Name of the nodal attribute. For |
posit_ids |
Positional identifiers of the nodes. For |
override.null.error |
If |
value |
New values of the attribute. For |
override.length.check |
If |
n.new |
Number of new nodes: for |
at |
Current time step, recorded as the entry time ( |
For get_attr(), the attribute vector, or its values for the
nodes in posit_ids; for get_attr_list(), a named list of
attribute vectors; for get_core_attributes(), a named list with a
value of the correct type for each core attribute. The other
functions return the updated netsim_dat object.
The append_core_attr function initializes the attributes necessary for
EpiModel to work (the four core attributes are: "active", "unique_id",
"entrTime", and "exitTime"). These attributes are used in the initialization
phase of the simulation, to create the nodes (see
initialize.net()); and also used when adding nodes during the
simulation (see arrivals.net()).
Every nodal attribute holds exactly one value per node, and netsim()
checks this at the end of each time step. When set_attr and append_attr
create an attribute, the nodes they do not write to are filled with NA to
preserve that: set_attr with posit_ids fills the unselected nodes, and
append_attr fills the nodes that predate the ones being appended. This
means append_core_attr must be called before append_attr when adding new
nodes, as it is what makes those nodes known to the rest of the object.
These accessors operate on the live netsim_dat object that EpiModel
constructs internally when a simulation starts and passes through each
module at every time step. The expected calling context is inside a
user-supplied module function (e.g., a custom infection.FUN,
recovery.FUN, or arrivals/departures module) registered with
control.net().
They are not a general-purpose tool for editing the user-facing input
or output objects of netsim():
Calling them on a param.net(), init.net(), or control.net()
object before a run will appear to succeed (those objects are also
list-like) but produces an object that is not a valid simulation
input.
Calling them on the object returned by netsim() modifies only the
saved input slot, not anything that would change the result of a
re-run. Note also that netsim() strips the *.FUN entries from
its returned control slot, so feeding that slot back into a new
simulation will fail.
For modifications outside a running simulation, use the following instead:
Editing parameters before a run: update_params() for a
param.net object, or direct list assignment
(e.g., p$inf.prob <- 0.5).
Editing init or control before a run: direct list assignment
(e.g., ctrl$nsteps <- 1000), or rebuild with a fresh call to the
init.net() / control.net() constructor.
Scheduled mid-simulation changes: the .param.updater.list
argument to param.net() and the .control.updater.list argument
to control.net(). See the "model-parameters" vignette for the
underlying updater module and the scenario API built on top of it.
The set_, append_, and add_ functions DO NOT modify the
netsim_dat object in place. The result must be assigned back to
dat in order to be registered: dat <- set_*(dat, item, value).
net-accessor for an overview of the accessors, and get_epi()
and get_param() for the other groups; arrive_nodes() and
depart_nodes() for adding and removing nodes from the networks;
get_unique_ids() and get_posit_ids() for converting node identifiers.
dat <- create_dat_object(control = list(nsteps = 150)) dat <- append_core_attr(dat, at = 1, n.new = 10) dat <- add_attr(dat, "age") dat <- set_attr(dat, "age", runif(10, 15, 65)) dat <- set_attr(dat, "status", rep(c("s", "i"), c(8, 2))) get_attr_list(dat) get_attr_list(dat, c("age", "active")) get_attr(dat, "status") get_attr(dat, "status", posit_ids = c(1, 9)) # Edit selected nodes dat <- set_attr(dat, "status", "i", posit_ids = 3) get_attr(dat, "status") # Add 5 nodes: core attributes first, then the others dat <- append_core_attr(dat, at = 2, n.new = 5) dat <- append_attr(dat, "status", "s", 5) dat <- append_attr(dat, "age", 15, 5) get_attr(dat, "age") get_attr(dat, "entrTime")dat <- create_dat_object(control = list(nsteps = 150)) dat <- append_core_attr(dat, at = 1, n.new = 10) dat <- add_attr(dat, "age") dat <- set_attr(dat, "age", runif(10, 15, 65)) dat <- set_attr(dat, "status", rep(c("s", "i"), c(8, 2))) get_attr_list(dat) get_attr_list(dat, c("age", "active")) get_attr(dat, "status") get_attr(dat, "status", posit_ids = c(1, 9)) # Edit selected nodes dat <- set_attr(dat, "status", "i", posit_ids = 3) get_attr(dat, "status") # Add 5 nodes: core attributes first, then the others dat <- append_core_attr(dat, at = 2, n.new = 5) dat <- append_attr(dat, "status", "s", 5) dat <- append_attr(dat, "age", 15, 5) get_attr(dat, "age") get_attr(dat, "entrTime")
Reconstructs the state of all tracked attributes at a specific time step
from the delta-compressed attribute history. Returns a tibble with one
row per active node and one column per tracked attribute.
get_attr_at(sim, at, sim_num = 1, compute_age = FALSE)get_attr_at(sim, at, sim_num = 1, compute_age = FALSE)
sim |
An |
at |
The time step at which to reconstruct attributes, on the time
step labels of |
sim_num |
The simulation number to use (default 1). |
compute_age |
If |
A tibble with columns unique_id, active, and one column per
tracked attribute, containing the most recent value at or before at
for each active node.
record_attr_history(), get_attr_history()
nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) control <- control.net(type = "SI", nsteps = 20, nsims = 1, tracked.attributes = "status", verbose = FALSE) sim <- netsim(est, param.net(inf.prob = 0.3, act.rate = 1), init.net(i.num = 10), control) # The status of every node at time step 10 at10 <- get_attr_at(sim, at = 10) head(at10) table(at10$status)nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) control <- control.net(type = "SI", nsteps = 20, nsims = 1, tracked.attributes = "status", verbose = FALSE) sim <- netsim(est, param.net(inf.prob = 0.3, act.rate = 1), init.net(i.num = 10), control) # The status of every node at time step 10 at10 <- get_attr_at(sim, at = 10) head(at10) table(at10$status)
Extract the Attributes History from Network Simulations
get_attr_history(sims)get_attr_history(sims)
sims |
An |
A list of data.frames, one for each "measure" recorded in the
simulation by the record_attr_history function.
nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) control <- control.net(type = "SI", nsteps = 20, nsims = 1, tracked.attributes = "status", verbose = FALSE) sim <- netsim(est, param.net(inf.prob = 0.3, act.rate = 1), init.net(i.num = 10), control) # One data frame per tracked attribute, with the changes at each step hist <- get_attr_history(sim) names(hist) head(hist$status)nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) control <- control.net(type = "SI", nsteps = 20, nsims = 1, tracked.attributes = "status", verbose = FALSE) sim <- netsim(est, param.net(inf.prob = 0.3, act.rate = 1), init.net(i.num = 10), control) # One data frame per tracked attribute, with the changes at each step hist <- get_attr_history(sim) names(hist) head(hist$status)
Returns all the node connected directly or indirectly to a set of nodes
get_connected_nodes(adj_list, nodes)get_connected_nodes(adj_list, nodes)
adj_list |
The network represented as an adjacency list |
nodes |
A set of nodes |
A vector of nodes indexes that are connected together with the ones
provided in the nodes argument. The nodes themselves are not
listed in this output
Counts the number of distinct partners each of a set of index nodes has
accumulated over the tracked history. A thin wrapper around
get_partners() that collapses the partner list to a count per index.
get_cumulative_degree( dat, index_posit_ids, networks = NULL, truncate = Inf, only.active.nodes = FALSE )get_cumulative_degree( dat, index_posit_ids, networks = NULL, truncate = Inf, only.active.nodes = FALSE )
dat |
Main |
index_posit_ids |
The positional IDs of the indexes of interest. |
networks |
Numerical indexes of the networks to extract the partnerships from. (May be > 1
for models with multi-layer networks.) If |
truncate |
After how many time steps a partnership that is no longer active should be removed from the output. See the Truncation section. |
only.active.nodes |
If |
A data.frame with 2 columns:
index_pid: the positional ID (see get_posit_ids()) of the indexes.
degree: the cumulative degree of the index.
The cumulative degree of a node is the number of distinct partners
connected to it during the tracked time window. The window is whatever
history the cumulative edgelist currently contains (controlled at
simulation time by control$truncate.el.cuml and at call time by the
truncate argument).
get_partners() for the full partner list backing this count.
Other cumulative_edgelist:
as_cumulative_edgelist(),
dedup_cumulative_edgelist(),
get_cumulative_edgelist(),
get_cumulative_edgelists_df(),
get_partners(),
reachable-nodes,
update_cumulative_edgelist()
## Not run: get_cumulative_degree(dat, index_posit_ids = 1:50, truncate = 52) ## End(Not run)## Not run: get_cumulative_degree(dat, index_posit_ids = 1:50, truncate = 52) ## End(Not run)
Returns the cumulative edgelist for a given network: a record of every edge
EpiModel has tracked, with the time steps at which each edge formed and
(if no longer active) dissolved. This is the canonical mechanism for
querying partnership histories during or after a simulation, and is
particularly important under tergmLite = TRUE, where the full
networkDynamic history is not retained.
get_cumulative_edgelist(dat, network)get_cumulative_edgelist(dat, network)
dat |
Main |
network |
Numerical index of the network from which the cumulative edgelist should be extracted. (May be > 1 for models with multiple overlapping networks.) |
Cumulative-edgelist tracking is opt-in. It must be enabled via
control.net(cumulative.edgelist = TRUE) (see control.net()); calling
this function on a simulation that did not enable tracking raises an error.
Inside a custom module (where dat is the live netsim_dat object), call
this function directly. After a netsim() run, the saved edgelists are
attached to the returned object as sim$cumulative.edgelist[[s]] (one
element per simulation, populated when save.cumulative.edgelist = TRUE);
read those directly rather than calling this function on the processed
output.
For the current (active-only, no history) edgelist, see get_edgelist()
and get_edgelists_df().
A tibble with four columns:
head: the unique ID (see get_unique_ids()) of the head node.
tail: the unique ID of the tail node.
start: the time step at which the edge formed.
stop: the time step at which the edge dissolved, or NA if the edge
is still active. Edges are active over [start, stop] inclusive.
control.net() for the controlling flags (cumulative.edgelist,
truncate.el.cuml, save.cumulative.edgelist).
vignette("network-objects", package = "EpiModel") walks through the
full lifecycle.
Other cumulative_edgelist:
as_cumulative_edgelist(),
dedup_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelists_df(),
get_partners(),
reachable-nodes,
update_cumulative_edgelist()
## Not run: # Inside a custom module (dat is the live netsim_dat object): el <- get_cumulative_edgelist(dat, network = 1) # Post-simulation on a processed netsim object, read the saved slot: sim$cumulative.edgelist[[1]] ## End(Not run)## Not run: # Inside a custom module (dat is the live netsim_dat object): el <- get_cumulative_edgelist(dat, network = 1) # Post-simulation on a processed netsim object, read the saved slot: sim$cumulative.edgelist[[1]] ## End(Not run)
Combines the cumulative edgelists from one or more network layers into a
single data.frame, adding a network column to identify the layer.
Like get_cumulative_edgelist(), this requires
control.net(cumulative.edgelist = TRUE).
get_cumulative_edgelists_df(dat, networks = NULL)get_cumulative_edgelists_df(dat, networks = NULL)
dat |
Main |
networks |
Numerical indexes of the networks to extract the partnerships
from. (May be > 1 for models with multiple overlapping
networks.) If |
A data.frame with 5 columns:
head: the unique ID (see get_unique_ids()) of the head node.
tail: the unique ID of the tail node.
start: the time step at which the edge formed.
stop: the time step at which the edge dissolved, or NA if still
active.
network: the numerical index of the network on which the
partnership lives.
Note: column names head/tail here match the single-network
get_cumulative_edgelist() output. The index/partner naming used by
get_partners() is reserved for queries about specific index nodes.
get_cumulative_edgelist() (single network), control.net()
(cumulative.edgelist, save.cumulative.edgelist).
vignette("network-objects", package = "EpiModel") walks through the
full lifecycle.
Other cumulative_edgelist:
as_cumulative_edgelist(),
dedup_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelist(),
get_partners(),
reachable-nodes,
update_cumulative_edgelist()
Return the Current Timestep
get_current_timestep(dat)get_current_timestep(dat)
dat |
Main |
The current timestep.
A fast method for querying the current degree of all individuals within a network.
get_degree(x)get_degree(x)
x |
Either an object of class |
Individual-level data on the current degree of nodes within a network is
often useful for summary statistics. Given a network class object,
net, one way to look up the current degree is to get a summary of the
ERGM term, sociality, as in:
summary(net ~ sociality(nodes = NULL)). But that is computationally
inefficient for a number of reasons. This function provides a fast method for
generating the vector of degrees using a query of the edgelist. It is even
faster if the parameter x is already transformed into an edgelist.
A vector of length equal to the total network size, containing the current degree of each node in the network.
nw <- network_initialize(n = 500) set.seed(1) fit <- ergm(nw ~ edges, target.stats = 250) sim <- simulate(fit) # Slow ERGM-based method ergm.method <- unname(summary(sim ~ sociality(nodes = NULL))) ergm.method # Fast tabulate method with network object deg.net <- get_degree(sim) deg.net # Even faster if network already transformed into an edgelist el <- as.edgelist(sim) deg.el <- get_degree(el) deg.el identical(as.integer(ergm.method), deg.net, deg.el)nw <- network_initialize(n = 500) set.seed(1) fit <- ergm(nw ~ edges, target.stats = 250) sim <- simulate(fit) # Slow ERGM-based method ergm.method <- unname(summary(sim ~ sociality(nodes = NULL))) ergm.method # Fast tabulate method with network object deg.net <- get_degree(sim) deg.net # Even faster if network already transformed into an edgelist el <- as.edgelist(sim) deg.el <- get_degree(el) deg.el identical(as.integer(ergm.method), deg.net, deg.el)
Calculates the cumulative or momentary degree distribution from
the timed edgelist of a dynamic netdx() simulation.
get_degree_dist( x, type = c("cumulative", "momentary"), sims = NULL, window = NULL, unique.partners = TRUE )get_degree_dist( x, type = c("cumulative", "momentary"), sims = NULL, window = NULL, unique.partners = TRUE )
x |
An |
type |
Distribution to calculate, either |
sims |
A vector of simulation numbers to include. The default is all
simulations in |
window |
A vector of length 2 giving the first and last time step of
the observation window, on the time scale of the timed edgelist
(which starts at 0). The default is the full simulation,
|
unique.partners |
If |
The momentary degree distribution is the distribution plotted by
plot.netdx() when degree(k) terms are included in the nwstats.formula
of netdx(): it counts the partners a node has at one moment in time. The
cumulative degree distribution counts the partners a node accumulates across
the whole observation window, so a node with one partner at a time and a
node with several simultaneous partners may have the same cumulative degree.
Partnerships are counted if they are active at any point in the window: a
partnership contributes to the cumulative degree of both of its nodes when
its spell overlaps window, and to the momentary degree of both nodes at
each time step of the window in which it is active. Partnerships that are
ongoing when the simulation ends are counted for the steps they are
observed.
Because the cumulative degree grows with the length of the observation
window, window should be set to a substantively meaningful period (for
example, one year of time steps) when comparing across models or against
data.
A data.frame with one row per simulation and degree value, and the
columns:
sim: the simulation number.
degree: the degree value, from 0 to the maximum observed across the
selected simulations.
count: the number of nodes with that degree. For
type = "momentary", this is the mean number of nodes per time step,
and so need not be a whole number.
prop: count divided by the network size.
plot.netdx() with type = "cumldeg" to plot these distributions,
and netdx() to generate the input object.
nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), duration = 10), verbose = FALSE) dx <- netdx(est, nsims = 2, nsteps = 50, keep.tedgelist = TRUE, verbose = FALSE) # Cumulative degree over the full simulation cd <- get_degree_dist(dx, type = "cumulative") head(cd) # Mean cumulative degree per simulation tapply(cd$degree * cd$prop, cd$sim, sum) # Momentary degree over the last 25 steps get_degree_dist(dx, type = "momentary", window = c(25, 50))nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), duration = 10), verbose = FALSE) dx <- netdx(est, nsims = 2, nsteps = 50, keep.tedgelist = TRUE, verbose = FALSE) # Cumulative degree over the full simulation cd <- get_degree_dist(dx, type = "cumulative") head(cd) # Mean cumulative degree per simulation tapply(cd$degree * cd$prop, cd$sim, sum) # Momentary degree over the last 25 steps get_degree_dist(dx, type = "momentary", window = c(25, 50))
This function outputs an edgelist from the specified network, selecting the method depending on the stored network type.
get_edgelist(dat, network)get_edgelist(dat, network)
dat |
Main |
network |
Numerical index of the network from which the edgelist should be extracted. (May be > 1 for models with multiple overlapping networks.) |
An edgelist in matrix form with two columns. Each column contains the
posit_ids (see get_posit_ids) of the nodes in each edge.
Get the Edgelist(s) from the Specified Network(s)
get_edgelists_df(dat, networks = NULL)get_edgelists_df(dat, networks = NULL)
dat |
Main |
networks |
Numerical indexes of the networks to extract the partnerships
from. (May be > 1 for models with multiple overlapping
networks.) If |
A data.frame with the following columns:
head: Positional ID of the head node.
tail: Positional ID of the tail node.
network: The numerical index of the network on which the edge is located.
Retrieve, create, and edit the epidemic outputs of the main
netsim_dat object of network models, from inside module
functions. Each epidemic output is a vector with one value per
time step, which becomes a column of the data frame returned by
as.data.frame.netsim() after the simulation.
get_epi() returns one output, for all time steps or for the time
steps in at. get_epi_list() returns several outputs as a named
list.
set_epi() records value at one time step, the current one by
default, and creates the output if it does not exist. add_epi()
creates an output set to NA at every time step.
Unlike the other set_ functions, set_epi() takes a time step at,
which comes last and must be passed by name.
See net-accessor for an overview of the accessors.
get_epi(dat, item, at = NULL, override.null.error = FALSE) get_epi_list(dat, item = NULL) set_epi(dat, item, value, ..., at = NULL) add_epi(dat, item)get_epi(dat, item, at = NULL, override.null.error = FALSE) get_epi_list(dat, item = NULL) set_epi(dat, item, value, ..., at = NULL) add_epi(dat, item)
dat |
Main |
item |
Name of the epidemic output. For |
at |
For |
override.null.error |
If |
value |
Value of the output at time step |
... |
Must be empty. It makes |
For get_epi(), the output vector, or its values at the time
steps in at; for get_epi_list(), a named list of output
vectors. The other functions return the updated netsim_dat
object.
These accessors operate on the live netsim_dat object that EpiModel
constructs internally when a simulation starts and passes through each
module at every time step. The expected calling context is inside a
user-supplied module function (e.g., a custom infection.FUN,
recovery.FUN, or arrivals/departures module) registered with
control.net().
They are not a general-purpose tool for editing the user-facing input
or output objects of netsim():
Calling them on a param.net(), init.net(), or control.net()
object before a run will appear to succeed (those objects are also
list-like) but produces an object that is not a valid simulation
input.
Calling them on the object returned by netsim() modifies only the
saved input slot, not anything that would change the result of a
re-run. Note also that netsim() strips the *.FUN entries from
its returned control slot, so feeding that slot back into a new
simulation will fail.
For modifications outside a running simulation, use the following instead:
Editing parameters before a run: update_params() for a
param.net object, or direct list assignment
(e.g., p$inf.prob <- 0.5).
Editing init or control before a run: direct list assignment
(e.g., ctrl$nsteps <- 1000), or rebuild with a fresh call to the
init.net() / control.net() constructor.
Scheduled mid-simulation changes: the .param.updater.list
argument to param.net() and the .control.updater.list argument
to control.net(). See the "model-parameters" vignette for the
underlying updater module and the scenario API built on top of it.
The set_, append_, and add_ functions DO NOT modify the
netsim_dat object in place. The result must be assigned back to
dat in order to be registered: dat <- set_*(dat, item, value).
net-accessor for an overview of the accessors, and get_attr()
and get_param() for the other groups; epi_trackers() for outputs
computed by tracker functions at each time step; mutate_epi() for
outputs derived after the simulation.
dat <- create_dat_object(control = list(nsteps = 5)) dat <- set_current_timestep(dat, 1) dat <- add_epi(dat, "i.num") dat <- set_epi(dat, "i.num", 10) dat <- set_epi(dat, "s.num", 90) get_epi_list(dat) # Record at a time step other than the current one dat <- set_epi(dat, "i.num", 12, at = 2) get_epi_list(dat, c("i.num", "s.num")) get_epi(dat, "i.num") get_epi(dat, "i.num", at = c(1, 2))dat <- create_dat_object(control = list(nsteps = 5)) dat <- set_current_timestep(dat, 1) dat <- add_epi(dat, "i.num") dat <- set_epi(dat, "i.num", 10) dat <- set_epi(dat, "s.num", 90) get_epi_list(dat) # Record at a time step other than the current one dat <- set_epi(dat, "i.num", 12, at = 2) get_epi_list(dat, c("i.num", "s.num")) get_epi(dat, "i.num") get_epi(dat, "i.num", at = c(1, 2))
Given a formation formula for a network model, outputs a
character vector of vertex attributes to be used in
netsim() simulations.
get_formula_term_attr(form, nw)get_formula_term_attr(form, nw)
form |
An ERGM model formula. |
nw |
A network object. |
A character vector of vertex attributes.
Extracts the network object from either a network epidemic model
object generated with netsim, a network diagnostic
simulation generated with netdx, or a netsim_dat
object used internally in netsim. For netdx or
netsim with tergmLite == FALSE, the extracted
network object is a networkDynamic, which can be
collapsed down to a static network object with the
collapse and at arguments. For netsim with
tergmLite == TRUE, the extracted network object is the
final networkLite, the collapse argument should be
FALSE, and the at argument should be missing. For
netsim_dat, the collapse and at arguments
are not supported, and the network object is either the current
networkLite (if tergmLite == TRUE) or the current
networkDynamic (if tergmLite == FALSE).
get_network(x, ...) ## S3 method for class 'netdx' get_network(x, sim = 1, collapse = FALSE, at = NULL, ...) ## S3 method for class 'netsim' get_network(x, sim = 1, network = 1, collapse = FALSE, at = NULL, ...) ## S3 method for class 'netsim_dat' get_network(x, network = 1L, ...)get_network(x, ...) ## S3 method for class 'netdx' get_network(x, sim = 1, collapse = FALSE, at = NULL, ...) ## S3 method for class 'netsim' get_network(x, sim = 1, network = 1, collapse = FALSE, at = NULL, ...) ## S3 method for class 'netsim_dat' get_network(x, network = 1L, ...)
x |
An |
... |
Additional arguments. |
sim |
Simulation number of extracted network, for |
collapse |
If |
at |
If |
network |
Network number, for |
This function requires that the network object is saved during the network
simulation while running either netsim() or netdx().
For the former, that is specified by setting the save.network
parameter in control.net() to TRUE. For the latter, that
is specified with the keep.tnetwork parameter directly in
netdx().
For netdx or netsim with tergmLite == FALSE, a
networkDynamic object (if collapse = FALSE) or a
static network object (if collapse = TRUE). For
netsim with tergmLite == TRUE or netsim_dat with
tergmLite == TRUE, a networkLite object. For
netsim_dat with tergmLite == FALSE, a
networkDynamic object.
# Set up network and TERGM formula nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Estimate the model est <- netest(nw, formation, target.stats, coef.diss) # Run diagnostics, saving the networkDynamic objects dx <- netdx(est, nsteps = 10, nsims = 3, keep.tnetwork = TRUE, verbose = FALSE) # Extract the network for simulation 2 from dx object get_network(dx, sim = 2) # Extract and collapse the network from simulation 1 at time step 5 get_network(dx, collapse = TRUE, at = 5) # Parameterize the epidemic model, and simulate it param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod <- netsim(est, param, init, control) # Extract the network for simulation 2 from mod object get_network(mod, sim = 2) ## Extract and collapse the network from simulation 1 at time step 5 get_network(mod, collapse = TRUE, at = 5)# Set up network and TERGM formula nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Estimate the model est <- netest(nw, formation, target.stats, coef.diss) # Run diagnostics, saving the networkDynamic objects dx <- netdx(est, nsteps = 10, nsims = 3, keep.tnetwork = TRUE, verbose = FALSE) # Extract the network for simulation 2 from dx object get_network(dx, sim = 2) # Extract and collapse the network from simulation 1 at time step 5 get_network(dx, collapse = TRUE, at = 5) # Parameterize the epidemic model, and simulate it param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod <- netsim(est, param, init, control) # Extract the network for simulation 2 from mod object get_network(mod, sim = 2) ## Extract and collapse the network from simulation 1 at time step 5 get_network(mod, collapse = TRUE, at = 5)
Gets all network attributes except "mnext" from its
network argument.
get_network_attributes(x)get_network_attributes(x)
x |
An object of class |
This function is used in EpiModel workflows to copy relevant network
attributes from the network object to the netsim_dat object when
initializing netsim runs.
Returns the named list of network attributes.
nw <- network_initialize(100) get_network_attributes(nw)nw <- network_initialize(100) get_network_attributes(nw)
Given a simulated network, outputs a character vector of vertex
attributes to be used in netsim() simulations.
get_network_term_attr(nw)get_network_term_attr(nw)
nw |
A network object. |
A character vector of vertex attributes.
Extracts network statistics from a network epidemic model
simulated with netsim or a network diagnostics object
simulated with netdx. Statistics can be returned either
as a single data frame or as a list of matrices (one matrix
for each simulation).
get_nwstats(x, sim = NULL, network = 1, mode = c("data.frame", "list"))get_nwstats(x, sim = NULL, network = 1, mode = c("data.frame", "list"))
x |
|
sim |
A vector of simulation numbers from the extracted object. (Default = NULL, all simulations are included) |
network |
Network number, for |
mode |
Either |
A data frame or list of matrices containing the network statistics.
# Two-group Bernoulli random graph TERGM nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) dx <- netdx(est, nsim = 3, nsteps = 10, verbose = FALSE, nwstats.formula = ~edges + isolates) get_nwstats(dx) get_nwstats(dx, sim = 1) # SI epidemic model param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, nwstats.formula = ~edges + meandeg + degree(0:5), verbose = FALSE) mod <- netsim(est, param, init, control) # Extract the network statistics from all or sets of simulations get_nwstats(mod) get_nwstats(mod, sim = 2) get_nwstats(mod, sim = c(1, 3)) # On the fly summary stats summary(get_nwstats(mod)) colMeans(get_nwstats(mod))# Two-group Bernoulli random graph TERGM nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) dx <- netdx(est, nsim = 3, nsteps = 10, verbose = FALSE, nwstats.formula = ~edges + isolates) get_nwstats(dx) get_nwstats(dx, sim = 1) # SI epidemic model param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, nwstats.formula = ~edges + meandeg + degree(0:5), verbose = FALSE) mod <- netsim(est, param, init, control) # Extract the network statistics from all or sets of simulations get_nwstats(mod) get_nwstats(mod, sim = 2) get_nwstats(mod, sim = c(1, 3)) # On the fly summary stats summary(get_nwstats(mod)) colMeans(get_nwstats(mod))
Retrieve, create, and edit the parameters, control settings,
and initial conditions of the main netsim_dat object of
network models, from inside module functions. They start as
the param.net(), control.net(), and init.net() inputs of
netsim(), and the three share one set of accessors:
get_param(), get_control(), and get_init() return one element.
get_param_list(), get_control_list(), and get_init_list() return
several elements as a named list.
set_param(), set_control(), and set_init() replace the value of an
element, and create the element if it does not exist. add_param(),
add_control(), and add_init() create an element set to NA.
get_network_control() returns the entry for one network layer of a
control setting given as a multilayer() object.
Unlike set_attr() and set_epi(), these set_ functions take neither
nodes nor a time step: the new value is used from then on, until it is set
again.
See net-accessor for an overview of the accessors.
get_param(dat, item, override.null.error = FALSE) get_param_list(dat, item = NULL) set_param(dat, item, value) add_param(dat, item) get_control(dat, item, override.null.error = FALSE) get_control_list(dat, item = NULL) get_network_control(dat, network, item, override.null.error = FALSE) set_control(dat, item, value) add_control(dat, item) get_init(dat, item, override.null.error = FALSE) get_init_list(dat, item = NULL) set_init(dat, item, value) add_init(dat, item)get_param(dat, item, override.null.error = FALSE) get_param_list(dat, item = NULL) set_param(dat, item, value) add_param(dat, item) get_control(dat, item, override.null.error = FALSE) get_control_list(dat, item = NULL) get_network_control(dat, network, item, override.null.error = FALSE) set_control(dat, item, value) add_control(dat, item) get_init(dat, item, override.null.error = FALSE) get_init_list(dat, item = NULL) set_init(dat, item, value) add_init(dat, item)
dat |
Main |
item |
Name of the parameter, control setting, or initial condition.
For the |
override.null.error |
If |
value |
New value of the element. |
network |
Index of the network layer. |
For get_param(), get_control(), and get_init(), the value of
the element; for get_network_control(), its entry for layer
network; for the get_*_list() functions, a named list of
elements. The other functions return the updated netsim_dat
object.
These accessors operate on the live netsim_dat object that EpiModel
constructs internally when a simulation starts and passes through each
module at every time step. The expected calling context is inside a
user-supplied module function (e.g., a custom infection.FUN,
recovery.FUN, or arrivals/departures module) registered with
control.net().
They are not a general-purpose tool for editing the user-facing input
or output objects of netsim():
Calling them on a param.net(), init.net(), or control.net()
object before a run will appear to succeed (those objects are also
list-like) but produces an object that is not a valid simulation
input.
Calling them on the object returned by netsim() modifies only the
saved input slot, not anything that would change the result of a
re-run. Note also that netsim() strips the *.FUN entries from
its returned control slot, so feeding that slot back into a new
simulation will fail.
For modifications outside a running simulation, use the following instead:
Editing parameters before a run: update_params() for a
param.net object, or direct list assignment
(e.g., p$inf.prob <- 0.5).
Editing init or control before a run: direct list assignment
(e.g., ctrl$nsteps <- 1000), or rebuild with a fresh call to the
init.net() / control.net() constructor.
Scheduled mid-simulation changes: the .param.updater.list
argument to param.net() and the .control.updater.list argument
to control.net(). See the "model-parameters" vignette for the
underlying updater module and the scenario API built on top of it.
The set_, append_, and add_ functions DO NOT modify the
netsim_dat object in place. The result must be assigned back to
dat in order to be registered: dat <- set_*(dat, item, value).
net-accessor for an overview of the accessors, and get_attr()
and get_epi() for the other groups; update_params() for editing a
param.net object outside a simulation.
dat <- create_dat_object(control = list(nsteps = 150)) dat <- add_param(dat, "x") get_param(dat, "x") dat <- set_param(dat, "x", 0.4) dat <- set_param(dat, "y", 0.8) get_param_list(dat) get_param(dat, "x") # The control and init accessors work the same way dat <- add_control(dat, "x") dat <- set_control(dat, "x", 0.4) get_control_list(dat, c("nsteps", "x")) get_control(dat, "nsteps") dat <- add_init(dat, "x") dat <- set_init(dat, "x", 0.4) get_init_list(dat) get_init(dat, "x") # A control setting with one entry per network layer dat <- set_control(dat, "z", multilayer(0.1, 0.2)) get_network_control(dat, network = 2, "z")dat <- create_dat_object(control = list(nsteps = 150)) dat <- add_param(dat, "x") get_param(dat, "x") dat <- set_param(dat, "x", 0.4) dat <- set_param(dat, "y", 0.8) get_param_list(dat) get_param(dat, "x") # The control and init accessors work the same way dat <- add_control(dat, "x") dat <- set_control(dat, "x", 0.4) get_control_list(dat, c("nsteps", "x")) get_control(dat, "nsteps") dat <- add_init(dat, "x") dat <- set_init(dat, "x", 0.4) get_init_list(dat) get_init(dat, "x") # A control setting with one entry per network layer dat <- set_control(dat, "z", multilayer(0.1, 0.2)) get_network_control(dat, network = 2, "z")
Pulls every cumulative-edgelist row touching one of the supplied "index"
nodes, returning each (index, partner) pair together with the
partnership start/stop times and the network layer. This is the building
block for contact tracing over the simulated network history.
get_partners( dat, index_posit_ids, networks = NULL, truncate = Inf, only.active.nodes = FALSE )get_partners( dat, index_posit_ids, networks = NULL, truncate = Inf, only.active.nodes = FALSE )
dat |
Main |
index_posit_ids |
The positional IDs of the indexes of interest. |
networks |
Numerical indexes of the networks to extract the partnerships from. (May be > 1
for models with multi-layer networks.) If |
truncate |
After how many time steps a partnership that is no longer active should be removed from the output. See the Truncation section. |
only.active.nodes |
If |
Indexes are passed as positional IDs but the output uses unique IDs,
because partners may include nodes that have already departed (and thus
no longer have a positional ID). Use get_unique_ids() and
get_posit_ids() to convert between the two systems.
The truncate argument here filters by edge age: only edges whose stop
step is within truncate time steps of the current step are kept (active
edges are always included). It operates on whatever history is already
stored in the cumulative edgelist; it cannot recover edges that were
dropped earlier by update_cumulative_edgelist() or by
control$truncate.el.cuml.
A data.frame with 5 columns:
index: the unique IDs of the indexes.
partner: the unique IDs of the partners/contacts.
start: the time step at which the edge started.
stop: the time step in which the edge stopped; if ongoing, then NA is returned.
network: the numerical index for the network on which the partnership/contact is located.
get_cumulative_degree() for a partner count per index;
get_cumulative_edgelist() / get_cumulative_edgelists_df() for the
underlying edgelist; get_unique_ids() / get_posit_ids() for ID
conversion.
Other cumulative_edgelist:
as_cumulative_edgelist(),
dedup_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelist(),
get_cumulative_edgelists_df(),
reachable-nodes,
update_cumulative_edgelist()
## Not run: # Contacts of nodes 1..10 across all networks within the last 30 steps, # excluding partners who have since departed: get_partners(dat, index_posit_ids = 1:10, truncate = 30, only.active.nodes = TRUE) ## End(Not run)## Not run: # Contacts of nodes 1..10 across all networks within the last 30 steps, # excluding partners who have since departed: get_partners(dat, index_posit_ids = 1:10, truncate = 30, only.active.nodes = TRUE) ## End(Not run)
Subsets the entire netsim object to a subset of
simulations, essentially functioning like a reverse of
merge.
get_sims(x, sims, var = NULL)get_sims(x, sims, var = NULL)
x |
An object of class |
sims |
Either a numeric vector of simulation numbers to retain in the
output object, or |
var |
A character vector of variables to retain from |
An updated object of class netsim containing only the
simulations specified in sims and the variables specified in
var.
# Network model estimation nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Epidemic model param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose.int = 0) mod1 <- netsim(est1, param, init, control) # Get sim 2 s.g2 <- get_sims(mod1, sims = 2) # Get sims 2 and 3 and keep only a subset of variables s.g2.small <- get_sims(mod1, sims = 2:3, var = c("i.num", "si.flow")) # Extract the mean simulation for the variable i.num sim.mean <- get_sims(mod1, sims = "mean", var = "i.num")# Network model estimation nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Epidemic model param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose.int = 0) mod1 <- netsim(est1, param, init, control) # Get sim 2 s.g2 <- get_sims(mod1, sims = 2) # Get sims 2 and 3 and keep only a subset of variables s.g2.small <- get_sims(mod1, sims = 2:3, var = c("i.num", "si.flow")) # Extract the mean simulation for the variable i.num sim.mean <- get_sims(mod1, sims = "mean", var = "i.num")
Return an adjacency list of subnets
get_subnet_adj_list(adj_list)get_subnet_adj_list(adj_list)
adj_list |
A normal adjacency list |
A graph with 4 components: 1, 2, 3, 4, and 5 and 6, 7, 8 would yield a list like so: 1: 2, 3, 4 2: 1 3: 1 4: 1 5: numeric(0) 6: 7, 8 7: 6, 8: 6
This format speeds up the construction of reachable sets on dense networks
An adjacency list where only the first node of a subnet contains the subnet and all other contain only the first node
Gets a vertex attribute from an object of class network.
This function simplifies the related function in the
network package.
get_vertex_attribute(x, attrname)get_vertex_attribute(x, attrname)
x |
An object of class network. |
attrname |
The name of the attribute to get. |
This function is used in EpiModel workflows to query vertex
attributes on an initialized empty network object (see
network_initialize()).
Returns a vector of vertex attribute values for the attribute specified
by attrname.
nw <- network_initialize(100) nw <- set_vertex_attribute(nw, "age", runif(100, 15, 65)) get_vertex_attribute(nw, "age")nw <- network_initialize(100) nw <- set_vertex_attribute(nw, "age", runif(100, 15, 65)) get_vertex_attribute(nw, "age")
Simulates stochastic individual contact epidemic models for infectious disease.
icm(param, init, control)icm(param, init, control)
param |
Model parameters, as an object of class |
init |
Initial conditions, as an object of class |
control |
Control settings, as an object of class
|
Individual contact models are intended to be the stochastic microsimulation analogs to deterministic compartmental models. ICMs simulate disease spread on individual agents in discrete time as a function of processes with stochastic variation. The stochasticity is inherent in all transition processes: infection, recovery, and demographics.
The icm function supports the built-in SI, SIR, and SIS disease types
only, in one-group or two-group configurations, with or without demography.
For custom or extension epidemic models, use the network model class via
netsim() with control.net(type = NULL, ...) and user-supplied module
functions.
A list of class icm with the following elements:
param: the epidemic parameters passed into the model through
param, with additional parameters added as necessary.
control: the control settings passed into the model through
control, with additional controls added as necessary.
epi: a list of data frames, one for each epidemiological output from the model. Outputs always include the size of each compartment, as well as flows in, out of, and between compartments.
Extract the model results with as.data.frame.icm().
Summarize the time-specific model results with summary.icm().
Plot the model results with plot.icm(). Plot a compartment flow
diagram with comp_plot().
## Not run: ## Example 1: SI Model param <- param.icm(inf.prob = 0.2, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 500, nsims = 10) mod1 <- icm(param, init, control) mod1 plot(mod1) ## Example 2: SIR Model param <- param.icm(inf.prob = 0.2, act.rate = 0.25, rec.rate = 1/50) init <- init.icm(s.num = 500, i.num = 1, r.num = 0) control <- control.icm(type = "SIR", nsteps = 500, nsims = 10) mod2 <- icm(param, init, control) mod2 plot(mod2) ## Example 3: SIS Model param <- param.icm(inf.prob = 0.2, act.rate = 0.25, rec.rate = 1/50) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SIS", nsteps = 500, nsims = 10) mod3 <- icm(param, init, control) mod3 plot(mod3) ## Example 4: SI Model with Vital Dynamics (Two-Group) param <- param.icm(inf.prob = 0.4, inf.prob.g2 = 0.1, act.rate = 0.25, balance = "g1", a.rate = 1/100, a.rate.g2 = NA, ds.rate = 1/100, ds.rate.g2 = 1/100, di.rate = 1/50, di.rate.g2 = 1/50) init <- init.icm(s.num = 500, i.num = 1, s.num.g2 = 500, i.num.g2 = 0) control <- control.icm(type = "SI", nsteps = 500, nsims = 10) mod4 <- icm(param, init, control) mod4 plot(mod4) ## End(Not run)## Not run: ## Example 1: SI Model param <- param.icm(inf.prob = 0.2, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 500, nsims = 10) mod1 <- icm(param, init, control) mod1 plot(mod1) ## Example 2: SIR Model param <- param.icm(inf.prob = 0.2, act.rate = 0.25, rec.rate = 1/50) init <- init.icm(s.num = 500, i.num = 1, r.num = 0) control <- control.icm(type = "SIR", nsteps = 500, nsims = 10) mod2 <- icm(param, init, control) mod2 plot(mod2) ## Example 3: SIS Model param <- param.icm(inf.prob = 0.2, act.rate = 0.25, rec.rate = 1/50) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SIS", nsteps = 500, nsims = 10) mod3 <- icm(param, init, control) mod3 plot(mod3) ## Example 4: SI Model with Vital Dynamics (Two-Group) param <- param.icm(inf.prob = 0.4, inf.prob.g2 = 0.1, act.rate = 0.25, balance = "g1", a.rate = 1/100, a.rate.g2 = NA, ds.rate = 1/100, ds.rate.g2 = 1/100, di.rate = 1/50, di.rate.g2 = 1/50) init <- init.icm(s.num = 500, i.num = 1, s.num.g2 = 500, i.num.g2 = 0) control <- control.icm(type = "SI", nsteps = 500, nsims = 10) mod4 <- icm(param, init, control) mod4 plot(mod4) ## End(Not run)
This function adds 1 to the timestep counter stored in the
netsim_dat main list object.
increment_timestep(dat)increment_timestep(dat)
dat |
Main |
The updated netsim_dat main list object.
This DOES NOT modify the netsim_dat object in place. The result must
be assigned back to dat in order to be registered:
dat <- increment_timestep(dat).
Sets the initial conditions for deterministic compartmental
models simulated with dcm.
init.dcm(s.num, i.num, r.num, s.num.g2, i.num.g2, r.num.g2, ...)init.dcm(s.num, i.num, r.num, s.num.g2, i.num.g2, r.num.g2, ...)
s.num |
Number of initial susceptible persons. For two-group models, this is the number of initial group 1 susceptible persons. |
i.num |
Number of initial infected persons. For two-group models, this is the number of initial group 1 infected persons. |
r.num |
Number of initial recovered persons. For two-group models, this
is the number of initial group 1 recovered persons. This parameter is
only used for the |
s.num.g2 |
Number of initial susceptible persons in group 2. This parameter is only used for two-group models. |
i.num.g2 |
Number of initial infected persons in group 2. This parameter is only used for two-group models. |
r.num.g2 |
Number of initial recovered persons in group 2. This
parameter is only used for two-group |
... |
Additional initial conditions passed to model. |
The initial conditions for a model solved with dcm() should be
input into the init.dcm function. This function handles initial
conditions for both base model types and original models.
Original models may use the parameter names listed as arguments here, a new set of names, or a combination of both. With new models, initial conditions must be input in the same order that the solved derivatives from the model are output.
An EpiModel object of class init.dcm.
Like param.dcm(), initial conditions may be specified as vectors of length
greater than one to run sensitivity analyses over initial conditions. When
sens.param = TRUE in control.dcm() (the default), each element of the
vector produces a separate model run. If both parameters and initial
conditions have vector values, all vectors must have the same length.
Use param.dcm() to specify model parameters and
control.dcm() to specify the control settings. Run the
parameterized model with dcm().
# SI model initial conditions init <- init.dcm(s.num = 500, i.num = 1) # Sensitivity analysis over initial infected count init <- init.dcm(s.num = 500, i.num = c(1, 5, 25))# SI model initial conditions init <- init.dcm(s.num = 500, i.num = 1) # Sensitivity analysis over initial infected count init <- init.dcm(s.num = 500, i.num = c(1, 5, 25))
Sets the initial conditions for stochastic individual contact
models simulated with icm.
init.icm(s.num, i.num, r.num, s.num.g2, i.num.g2, r.num.g2, ...)init.icm(s.num, i.num, r.num, s.num.g2, i.num.g2, r.num.g2, ...)
s.num |
Number of initial susceptible persons. For two-group models, this is the number of initial group 1 susceptible persons. |
i.num |
Number of initial infected persons. For two-group models, this is the number of initial group 1 infected persons. |
r.num |
Number of initial recovered persons. For two-group models, this
is the number of initial group 1 recovered persons. This parameter is
only used for the |
s.num.g2 |
Number of initial susceptible persons in group 2. This parameter is only used for two-group models. |
i.num.g2 |
Number of initial infected persons in group 2. This parameter is only used for two-group models. |
r.num.g2 |
Number of initial recovered persons in group 2. This
parameter is only used for two-group |
... |
Additional initial conditions passed to model. |
The initial conditions for a model solved with icm() should be
input into the init.icm function. This function handles initial
conditions for the built-in SI, SIR, and SIS disease types; for custom or
extension epidemic models, use init.net() with the network model class.
An EpiModel object of class init.icm.
Use param.icm() to specify model parameters and
control.icm() to specify the control settings. Run the
parameterized model with icm().
Sets the initial conditions for stochastic network models
simulated with netsim.
init.net(i.num, r.num, i.num.g2, r.num.g2, status.vector, infTime.vector, ...)init.net(i.num, r.num, i.num.g2, r.num.g2, status.vector, infTime.vector, ...)
i.num |
Number of initial infected persons. For two-group models, this is the number of initial group 1 infected persons. |
r.num |
Number of initial recovered persons. For two-group models, this
is the number of initial group 1 recovered persons. This parameter is
only used for the |
i.num.g2 |
Number of initial infected persons in group 2. This parameter is only used for two-group models. |
r.num.g2 |
Number of initial recovered persons in group 2. This
parameter is only used for two-group |
status.vector |
A vector of length equal to the size of the input
network, containing the status of each node. Setting status here
overrides any inputs passed in the |
infTime.vector |
A vector of length equal to the size of the input
network, containing the (historical) time of infection for each of
those nodes with a current status of |
... |
Additional initial conditions passed to model. |
The initial conditions for a model solved with netsim() should be
input into the init.net function. This function handles initial
conditions for both base models and new modules. For an overview of
specifying initial conditions across a variety of base network models,
consult the Network Modeling for Epidemics
tutorials.
An EpiModel object of class init.net.
Use param.net() to specify model parameters and
control.net() to specify the control settings. Run the
parameterized model with netsim().
# Example of using status.vector and infTime.vector together n <- 100 status <- sample(c("s", "i"), size = n, replace = TRUE, prob = c(0.8, 0.2)) infTime <- rep(NA, n) infTime[which(status == "i")] <- -rgeom(sum(status == "i"), prob = 0.01) + 2 init.net(status.vector = status, infTime.vector = infTime)# Example of using status.vector and infTime.vector together n <- 100 status <- sample(c("s", "i"), size = n, replace = TRUE, prob = c(0.8, 0.2)) infTime <- rep(NA, n) infTime[which(status == "i")] <- -rgeom(sum(status == "i"), prob = 0.01) + 2 init.net(status.vector = status, infTime.vector = infTime)
This function defines and initializes the absdiffby ERGM term that allows for representing homophily with respect to a non-binary attribute (e.g., age) differentially by a binary attribute (e.g., sex).
InitErgmTerm.absdiffby(nw, arglist, ...)InitErgmTerm.absdiffby(nw, arglist, ...)
nw |
An object of class |
arglist |
A list of arguments as specified in the |
... |
Additional data passed into the function as specified in the
|
This ERGM user term was written to allow for age-based homophily in
partnership formation that is asymmetric by sex. The absdiff component
targets age-based homophily while the by component allows that to be
structured by a binary attribute such as "male", in order to enforce an
offset in the average difference. This allows, for example, a average age
difference in partnerships, but with males (on average) older than females.
This function defines and initializes the absdiffnodemix ERGM term that allows for targeting homophily based on a non-binary attribute (e.g., age) by combinations of a binary attribute (e.g., race).
InitErgmTerm.absdiffnodemix(nw, arglist, ...)InitErgmTerm.absdiffnodemix(nw, arglist, ...)
nw |
An object of class |
arglist |
A list of arguments as specified in the |
... |
Additional data passed into the function as specified in the
|
This ERGM user term was written to allow for age-based homophily in
partnership formation that is heterogeneous by race. The absdiff
component targets the distribution of age mixing on that continuous
variable, and the nodemix component differentiates this for
black-black, black-white, and white-white couples.
This function defines and initializes the fuzzynodematch ERGM term that allows for generalized homophily.
InitErgmTerm.fuzzynodematch(nw, arglist, ...)InitErgmTerm.fuzzynodematch(nw, arglist, ...)
nw |
An object of class |
arglist |
A list of arguments as specified in the |
... |
Additional data passed into the function as specified in the
|
This ERGM user term was written to allow for generalized homophily.The
attr term argument should specify a character vertex attribute
encoding the "venues" associated to each node. The split argument
should specify a string that separates different "venues" in the attribute
value for each node, as handled by strsplit with fixed = TRUE.
For example, if split is "|" (the default), and the attribute
value for a given node is "a12|b476", then the associated venues for
this node are "a12" and "b476". The empty string "" is
interpreted as "no venues".
If the binary term argument is FALSE (the default), the change
statistic for an on-toggle is the number of unique venues associated to both
nodes (informally speaking, this could be described as the number of venues
on which the two nodes "match"); if binary is TRUE, the change
statistic for an on-toggle is 1 if any venue is associated to both
nodes, and 0 otherwise.
Are These Nodes Active (Positional IDs)
is_active_posit_ids(dat, posit_ids)is_active_posit_ids(dat, posit_ids)
dat |
Main |
posit_ids |
A vector of node positional identifiers. |
A logical vector with TRUE if the node is still active and FALSE otherwise.
Are These Nodes Active (Unique IDs)
is_active_unique_ids(dat, unique_ids)is_active_unique_ids(dat, unique_ids)
dat |
Main |
unique_ids |
A vector of node unique identifiers. |
A logical vector with TRUE if the node is still active and FALSE otherwise.
Extracts the matrix of transmission data for each transmission event that occurred within a network epidemic model.
is.transmat(x) get_transmat(x, sim = 1, deduplicate = TRUE)is.transmat(x) get_transmat(x, sim = 1, deduplicate = TRUE)
x |
An |
sim |
Simulation number of extracted network. |
deduplicate |
If |
A data frame with the following standard columns:
at: the time step at which the transmission occurred.
sus: the ID number of the susceptible (newly infected) node.
inf: the ID number of the infecting node.
infDur: the duration of the infecting node's disease at the time of the transmission.
transProb: the probability of transmission per act.
actRate: the rate of acts per unit time.
finalProb: the final transmission probability for the transmission event.
A simulation without transmissions gives a data frame with no rows and the
columns of the other simulations in x, or, if none of them has a
transmission either, the columns at, sus, and inf.
## Simulate SI epidemic on two-group Bernoulli random graph nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod <- netsim(est, param, init, control) ## Extract the transmission matrix from simulation 2 get_transmat(mod, sim = 2)## Simulate SI epidemic on two-group Bernoulli random graph nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod <- netsim(est, param, init, control) ## Extract the transmission matrix from simulation 2 get_transmat(mod, sim = 2)
Reconstructs a networkDynamic object from a completed netsim
simulation, using the cumulative edgelist for edge spells and the
tracked attribute history for vertex activity and time-varying
attributes. The resulting object can be used with ndtv for
visualization or with tsna for temporal network analysis.
make_networkDynamic(sim, sim_num = 1, network = NULL)make_networkDynamic(sim, sim_num = 1, network = NULL)
sim |
An |
sim_num |
The simulation number to use (default 1). |
network |
Optional network number to filter edges. If |
The simulation must be run with cumulative.edgelist = TRUE,
save.cumulative.edgelist = TRUE, and truncate.el.cuml = Inf in
control.net, so that the cumulative edgelist holds every edge, and with
at least one attribute in tracked.attributes or tracked.attributes.once,
so that the activity of the nodes is recorded. The vertex ids of the
networkDynamic object are the unique_ids of the nodes. Each pair of
nodes tied on a layer has one edge, with one activity spell per period the
tie was active, and the layer in the network edge attribute. With
network = NULL and more than one layer, the layers are merged into one
network that allows multiple edges (multiple = TRUE), so that a pair of
nodes tied on two layers has one edge per layer.
The nodes are active from the first record of the attribute history: for a
new simulation from time 0, as in the networkDynamic objects that
netsim() saves without tergmLite, and for a restarted one from
start - 1, the snapshot its history starts from. An edge that formed
before the activity spell of one of its nodes starts is active from the
start of that spell, so that no edge is active between inactive vertices.
A networkDynamic object with active vertex spells and
time-varying vertex attributes.
get_attr_at(), get_attr_history()
nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) control <- control.net(type = "SI", nsteps = 20, nsims = 1, tergmLite = TRUE, resimulate.network = TRUE, cumulative.edgelist = TRUE, save.cumulative.edgelist = TRUE, truncate.el.cuml = Inf, tracked.attributes = "status", verbose = FALSE) sim <- netsim(est, param.net(inf.prob = 0.3, act.rate = 1), init.net(i.num = 10), control) # The full network history of a tergmLite run, with each node's status nd <- make_networkDynamic(sim) nd x10 <- network.collapse(nd, at = 10) table(get_vertex_attribute(x10, "status"))nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) control <- control.net(type = "SI", nsteps = 20, nsims = 1, tergmLite = TRUE, resimulate.network = TRUE, cumulative.edgelist = TRUE, save.cumulative.edgelist = TRUE, truncate.el.cuml = Inf, tracked.attributes = "status", verbose = FALSE) sim <- netsim(est, param.net(inf.prob = 0.3, act.rate = 1), init.net(i.num = 10), control) # The full network history of a tergmLite run, with each node's status nd <- make_networkDynamic(sim) nd x10 <- network.collapse(nd, at = 10) table(get_vertex_attribute(x10, "status"))
netsim Object with tergmLiteExtract the elements required for re-initializing a netsim simulation from
a completed simulation. This function also resets the Unique IDs and Time
values to reduce the size of the simulation. This function only works for
simulations run with tergmLite = TRUE and save.run = TRUE in
control.net().
make_restart_point(sim_obj, time_attrs, sim_num = 1, keep_steps = 1)make_restart_point(sim_obj, time_attrs, sim_num = 1, keep_steps = 1)
sim_obj |
a |
time_attrs |
a |
sim_num |
the number of the simulation to extract from the |
keep_steps |
The number of simulation steps to keep from the previous run. By default only keep one but more is possible if some back-history is wanted. |
The restart point created always contains a single simulation and drops the
attr.history and the raw.records from the initial simulation.
sim_obj does not need to hold the parameters: when restarting, netsim()
takes them from its param argument alone, which must hold all the
parameters of the model.
The epi trackers, cumulative edgelists, transmission matrix and nwstats are
truncated to only contain the last keep_steps entries. The unique IDs in
the transmission matrix are re-based like the ones of the attributes.
Warning: the time_attrs argument is mandatory. Almost all extension models
have such attributes (e.g. the time of HIV diagnosis). If no such attribute
exists beyond the core ones, passing c() will allow the function to run
while ensuring that this was done on purpose. An attribute holding a time
step that is not offset puts the events it records in the future of the
restarted simulation: for example, a duration of infection computed from an
infTime that was not offset would be negative.
A dynamic netcensus() layer reads the observed network on the simulation
clock, which this function re-bases, so it stops on such a layer. Restart
those simulations from the netsim object itself, selecting a simulation
with get_sims().
When restarting from the output of this function, it is suggested to express
the time steps in a relative manner in control.net:
control.net( start = restart_point$control$nsteps + 1, nsteps = restart_point$control$nsteps + 1 + 104 )
a trimmed netsim object with only one simulation that is ready to
be used as a restart point.
nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 20), verbose = FALSE) param <- param.net(inf.prob = 0.3, act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 20, nsims = 2, tergmLite = TRUE, resimulate.network = TRUE, save.run = TRUE, verbose = FALSE) sim <- netsim(est, param, init, control) # Make a restart point from simulation 2. The built-in SI model has no time # attribute beyond the core ones, which are offset by default. x <- make_restart_point(sim, time_attrs = c(), sim_num = 2) # Run it for 10 more time steps control <- control.net(type = "SI", start = x$control$nsteps + 1, nsteps = x$control$nsteps + 10, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE) sim2 <- netsim(x, param, init, control)nw <- network_initialize(n = 100) est <- netest(nw, formation = ~edges, target.stats = 50, coef.diss = dissolution_coefs(~offset(edges), 20), verbose = FALSE) param <- param.net(inf.prob = 0.3, act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 20, nsims = 2, tergmLite = TRUE, resimulate.network = TRUE, save.run = TRUE, verbose = FALSE) sim <- netsim(est, param, init, control) # Make a restart point from simulation 2. The built-in SI model has no time # attribute beyond the core ones, which are offset by default. x <- make_restart_point(sim, time_attrs = c(), sim_num = 2) # Run it for 10 more time steps control <- control.net(type = "SI", start = x$control$nsteps + 1, nsteps = x$control$nsteps + 10, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE) sim2 <- netsim(x, param, init, control)
Merges epidemiological data from two independent simulations of
stochastic individual contact models from icm().
## S3 method for class 'icm' merge(x, y, ...)## S3 method for class 'icm' merge(x, y, ...)
x |
An |
y |
Another |
... |
Additional merge arguments (not used). |
This merge function combines the results of two independent simulations of
icm() class models, simulated under separate function calls. The
model parameterization between the two calls must be exactly the same, except
for the number of simulations in each call. This allows for manual
parallelization of model simulations.
This merge function does not work the same as the default merge, which allows for a combined object where the structure differs between the input elements. Instead, the function checks that objects are identical in model parameterization in every respect (except number of simulations) and binds the results.
An EpiModel object of class icm() containing the
data from both x and y.
param <- param.icm(inf.prob = 0.2, act.rate = 0.8) init <- init.icm(s.num = 1000, i.num = 100) control <- control.icm( type = "SI", nsteps = 10, nsims = 3, verbose = FALSE ) x <- icm(param, init, control) control <- control.icm( type = "SI", nsteps = 10, nsims = 1, verbose = FALSE ) y <- icm(param, init, control) z <- merge(x, y) # Examine separate and merged data as.data.frame(x) as.data.frame(y) as.data.frame(z)param <- param.icm(inf.prob = 0.2, act.rate = 0.8) init <- init.icm(s.num = 1000, i.num = 100) control <- control.icm( type = "SI", nsteps = 10, nsims = 3, verbose = FALSE ) x <- icm(param, init, control) control <- control.icm( type = "SI", nsteps = 10, nsims = 1, verbose = FALSE ) y <- icm(param, init, control) z <- merge(x, y) # Examine separate and merged data as.data.frame(x) as.data.frame(y) as.data.frame(z)
Merges epidemiological data from two independent simulations of
stochastic network models from netsim.
## S3 method for class 'netsim' merge( x, y, keep.transmat = TRUE, keep.network = TRUE, keep.nwstats = TRUE, keep.other = TRUE, param.error = TRUE, keep.diss.stats = TRUE, keep.run = TRUE, keep.cumulative.edgelist = FALSE, keep.attr.history = TRUE, keep.raw.records = TRUE, ... )## S3 method for class 'netsim' merge( x, y, keep.transmat = TRUE, keep.network = TRUE, keep.nwstats = TRUE, keep.other = TRUE, param.error = TRUE, keep.diss.stats = TRUE, keep.run = TRUE, keep.cumulative.edgelist = FALSE, keep.attr.history = TRUE, keep.raw.records = TRUE, ... )
x |
An |
y |
Another |
keep.transmat |
If |
keep.network |
If |
keep.nwstats |
If |
keep.other |
If |
param.error |
If |
keep.diss.stats |
If |
keep.run |
If |
keep.cumulative.edgelist |
If |
keep.attr.history |
If |
keep.raw.records |
If |
... |
Additional merge arguments (not currently used). |
This merge function combines the results of two independent simulations of
netsim() class models, simulated under separate function calls.
The model parameterization between the two calls must be exactly the same,
except for the number of simulations in each call and the execution
settings listed under param.error. This allows for manual
parallelization of model simulations.
This merge function does not work the same as the default merge, which allows for a combined object where the structure differs between the input elements. Instead, the function checks that objects are identical in model parameterization in every respect (except number of simulations) and binds the results.
After dropping the elements not kept (see the keep.* arguments), x and
y must hold the same elements.
An EpiModel object of class netsim() containing
the data from both x and y.
# Network model nw <- network_initialize(n = 100) coef.diss <- dissolution_coefs(dissolution = ~ offset(edges), duration = 10) est <- netest(nw, formation = ~edges, target.stats = 25, coef.diss = coef.diss, verbose = FALSE ) # Epidemic models param <- param.net(inf.prob = 1) init <- init.net(i.num = 1) control <- control.net( type = "SI", nsteps = 20, nsims = 2, save.nwstats = TRUE, nwstats.formula = ~ edges + degree(0), verbose = FALSE ) x <- netsim(est, param, init, control) y <- netsim(est, param, init, control) # Merging z <- merge(x, y) # Examine separate and merged data as.data.frame(x) as.data.frame(y) as.data.frame(z)# Network model nw <- network_initialize(n = 100) coef.diss <- dissolution_coefs(dissolution = ~ offset(edges), duration = 10) est <- netest(nw, formation = ~edges, target.stats = 25, coef.diss = coef.diss, verbose = FALSE ) # Epidemic models param <- param.net(inf.prob = 1) init <- init.net(i.num = 1) control <- control.net( type = "SI", nsteps = 20, nsims = 2, save.nwstats = TRUE, nwstats.formula = ~ edges + degree(0), verbose = FALSE ) x <- netsim(est, param, init, control) y <- netsim(est, param, init, control) # Merging z <- merge(x, y) # Examine separate and merged data as.data.frame(x) as.data.frame(y) as.data.frame(z)
Stochastic individual contact models of infectious disease simulate epidemics in which contacts between individuals are instantaneous events in discrete time. They are intended to be the stochastic microsimulation analogs to deterministic compartmental models.
The icm() function handles both the simulation tasks. Within this
function are a series of modules that initialize the simulation and then
simulate new infections, recoveries, and vital dynamics at each time step. A
module also handles the basic bookkeeping calculations for disease
prevalence.
This help page presents a brief overview of the built-in module functions
in the order in which they are used within icm(). ICMs support only the
built-in SI, SIR, and SIS disease types. For custom or extension epidemic
models, use the network model class via netsim() and control.net()
instead.
This function sets up agent attributes, like disease status, on the network
at the starting time step of disease simulation, . For
multiple-simulation function calls, these are reset at the beginning of each
simulation.
initialize.icm(): sets which agents are initially
infected, through the initial conditions passed in
init.icm().
The main disease simulation occurs at each time step given the current state of the population at that step. Infection of agents is simulated as a function of disease parameters and population composition. Recovery of agents is likewise simulated with respect to infected nodes. These functions also analyze the flows for summary measures such as disease incidence.
infection.icm(): randomly draws an edgelist given the
parameters, subsets the list for discordant pairs, and simulates
transmission on those discordant pairs through a series of draws from
a binomial distribution.
recovery.icm(): simulates recovery from infection either
to a lifelong immune state (for SIR models) or back to the susceptible
state (for SIS models), as a function of the recovery rate specified
in the rec.rate parameter. The recovery rate may vary for
two-group models.
Vital dynamics such as arrival and departure processes are simulated at each time step to update entries into and exits from the population. These are used in open-population ICMs.
departures.icm(): randomly simulates departures or exits
for agents given the departure rate specified in the disease-state and
group-specific departure parameters in param.icm(). This
involves deactivating agents from the population, but their historical
data is preserved in the simulation.
arrivals.icm(): randomly simulates new arrivals into the
population given the current population size and the arrival rate
parameters. This involves adding new agents into the population.
Simulations require bookkeeping at each time step to calculate the summary epidemiological statistics used in the model output analysis.
prevalence.icm(): calculates the number in each disease
state (susceptible, infected, recovered) at each time step for those
active agents in the population.
Stochastic network models of infectious disease in EpiModel require
statistical modeling of networks, simulation of those networks forward
through time, and simulation of epidemic dynamics on top of those evolving
networks. The netsim() function handles both the network and
epidemic simulation tasks. Within this function are a series of modules that
initialize the simulation and then simulate new infections, recoveries, and
demographics on the network. Modules also handle the resimulation of the
network and some bookkeeping calculations for disease prevalence.
Writing original network models that expand upon our "base" model set will
require modifying the existing modules or adding new modules to the workflow
in netsim(). The existing modules may be used as a template for
replacement or new modules.
This help page provides an orientation to these module functions, in the
order in which they are used within netsim(), to help guide users
in writing their own functions. These module functions are not shown
on the help index since they are not called directly by the end-user. To
understand these functions in more detail, review the separate help pages
listed below.
This function sets up nodal attributes, like disease status, on the network
at the starting time step of disease simulation, . For
multiple-simulation function calls, these are reset at the beginning of each
individual simulation.
initialize.net(): sets up the main netsim_dat data
structure used in the simulation, initializes which nodes are infected
(via the initial conditions passed in init.net()), and
simulates a first time step of the networks given the network model
fit from netest().
The main disease simulation occurs at each time step given the current state of the network at that step. Infection of nodes is simulated as a function of attributes of the nodes and the edges. Recovery of nodes is likewise simulated as a function of nodal attributes of those infected nodes. These functions also calculate summary flow measures such as disease incidence.
infection.net(): simulates disease transmission given an
edgelist of discordant partnerships by calculating the relevant
transmission and act rates for each edge, and then updating the nodal
attributes and summary statistics.
recovery.net(): simulates recovery from infection either
to a lifelong immune state (for SIR models) or back to the susceptible
state (for SIS models), as a function of the recovery rate parameters
specified in param.net().
Demographics such as arrival and departure processes are simulated at each time step to update entries into and exits from the network. These are used in epidemic models with network feedback, in which the network is resimulated at each time step to account for the nodal changes affecting the edges.
departures.net(): randomly simulates departure for nodes
given their disease status (susceptible, infected, recovered), and
their group-specific departure rates specified in
param.net(). Departures involve deactivating nodes.
arrivals.net(): randomly simulates new arrivals into the
network given the current population size and the arrival rate
specified in the a.rate parameters. This involves adding new
nodes into the network.
In dependent network models, the network object is resimulated at each time step to account for changes in the size of the network (changed through entries and exits), and the disease status of the nodes.
resim_nets(): resimulates the network object one time step
forward given the set of formation and dissolution coefficients
estimated in netest().
Network simulations require bookkeeping at each time step to calculate the summary epidemiological statistics used in the model output analysis.
prevalence.net(): calculates the number in each disease
state (susceptible, infected, recovered) at each time step for those
active nodes in the network. If the epi.by control is used, it
calculates these statistics by a set of specified nodal attributes.
verbose.net(): summarizes the current state of the
simulation and prints this to the console.
If epidemic type is supplied within control.net(),
EpiModel defaults each of the base epidemic and demographic modules described
above (arrivals.FUN, departures.FUN, infection.FUN, recovery.FUN) to the
correct .net function based on variables passed to param.net()
(e.g. num.g2, denoting population size of group two, would select the
two-group variants of the aforementioned modules). Two-group modules are
denoted by a .2g affix (e.g., recovery.2g.net)
Changes the group of existing nodes during a simulation and
rewires a netclique() layer to match: each moved node loses
its edges to the members of its old group and is connected to
every active member of its new group. Custom modules use it to
represent people changing groups, such as a young adult leaving
home, a couple forming a household, or a child moving in with
relatives.
move_to_group(dat, ids, group, network = NULL)move_to_group(dat, ids, group, network = NULL)
dat |
Main |
ids |
Positional ids of the nodes to move. Every node must be active. |
group |
New group ids: one per element of |
network |
Index of the clique layer in the list of layers passed to
|
The clique edges are built from the grouping attribute once, when the
simulation starts, and are afterwards changed only by arrivals, departures,
and this function. Setting the grouping attribute with set_attr() alone
therefore does not rewire the layer: the old edges remain and the layer no
longer matches the groups. move_to_group() sets the attribute and the
edges together, in either network storage mode (tergmLite = TRUE or
FALSE), so that the layer stays exactly the union of the cliques of the
current groups.
Nodes that arrive in a time step join the layer when nwupdate.net()
runs, which places them by the layer's arrival rule (see netclique()), so
they cannot be moved before then. To place arriving nodes in chosen groups,
set the grouping attribute in the arrivals module and use
arrivals = "join" with an arrivals.FUN that returns that attribute for
the new nodes.
A node moved to its own current group keeps its edges. When the moves leave
a group without members, the group ceases to exist, as when its last member
departs. For numeric group ids, one more than the largest id in use,
max(get_attr(dat, group.attr), na.rm = TRUE) + 1, is an unused id; ids of
groups whose members have all departed are also unused, so reusing one
starts a new group. The ids set here count toward the running maximum from
which the "new" arrival rule of netclique() draws, so a later arrival
is never given the id of a group formed by a move.
Under tergmLite = TRUE with tergmLite.track.duration = TRUE, the moved
nodes' new edges are recorded as formed at the current time step. In the
cumulative edgelist (see control.net()), a move ends the node's old
edges and starts new ones.
The updated netsim_dat object.
netclique() for the clique layer and its rules for placing
arriving nodes.
# A module in which people aged 18 to 29 leave home with a probability of # 0.05 per time step, each starting a household of their own leave_home <- function(dat, at) { active <- get_attr(dat, "active") age <- get_attr(dat, "age") hh_id <- get_attr(dat, "hh_id") elig <- which(active == 1 & age >= 18 & age < 30) movers <- elig[runif(length(elig)) < 0.05] if (length(movers) > 0) { new_ids <- max(hh_id, na.rm = TRUE) + seq_along(movers) dat <- move_to_group(dat, ids = movers, group = new_ids) } return(dat) } # 50 households of 4 under a community layer set.seed(12) nw <- network_initialize(n = 200) nw <- set_vertex_attribute(nw, "age", sample(0:79, 200, replace = TRUE)) nw <- set_vertex_attribute(nw, "hh_id", rep(1:50, each = 4)) hh <- netclique(nw, group.attr = "hh_id") est <- netest(nw, formation = ~edges, target.stats = 100, coef.diss = dissolution_coefs(~offset(edges), 20), verbose = FALSE) param <- param.net(inf.prob = multilayer(0.2, 0.05), act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = NULL, nsteps = 20, nsims = 1, infection.FUN = infection.net, leave_home.FUN = leave_home, tergmLite = TRUE, resimulate.network = TRUE, save.run = TRUE, verbose = FALSE) sim <- netsim(list(hh, est), param, init, control) # More households at the end than at the start length(unique(sim$run[[1]]$attr$hh_id))# A module in which people aged 18 to 29 leave home with a probability of # 0.05 per time step, each starting a household of their own leave_home <- function(dat, at) { active <- get_attr(dat, "active") age <- get_attr(dat, "age") hh_id <- get_attr(dat, "hh_id") elig <- which(active == 1 & age >= 18 & age < 30) movers <- elig[runif(length(elig)) < 0.05] if (length(movers) > 0) { new_ids <- max(hh_id, na.rm = TRUE) + seq_along(movers) dat <- move_to_group(dat, ids = movers, group = new_ids) } return(dat) } # 50 households of 4 under a community layer set.seed(12) nw <- network_initialize(n = 200) nw <- set_vertex_attribute(nw, "age", sample(0:79, 200, replace = TRUE)) nw <- set_vertex_attribute(nw, "hh_id", rep(1:50, each = 4)) hh <- netclique(nw, group.attr = "hh_id") est <- netest(nw, formation = ~edges, target.stats = 100, coef.diss = dissolution_coefs(~offset(edges), 20), verbose = FALSE) param <- param.net(inf.prob = multilayer(0.2, 0.05), act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = NULL, nsteps = 20, nsims = 1, infection.FUN = infection.net, leave_home.FUN = leave_home, tergmLite = TRUE, resimulate.network = TRUE, save.run = TRUE, verbose = FALSE) sim <- netsim(list(hh, est), param, init, control) # More households at the end than at the start length(unique(sim$run[[1]]$attr$hh_id))
This utility function allows specification of certain
netsim() controls and parameters to vary by network. The
netsim() control arguments currently supporting
multilayer specifications are nwstats.formula,
set.control.ergm, set.control.tergm, and
tergmLite.track.duration. The param.net() parameters
supporting them are inf.prob, inf.prob.g2, and
act.rate, which the built-in infection modules then apply
per layer.
multilayer(...)multilayer(...)
... |
control arguments or parameter values to apply to each network, with the index of the network corresponding to the index of the argument |
an object of class multilayer containing the specified
control arguments or parameter values
netsim() for passing a list of netest() fits and netclique()
layers, one per network. The
Multi-Layer Networks
chapter of the Network Modeling for Epidemics course materials works
through a two-layer model in full.
# A household layer that transmits more per contact than the community layer param <- param.net(inf.prob = multilayer(0.45, 0.10), act.rate = 1) param# A household layer that transmits more per contact than the community layer param <- param.net(inf.prob = multilayer(0.45, 0.10), act.rate = 1) param
Inspired by dplyr::mutate, mutate_epi adds new
variables to the epidemiological and related variables within
simulated model objects of any class in EpiModel.
mutate_epi(x, ...)mutate_epi(x, ...)
x |
An |
... |
Name-value pairs of expressions (see examples below). |
The updated EpiModel object of class dcm, icm,
or netsim.
# DCM example param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SI", nsteps = 500) mod1 <- dcm(param, init, control) mod1 <- mutate_epi(mod1, prev = i.num/num) plot(mod1, y = "prev") # Network model example nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 1, i.num.g2 = 0) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod1 <- netsim(est1, param, init, control) mod1 # Add the prevalences to the dataset mod1 <- mutate_epi(mod1, i.prev = i.num / num, i.prev.g2 = i.num.g2 / num.g2) plot(mod1, y = c("i.prev", "i.prev.g2"), qnts = 0.5, legend = TRUE) # Add incidence rate per 100 person years (assume time step = 1 week) mod1 <- mutate_epi(mod1, ir100 = 5200*(si.flow + si.flow.g2) / (s.num + s.num.g2)) as.data.frame(mod1) as.data.frame(mod1, out = "mean")# DCM example param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SI", nsteps = 500) mod1 <- dcm(param, init, control) mod1 <- mutate_epi(mod1, prev = i.num/num) plot(mod1, y = "prev") # Network model example nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 1, i.num.g2 = 0) control <- control.net(type = "SI", nsteps = 10, nsims = 3, verbose = FALSE) mod1 <- netsim(est1, param, init, control) mod1 # Add the prevalences to the dataset mod1 <- mutate_epi(mod1, i.prev = i.num / num, i.prev.g2 = i.num.g2 / num.g2) plot(mod1, y = c("i.prev", "i.prev.g2"), qnts = 0.5, legend = TRUE) # Add incidence rate per 100 person years (assume time step = 1 week) mod1 <- mutate_epi(mod1, ir100 = 5200*(si.flow + si.flow.g2) / (s.num + s.num.g2)) as.data.frame(mod1) as.data.frame(mod1, out = "mean")
These get_, set_, append_, and add_
functions allow a safe and efficient way to retrieve and mutate
the main netsim_dat class object of network models
(typical variable name dat). They are intended for use
inside module functions that run during a netsim()
simulation, not for editing the user-facing param.net,
init.net, or control.net inputs before a run or the
output object returned by netsim(). See the Intended
Usage section below for details and alternatives.
The accessors are documented on three pages, by the part of dat they act
on:
Nodal attributes, with one value per node (get_attr()):
get_attr(), get_attr_list(), set_attr(), add_attr(),
append_attr(), append_core_attr(), remove_node_attr(), and
get_core_attributes().
Epidemic outputs, with one value per time step (get_epi()):
get_epi(), get_epi_list(), set_epi(), and add_epi().
Parameters, control settings, and initial conditions
(get_param()): get_param(), get_param_list(), set_param(),
add_param(), the same four functions for control and init, and
get_network_control().
Nodes are referred to by their positional identifiers; see
get_unique_ids() and get_posit_ids() to convert them to and from
their unique identifiers.
These accessors operate on the live netsim_dat object that EpiModel
constructs internally when a simulation starts and passes through each
module at every time step. The expected calling context is inside a
user-supplied module function (e.g., a custom infection.FUN,
recovery.FUN, or arrivals/departures module) registered with
control.net().
They are not a general-purpose tool for editing the user-facing input
or output objects of netsim():
Calling them on a param.net(), init.net(), or control.net()
object before a run will appear to succeed (those objects are also
list-like) but produces an object that is not a valid simulation
input.
Calling them on the object returned by netsim() modifies only the
saved input slot, not anything that would change the result of a
re-run. Note also that netsim() strips the *.FUN entries from
its returned control slot, so feeding that slot back into a new
simulation will fail.
For modifications outside a running simulation, use the following instead:
Editing parameters before a run: update_params() for a
param.net object, or direct list assignment
(e.g., p$inf.prob <- 0.5).
Editing init or control before a run: direct list assignment
(e.g., ctrl$nsteps <- 1000), or rebuild with a fresh call to the
init.net() / control.net() constructor.
Scheduled mid-simulation changes: the .param.updater.list
argument to param.net() and the .control.updater.list argument
to control.net(). See the "model-parameters" vignette for the
underlying updater module and the scenario API built on top of it.
The set_, append_, and add_ functions DO NOT modify the
netsim_dat object in place. The result must be assigned back to
dat in order to be registered: dat <- set_*(dat, item, value).
set_ and append_ vs add_
The set_ and append_ functions edit a pre-existing element or
create a new one if it does not exist already by calling the add_
functions internally.
update_params() for editing a param.net object outside a
simulation; param.net(), init.net(), control.net() for input
constructors; netsim() for running a simulation.
netest(), netdx(), and control.net() pass control
settings to the ergm and tergm packages, which estimate and
simulate the network model, through their set.control.ergm,
set.control.tergm, and set.control.ergm.ego arguments. This
page lists the control function that each argument takes, the
defaults that EpiModel sets, how to use netdx() to find the
stage that needs adjusting, and the settings most often changed.
The worked examples are in the Improving Model Estimation and Simulation appendix of the Network Modeling for Epidemics course materials, which covers full STERGM estimation for short partnership durations, the estimation settings for large and slow ERGM fits, and the simulation settings for diagnostics and epidemic models.
Each argument takes an object built by a specific control function. Passing an object from another one stops with an error that names the right function.
Estimation in netest():
set.control.ergm takes ergm::control.ergm(), for the ERGM fit with
the edges dissolution approximation (edapprox = TRUE).
set.control.ergm.ego takes ergm.ego::control.ergm.ego(), for the
same fit when nw is an egor object.
set.control.tergm takes tergm::control.tergm(), for the full STERGM
fit (edapprox = FALSE).
Simulation in netdx() and control.net():
set.control.ergm takes ergm::control.simulate.formula(), for the
cross-sectional network that the dynamic simulation starts from, and
for the static diagnostics of netdx(dynamic = FALSE). It is used only
for fits with edapprox = TRUE; a full STERGM fit starts from the
network saved by netest().
set.control.tergm takes tergm::control.simulate.formula.tergm(),
for each time step of the dynamic network simulation, both in the
diagnostics and in the epidemic model.
In a model with several network layers, control.net() takes one control
object per layer through multilayer().
Three defaults differ from those of the control functions themselves:
set.control.tergm in netest() is
control.tergm(MCMC.maxchanges = .Machine$integer.max).
set.control.tergm in netdx() and control.net() is
control.simulate.formula.tergm(MCMC.maxchanges = .Machine$integer.max).
This raises the number of network changes that tergm can record in one
simulation above its default limit of 1e6, which a long netdx() run
can exceed.
set.control.ergm in control.net() is
control.simulate.formula(MCMC.burnin = 2e5), a longer burn-in for the
starting network than the ergm default.
A control object passed to one of these arguments replaces the default as a whole, not only the settings it names, so restate these settings alongside any others (see the examples).
An error or a stalled fit in netest() calls for the estimation settings
below. When the fit succeeds but the dynamic diagnostics of netdx() miss
the formation targets, the cause can lie in the simulation, in the edges
dissolution approximation, or in the cross-sectional fit:
The per-step burn-in of the simulation. By default, tergm sets
the number of proposals in each time step adaptively. With short
partnership durations it can end a time step before the network has
replaced the partnerships that dissolved, so statistics such as the edge
count settle below their targets. This applies to fits with and without
the approximation. Setting MCMC.burnin.min and MCMC.burnin.max in
set.control.tergm to the same value (such as 1e4) fixes the number of
proposals per time step and is quick to try.
The edges dissolution approximation. For fits with
edapprox = TRUE, run static diagnostics with netdx(dynamic = FALSE).
If they are on target but the dynamic diagnostics remain off with a
fixed per-step burn-in, the approximation is the likely cause. It loses
accuracy when many partnerships form and dissolve at each time step,
that is, when durations are short or density is high. Fit the full
STERGM with edapprox = FALSE, or redefine the time step as a shorter
unit so that durations span more time steps, rescaling every other
time-based parameter of the model to match.
The cross-sectional fit. If the static diagnostics are also off, the
ERGM fit has not reached the targets, or the static simulation has not
moved far enough from its starting network. On a large network, raise
MCMC.burnin and MCMC.interval in the set.control.ergm of netdx()
before changing the estimation settings of netest().
Read the Pct Diff column of print.netdx() alongside the Z Score. The
standard error behind the Z score shrinks with the effective sample size, so
many static draws can make a difference of a fraction of a percent
statistically significant, while the autocorrelation between time steps
keeps the effective sample size of a dynamic simulation, and so its Z
scores, smaller.
The simulation settings that bring the netdx() diagnostics on target
belong in control.net() as well: the epidemic simulation steps the network
forward with the same tergm simulation, so without them it runs on the
network that the diagnostics flagged.
The control functions have many arguments, of which a few account for most adjustments in practice. Their help pages document the rest.
For the ERGM fit, in ergm::control.ergm():
MCMLE.maxit: the maximum number of MCMLE iterations. Raise it for a fit
that is still moving toward the targets when it stops.
MCMC.samplesize, MCMC.interval, and MCMC.burnin: the size,
spacing, and burn-in of the MCMC sample drawn at each iteration. Larger
networks generally need a longer interval and burn-in. By default ergm
extends the sample until it reaches the effective size set by
MCMLE.effectiveSize; setting MCMLE.effectiveSize = NULL holds it at
MCMC.samplesize draws, which bounds the time per iteration.
SAN.nsteps.times and SAN.maxit: simulated annealing (SAN) builds the
starting network that matches the target statistics. SAN.nsteps.times
scales the total number of SAN proposals, and SAN.maxit divides them
into that many runs. Raise SAN.nsteps.times when SAN does not reach the
targets.
MCMC.prop: hints for the MCMC proposal (see ergm::ergmHint). When
most ties fall within a few cells of a mixing matrix, a stratified
proposal such as ~strat(attr = ~age.grp) + sparse stops the sampler
from spending its proposals on cells that hold few or no ties. Listing
any hint replaces the default ones, so list sparse as well.
MCMC.maxedges: the maximum number of edges in a sampled network,
unlimited by default. A finite value makes a fit that wanders into dense,
degenerate networks stop with an error rather than run for hours.
MCMLE.steplength with MCMLE.steplength.margin = NULL: a fixed step
length below 1 (such as 0.5) keeps the first iterations of a hard fit
from overshooting. With the default margin, MCMLE.steplength is only
the maximum step length.
parallel: the number of cores across which the MCMC sample is drawn.
For the full STERGM fit, in tergm::control.tergm():
EGMME.MCMC.burnin.min and EGMME.MCMC.burnin.max: the number of
proposals per time step during estimation, set adaptively by default.
Setting both to the same value fixes it, which can stabilize a fit that
otherwise fails. In the course examples, 1e4 works for a network of
1,000 nodes, and larger networks may need a value on the order of the
network size. Fix the per-step burn-in of the simulation to the same
value.
SAN.nsteps.times, SAN.maxit, and MCMC.prop act as in
ergm::control.ergm().
For the dynamic simulation, in tergm::control.simulate.formula.tergm():
MCMC.burnin.min and MCMC.burnin.max: the number of proposals per
time step. Setting both to the same value fixes it, as described above.
tergm has no MCMC.interval; this pair takes its place.
MCMC.maxchanges: restate .Machine$integer.max when passing any other
setting.
MCMC.prop: the default, ~discord + sparse, proposes a share of its
toggles (set by MCMC.prop.args = list(discordance_fraction = ), 0.5 by
default) on dyads that have already changed within the time step. For
strongly structured mixing, add a strat() hint as in estimation and
keep discord and sparse in the formula.
For the cross-sectional simulation, in ergm::control.simulate.formula():
MCMC.burnin and MCMC.interval: the burn-in before the starting
network (or the first static draw) and the spacing between static draws.
Krivitsky PN, Hunter DR, Morris M, Klumb C. ergm 4: New Features for Analyzing Exponential-Family Random Graph Models. Journal of Statistical Software. 2023; 105(6): 1-44. doi:10.18637/jss.v105.i06.
Krivitsky PN, Handcock MS. A Separable Model for Dynamic Networks. Journal of the Royal Statistical Society, Series B. 2014; 76(1): 29-46.
netest(), netdx(), and control.net(), whose arguments these
settings are passed through; print.netdx() and plot.netdx() for
reading the diagnostics.
nw <- network_initialize(n = 100) formation <- ~edges + concurrent target.stats <- c(50, 20) coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 10) est <- netest(nw, formation, target.stats, coef.diss) # Fix the number of proposals per time step in the dynamic simulation, # restating the MCMC.maxchanges default that EpiModel sets sim.control <- control.simulate.formula.tergm( MCMC.burnin.min = 1e4, MCMC.burnin.max = 1e4, MCMC.maxchanges = .Machine$integer.max ) dx <- netdx(est, nsims = 2, nsteps = 100, set.control.tergm = sim.control, verbose = FALSE) dx # Pass the same settings to the epidemic simulation param <- param.net(inf.prob = 0.3, act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsims = 1, nsteps = 50, set.control.tergm = sim.control, verbose = FALSE) sim <- netsim(est, param, init, control) ## Not run: # Estimation settings for a larger or slower ERGM fit est <- netest(nw, formation, target.stats, coef.diss, set.control.ergm = control.ergm(MCMLE.maxit = 500, MCMC.samplesize = 1e4, MCMC.interval = 5e3, SAN.nsteps.times = 16, parallel = 4)) # Full STERGM fit with a fixed number of proposals per time step est <- netest(nw, formation, target.stats, coef.diss, edapprox = FALSE, set.control.tergm = control.tergm( EGMME.MCMC.burnin.min = 1e4, EGMME.MCMC.burnin.max = 1e4, MCMC.maxchanges = .Machine$integer.max )) dx <- netdx(est, nsims = 5, nsteps = 500, set.control.tergm = sim.control) ## End(Not run)nw <- network_initialize(n = 100) formation <- ~edges + concurrent target.stats <- c(50, 20) coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 10) est <- netest(nw, formation, target.stats, coef.diss) # Fix the number of proposals per time step in the dynamic simulation, # restating the MCMC.maxchanges default that EpiModel sets sim.control <- control.simulate.formula.tergm( MCMC.burnin.min = 1e4, MCMC.burnin.max = 1e4, MCMC.maxchanges = .Machine$integer.max ) dx <- netdx(est, nsims = 2, nsteps = 100, set.control.tergm = sim.control, verbose = FALSE) dx # Pass the same settings to the epidemic simulation param <- param.net(inf.prob = 0.3, act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsims = 1, nsteps = 50, set.control.tergm = sim.control, verbose = FALSE) sim <- netsim(est, param, init, control) ## Not run: # Estimation settings for a larger or slower ERGM fit est <- netest(nw, formation, target.stats, coef.diss, set.control.ergm = control.ergm(MCMLE.maxit = 500, MCMC.samplesize = 1e4, MCMC.interval = 5e3, SAN.nsteps.times = 16, parallel = 4)) # Full STERGM fit with a fixed number of proposals per time step est <- netest(nw, formation, target.stats, coef.diss, edapprox = FALSE, set.control.tergm = control.tergm( EGMME.MCMC.burnin.min = 1e4, EGMME.MCMC.burnin.max = 1e4, MCMC.maxchanges = .Machine$integer.max )) dx <- netdx(est, nsims = 5, nsteps = 500, set.control.tergm = sim.control) ## End(Not run)
Wraps a fully observed contact network, either a static
network or a networkDynamic with edge spells, as a layer
that netsim() accepts anywhere in its layer list alongside
the layers estimated with netest(). The simulation reads the
edges active at each time step from the observed object; there
is no formation model, no dissolution model, and no
resimulation. It is an addition to netest for the case in
which the whole network has been observed, not a substitute
for estimation from a sample (see Details).
netcensus(nw, window = NULL)netcensus(nw, window = NULL)
nw |
An object of class |
window |
Observation window of a dynamic census, as |
netest() exists to turn partial, usually egocentric, network data into a
generative model that netsim can simulate from. That is the general
workflow, because samples are the norm and the fit is what lets a sample
stand in for a population. When the whole network has been observed, for
every node and every contact and, for a dynamic census, over every time
step, there is nothing to estimate: the observed object is what netsim
would otherwise have to generate. netcensus places it in the layer list
directly. Sensor, proximity-logger, contact-tracing, and animal-tracking
datasets are the usual sources. It is the wrong tool for a sample from
which one wants to generalize, and it is not a way to model how the
observed ties arise; a network whose ties are to be reproduced from their
predictors is estimated with netest, whatever their turnover.
For a networkDynamic census, EpiModel time step at reads the edges
active at time at of the observed object, so the simulation clock is the
observation clock. A census recorded in other units, such as seconds or
calendar dates, needs its spell times rescaled to time steps first. Match
the time steps of control.net() to the observation window. Past its end,
the layer holds only the edges whose spells extend beyond it: spells
censored at the end of the observation (terminus Inf, as in tergm and
EpiModel output) stay active, and spells that end with the observation, as
in most contact data, leave the layer empty. netsim() warns when the
simulation ends before the window begins or nsteps reaches its end. Vertex
activity spells are not used; every node is present throughout.
The layer reads the observed object on the simulation clock, so a
simulation with a dynamic census layer is restarted from the netsim
object itself (selecting a simulation with get_sims()) rather than from
make_restart_point(), which re-bases the time steps and stops on such a
layer.
A census has a fixed node set, so vital dynamics are refused: netsim()
stops when the model has arrivals or departures and a netcensus layer,
and arrive_nodes() and depart_nodes() stop if a custom module tries to
add or remove nodes. Duration tracking under tergmLite is also refused
for a dynamic census, whose observed spells already carry the durations.
The layer is skipped by the network resimulation and the edges correction,
and the built-in infection modules read it through discord_edgelist()
like any other layer, so per-layer inf.prob and act.rate may be given
with multilayer() in param.net(). Under tergmLite, the active
edgelist is extracted from the observed object at every time step; without
tergmLite, the networkDynamic object is used as stored. Network
statistics are recorded through nwstats.formula in control.net(), with
the default "formation" meaning ~edges. netdx() refuses a netcensus
object, since there is no model to diagnose; print summarizes the
observed edges over the window.
An object of class netcensus, a list with elements:
newnetwork: the observed network, with temporally extended vertex attributes removed.
dynamic: TRUE for a networkDynamic census, FALSE for a static
one.
window: the observation window of a dynamic census, or NULL.
edapprox: FALSE.
summary: a list with the node count, the vertex attribute names, and either the edge count, mean degree, and number of isolates (static) or the number of distinct edges ever observed, the first and last time steps in the window, and the number of edges active at each of those steps, or at 1000 evenly spaced steps for longer windows (dynamic).
netclique() for a layer of cliques defined by a grouping
attribute, which is the other model-free layer. netsim() runs the
simulation, and multilayer() sets per-layer parameters and controls.
# A dynamic census: an observed networkDynamic with edge spells, here 80 # contacts between 50 people over 30 time steps set.seed(4) pairs <- t(combn(50, 2))[sample.int(choose(50, 2), 80), ] onset <- sample(0:25, 80, replace = TRUE) spells <- data.frame(onset = onset, terminus = onset + sample(2:10, 80, replace = TRUE), tail = pairs[, 1], head = pairs[, 2]) nd <- networkDynamic::networkDynamic(base.net = network_initialize(n = 50), edge.spells = spells) obs <- netcensus(nd, window = c(0, 30)) obs param <- param.net(inf.prob = 0.5, act.rate = 1) init <- init.net(i.num = 5) control <- control.net(type = "SI", nsteps = 25, nsims = 2, resimulate.network = FALSE, verbose = FALSE) sim <- netsim(obs, param, init, control) plot(sim) # The same census under tergmLite, with the active edges read each step control <- control.net(type = "SI", nsteps = 25, nsims = 2, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE) sim <- netsim(obs, param, init, control) # A static census next to an estimated layer nw <- network_initialize(n = 100) nw <- add.edges(nw, tail = 1:50, head = 51:100) est <- netest(nw, ~edges, target.stats = 40, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) sim <- netsim(list(netcensus(nw), est), param.net(inf.prob = multilayer(0.3, 0.1)), init.net(i.num = 5), control.net(type = "SI", nsteps = 20, nsims = 1, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE))# A dynamic census: an observed networkDynamic with edge spells, here 80 # contacts between 50 people over 30 time steps set.seed(4) pairs <- t(combn(50, 2))[sample.int(choose(50, 2), 80), ] onset <- sample(0:25, 80, replace = TRUE) spells <- data.frame(onset = onset, terminus = onset + sample(2:10, 80, replace = TRUE), tail = pairs[, 1], head = pairs[, 2]) nd <- networkDynamic::networkDynamic(base.net = network_initialize(n = 50), edge.spells = spells) obs <- netcensus(nd, window = c(0, 30)) obs param <- param.net(inf.prob = 0.5, act.rate = 1) init <- init.net(i.num = 5) control <- control.net(type = "SI", nsteps = 25, nsims = 2, resimulate.network = FALSE, verbose = FALSE) sim <- netsim(obs, param, init, control) plot(sim) # The same census under tergmLite, with the active edges read each step control <- control.net(type = "SI", nsteps = 25, nsims = 2, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE) sim <- netsim(obs, param, init, control) # A static census next to an estimated layer nw <- network_initialize(n = 100) nw <- add.edges(nw, tail = 1:50, head = 51:100) est <- netest(nw, ~edges, target.stats = 40, coef.diss = dissolution_coefs(~offset(edges), 10), verbose = FALSE) sim <- netsim(list(netcensus(nw), est), param.net(inf.prob = multilayer(0.3, 0.1)), init.net(i.num = 5), control.net(type = "SI", nsteps = 20, nsims = 1, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE))
Builds a network layer in which every pair of nodes sharing a
value of a grouping attribute is connected, so that each group
(a household, classroom, hospital ward, or cabin) is a clique.
netsim() accepts the layer anywhere in its layer list
alongside the layers estimated with netest(). The edges of a
clique layer never form or dissolve: there is no formation
model, no dissolution model, and no resimulation. It is an
addition to netest for structures that are groups by
definition, not a substitute for an ERGM (see Details).
netclique( nw, group.attr, arrivals = c("isolate", "new", "join"), arrivals.FUN = NULL )netclique( nw, group.attr, arrivals = c("isolate", "new", "join"), arrivals.FUN = NULL )
nw |
An object of class |
group.attr |
Name of a vertex attribute on |
arrivals |
Rule for placing nodes that arrive during a simulation with
vital dynamics: |
arrivals.FUN |
Optional function used with |
A netest object carries a formation model, a dissolution model, and a
starting network; netsim resimulates its layer each time step. That is
the right representation whenever tie existence is something to model: a
network with a degree distribution, mixing by attribute, and clustering to
reproduce is an ERGM's job whether its ties turn over quickly, slowly, or
not at all, and a long partnership duration in dissolution_coefs() keeps
a netest layer close to fixed.
Some contact structures are groups by construction instead: every pair of
co-residents is a household contact for the whole simulation, every pair
of pupils in a classroom is a classroom contact, every pair of cabin-mates
shares a cabin. There is no tie-formation process to estimate, and an ERGM
can reproduce such cliques only through a nodematch term on the group
attribute targeted at its maximum, the number of within-group pairs. A
target at the maximum of a statistic has no finite coefficient, so the fit
runs to its iteration limit, the coefficient it stops at is arbitrary, and
a few groups are typically left incomplete. Before this function, the
alternative was to carry the clique edgelist into netsim as a parameter
and walk it in a custom infection module. netclique is for these cases.
It builds a layer object that fills a slot in the layer list, is skipped
by the network resimulation and the edges correction, and is read by the
built-in infection modules through discord_edgelist() like any other
layer.
A network whose edges are given rather than generated, such as a fully
observed contact network, is a different case again: it may carry its own
edge dynamics and it skips estimation for a different reason. That case is
handled by netcensus().
The group attribute must be an integer, numeric, or character vector; a
factor is refused because arrivals under "new" need to create values the
factor does not have. It should also be set on the network passed to
netest() for the other layers, since netsim reads nodal attributes from
the first layer in its list; when it is not, netsim copies it from the
clique layer.
An object of class netclique, a list with elements:
newnetwork: a networkLite object holding the node set, the vertex
attributes of nw, and the clique edges. A networkLite stores the
edges as an edgelist, so the layer stays small for large populations;
trim_netest() has nothing further to remove from it.
group.attr: the grouping attribute name.
arrivals, arrivals.FUN: the arrival rule.
target.stats, target.stats.names: the edge count of the layer,
named "edges", so that the network statistics table printed by
print.netsim() and plotted by plot.netsim() shows the layer's own
edge count as the target.
edapprox: FALSE.
summary: a list with the node count, number of groups, edge count, mean degree, number of isolates, and the group size distribution.
When a model has vital dynamics, each arriving node has to be placed on the
clique layer. netsim applies the rule chosen with arrivals inside
arrive_nodes(), once per clique layer, after the arrivals module has
created the node and set its other attributes:
"isolate": the node gets no edges and its group attribute is NA. A
custom module may place it later.
"new": the node gets a fresh group id and no edges. Fresh ids
continue from the largest id used so far in the simulation, so an id is
never given to a second group, even after every member of the first has
departed; for character ids they are new strings of the form
arrival_<i>. Groups then grow only through further "join" arrivals,
so this rule suits models in which arrivals are single-person
households.
"join": the node joins an existing group and is connected to every
active member of that group, including other nodes joining the same
group in the same time step. By default the group is drawn with
probability proportional to its current size, which is the distribution
of a randomly chosen existing member. arrivals.FUN replaces that draw:
it is called as arrivals.FUN(dat, at, new_ids, network) and must return
one group id per element of new_ids (an NA leaves that node as an
isolate). Because the function receives the full dat object it can
read any nodal attribute; the example below places each newborn in a
household that already has a young child, and a function that reads the
group attribute back for new_ids lets a custom arrivals module set the
group itself. A function that draws from existing groups should leave
new_ids and inactive nodes out of its pool: when an arrivals module
gives new nodes a default value of the grouping attribute, such as 0,
a pool taken from all nodes contains that value, and every arrival that
draws it joins the other arrivals in a spurious group.
The layer keeps arrivals.FUN with its enclosing environment, and so does
every netsim object simulated from it. Define the function at the top
level of a script or in a package, not inside another function whose local
objects (fitted networks, population data) would then be saved with each
simulation.
The rule decides the group attribute of every arriving node. A value given
by attr.rules in control.net() or by a custom arrivals module is
replaced, so that the layer always matches the groups, and netsim warns
when attr.rules names the group attribute. The exception is "join" with
an arrivals.FUN that reads that value back, as described above.
The built-in infection modules treat every layer alike, so a clique layer
transmits with the model's inf.prob and act.rate unless those are given
per layer as multilayer() objects in param.net():
param.net(inf.prob = multilayer(0.45, 0.10), act.rate = multilayer(1, 2))
with the household layer first and the community layer second. The
transmission matrix records the layer of each transmission in its
network column.
Nodes departing the population are removed from a clique layer with their
edges, as on every other layer. Network statistics for the layer are
recorded through nwstats.formula in control.net(), with the default
"formation" meaning ~edges for a clique layer, and the cumulative
edgelist records its edges with a start time of 0. netdx() refuses a
netclique object, since there is no model to diagnose; the group size
distribution and mean degree are shown by print.
sample_groups() builds a population from a table of group
types, and assign_groups() assigns group ids to an existing population
with composition constraints. netsim() runs the simulation, and
multilayer() sets per-layer parameters and controls.
# Households as cliques under a community TERGM layer hh <- sample_groups(500, c("adult" = 0.3, "adult adult" = 0.4, "adult adult child" = 0.2, "adult adult child child" = 0.1), attr.name = "age") nw <- network_initialize(n = 500) nw <- set_vertex_attribute(nw, "age", hh$age) nw <- set_vertex_attribute(nw, "hh_id", hh$group) est_hh <- netclique(nw, group.attr = "hh_id", arrivals = "join") est_hh print(est_hh, by = "age") est_com <- netest(nw, formation = ~edges + nodematch("age"), target.stats = c(250, 175), coef.diss = dissolution_coefs(~offset(edges), 20), verbose = FALSE) param <- param.net(inf.prob = multilayer(0.3, 0.05), act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 50, nsims = 1, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE) sim <- netsim(list(est_hh, est_com), param, init, control) # Share of transmissions on the household layer tm <- get_transmat(sim) mean(tm$network == 1) # Newborns join a household that already has a child est_hh2 <- netclique(nw, group.attr = "hh_id", arrivals = "join", arrivals.FUN = function(dat, at, new_ids, network) { active <- get_attr(dat, "active") hh <- get_attr(dat, "hh_id") age <- get_attr(dat, "age") existing <- active == 1 existing[new_ids] <- FALSE pool <- hh[which(existing & age == "child" & !is.na(hh))] pool[sample.int(length(pool), length(new_ids), replace = TRUE)] })# Households as cliques under a community TERGM layer hh <- sample_groups(500, c("adult" = 0.3, "adult adult" = 0.4, "adult adult child" = 0.2, "adult adult child child" = 0.1), attr.name = "age") nw <- network_initialize(n = 500) nw <- set_vertex_attribute(nw, "age", hh$age) nw <- set_vertex_attribute(nw, "hh_id", hh$group) est_hh <- netclique(nw, group.attr = "hh_id", arrivals = "join") est_hh print(est_hh, by = "age") est_com <- netest(nw, formation = ~edges + nodematch("age"), target.stats = c(250, 175), coef.diss = dissolution_coefs(~offset(edges), 20), verbose = FALSE) param <- param.net(inf.prob = multilayer(0.3, 0.05), act.rate = 1) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 50, nsims = 1, tergmLite = TRUE, resimulate.network = TRUE, verbose = FALSE) sim <- netsim(list(est_hh, est_com), param, init, control) # Share of transmissions on the household layer tm <- get_transmat(sim) mean(tm$network == 1) # Newborns join a household that already has a child est_hh2 <- netclique(nw, group.attr = "hh_id", arrivals = "join", arrivals.FUN = function(dat, at, new_ids, network) { active <- get_attr(dat, "active") hh <- get_attr(dat, "hh_id") age <- get_attr(dat, "age") existing <- active == 1 existing[new_ids] <- FALSE pool <- hh[which(existing & age == "child" & !is.na(hh))] pool[sample.int(length(pool), length(new_ids), replace = TRUE)] })
Runs diagnostic simulations on an ERGM/STERGM estimated with
netest to assess whether the fitted model reproduces the
intended network features. Both static (cross-sectional) and
dynamic (temporal) diagnostics are supported. This is the
recommended second step in the network modeling pipeline, after
estimation with netest and before epidemic simulation with
netsim.
netdx( x, nsims = 1, dynamic = TRUE, nsteps = NULL, nwstats.formula = "formation", set.control.ergm = control.simulate.formula(), set.control.tergm = control.simulate.formula.tergm(MCMC.maxchanges = .Machine$integer.max), sequential = TRUE, keep.tedgelist = FALSE, keep.tnetwork = FALSE, verbose = TRUE, ncores = 1, skip.dissolution = FALSE, future.use.plan = FALSE )netdx( x, nsims = 1, dynamic = TRUE, nsteps = NULL, nwstats.formula = "formation", set.control.ergm = control.simulate.formula(), set.control.tergm = control.simulate.formula.tergm(MCMC.maxchanges = .Machine$integer.max), sequential = TRUE, keep.tedgelist = FALSE, keep.tnetwork = FALSE, verbose = TRUE, ncores = 1, skip.dissolution = FALSE, future.use.plan = FALSE )
x |
An |
nsims |
Number of simulations to run. For dynamic diagnostics, 5–10 simulations are usually sufficient to assess model fit. For static diagnostics, use 10,000+ draws to obtain stable estimates. |
dynamic |
If |
nsteps |
Number of time steps per simulation (dynamic simulations only). Should be at least several multiples of the longest target partnership duration to allow the duration and dissolution statistics to stabilize. For example, if the target duration is 50, running for 500 time steps is a reasonable starting point. |
nwstats.formula |
A right-hand sided ERGM formula with the network
statistics of interest. The default is the formation formula of the
network model contained in |
set.control.ergm |
Control arguments passed to |
set.control.tergm |
Control arguments passed to |
sequential |
For static diagnostics ( |
keep.tedgelist |
If |
keep.tnetwork |
If |
verbose |
If |
ncores |
Number of processor cores to run multiple simulations
on, using the |
skip.dissolution |
If |
future.use.plan |
If |
The netdx function handles dynamic network diagnostics for network
models fit with the netest function. Given the fitted model,
netdx simulates a specified number of dynamic networks for a specified
number of time steps per simulation. The network statistics in
nwstats.formula are saved for each time step. Summary statistics for
the formation model terms, as well as dissolution model and relational
duration statistics, are then calculated and can be accessed when printing or
plotting the netdx object. See print.netdx and plot.netdx
for details on printing and plotting.
A list of class netdx. Use print() to view summary tables of
formation statistics, duration, and dissolution diagnostics. Use
plot.netdx to visualize these diagnostics over time. Use
as.data.frame.netdx() to extract timed edgelists (if
keep.tedgelist = TRUE).
Models fit with the full STERGM method in netest (setting the
edapprox argument to FALSE) require only a call to
tergm's simulate_formula.network. Control parameters for those
simulations may be set using set.control.tergm in netdx.
The parameters should be input through the control.simulate.formula.tergm
function, with the available parameters listed in the
tergm::control.simulate.formula.tergm help page in the tergm
package.
Models fit with the ERGM method with the edges dissolution approximation
(setting edapprox to TRUE) require a call first to
ergm's simulate_formula.network for simulating an initial
network, and second to tergm's simulate_formula.network for
simulating that static network forward through time. Control parameters may
be set for both processes in netdx. For the first, the parameters
should be input through the control.simulate.formula() function, with
the available parameters listed in the
ergm::control.simulate.formula help
page in the ergm package. For the second, parameters should be input
through the control.simulate.formula.tergm() function, with the
available parameters listed in the tergm::control.simulate.formula.tergm
help page in the tergm package. An example is shown below.
Pass the same set.control.tergm settings to control.net for the
epidemic simulation, which steps the network forward in the same way. See
net-controls for the settings most often changed.
Static diagnostics (dynamic = FALSE) draw many independent networks from
the fitted ERGM and compare the resulting statistics to the target values.
This is fast and checks whether the cross-sectional structure is correct,
but it does not verify partnership durations or dissolution rates. Dynamic
diagnostics (dynamic = TRUE) simulate the full temporal network forward
in time, checking both formation targets and dissolution/duration dynamics.
Dynamic diagnostics are slower but more comprehensive, and are required to
verify models that will be used with vital dynamics (arrivals/departures).
After running netdx, use print() and plot.netdx to inspect the
results. Key indicators of a good model fit include:
Formation statistics: The "Sim Mean" should be close to the "Target" value. A small "Pct Diff" (< 5\ indicate good fit.
Duration statistics (dynamic only): The simulated mean edge
durations should match the values passed to dissolution_coefs.
Dissolution statistics (dynamic only): The simulated dissolution
rates should be approximately 1 / duration.
The Z score scales with the effective sample size of the simulated statistics, so read it together with the percent difference: many static draws can make a small difference statistically significant, while the autocorrelation between time steps keeps the Z scores of dynamic diagnostics smaller.
Common problems: If the dynamic formation statistics are off, compare them
with static diagnostics (dynamic = FALSE). Static diagnostics on target
point to the dynamic simulation: either its per-step burn-in, which can be
fixed with MCMC.burnin.min and MCMC.burnin.max in set.control.tergm,
or the edges dissolution approximation, which loses accuracy at short
partnership durations. Static diagnostics that are also off point to the
ERGM fit or to too short a burn-in in set.control.ergm. The target
statistics may also be incompatible (e.g., specifying more edges than the
network can support). See net-controls for the settings to adjust at
each stage. If durations are off but formation is correct, verify that
d.rate was correctly specified in dissolution_coefs for models
with vital dynamics.
Estimate the network model with netest before running diagnostics.
Plot diagnostics with plot.netdx and print summary tables with
print.netdx. With keep.tedgelist = TRUE, extract the timed edgelist
with as.data.frame.netdx() and the cumulative or momentary degree
distribution with get_degree_dist. After diagnostics confirm a good fit,
simulate the epidemic with netsim.
# Static diagnostics on a simple model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 25) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) dx <- netdx(est, nsims = 1e4, dynamic = FALSE, verbose = FALSE) dx plot(dx) ## Not run: # Static diagnostics with additional network statistics dx1 <- netdx(est, nsims = 1e4, dynamic = FALSE, nwstats.formula = ~ edges + meandeg + concurrent ) dx1 plot(dx1, method = "b", stats = c("edges", "concurrent")) # Dynamic diagnostics on the STERGM approximation dx2 <- netdx(est, nsims = 5, nsteps = 500, nwstats.formula = ~ edges + meandeg + concurrent, set.control.ergm = control.simulate.formula(MCMC.burnin = 1e6) ) dx2 plot(dx2, stats = c("edges", "meandeg"), plots.joined = FALSE) plot(dx2, type = "duration") plot(dx2, type = "dissolution", qnts.col = "orange2") plot(dx2, type = "dissolution", method = "b", col = "bisque") # Dynamic diagnostics on a more complex model nw <- network_initialize(n = 1000) nw <- set_vertex_attribute(nw, "neighborhood", rep(1:10, 100)) formation <- ~edges + nodematch("neighborhood", diff = TRUE) target.stats <- c(800, 45, 81, 24, 16, 32, 19, 42, 21, 24, 31) coef.diss <- dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("neighborhood", diff = TRUE)), duration = c(52, 58, 61, 55, 81, 62, 52, 64, 52, 68, 58)) est2 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) dx3 <- netdx(est2, nsims = 5, nsteps = 100) print(dx3) plot(dx3) plot(dx3, type = "duration", plots.joined = TRUE, qnts = 0.2, legend = TRUE) plot(dx3, type = "dissolution", mean.smooth = FALSE, mean.col = "red") ## End(Not run)# Static diagnostics on a simple model nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 25) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) dx <- netdx(est, nsims = 1e4, dynamic = FALSE, verbose = FALSE) dx plot(dx) ## Not run: # Static diagnostics with additional network statistics dx1 <- netdx(est, nsims = 1e4, dynamic = FALSE, nwstats.formula = ~ edges + meandeg + concurrent ) dx1 plot(dx1, method = "b", stats = c("edges", "concurrent")) # Dynamic diagnostics on the STERGM approximation dx2 <- netdx(est, nsims = 5, nsteps = 500, nwstats.formula = ~ edges + meandeg + concurrent, set.control.ergm = control.simulate.formula(MCMC.burnin = 1e6) ) dx2 plot(dx2, stats = c("edges", "meandeg"), plots.joined = FALSE) plot(dx2, type = "duration") plot(dx2, type = "dissolution", qnts.col = "orange2") plot(dx2, type = "dissolution", method = "b", col = "bisque") # Dynamic diagnostics on a more complex model nw <- network_initialize(n = 1000) nw <- set_vertex_attribute(nw, "neighborhood", rep(1:10, 100)) formation <- ~edges + nodematch("neighborhood", diff = TRUE) target.stats <- c(800, 45, 81, 24, 16, 32, 19, 42, 21, 24, 31) coef.diss <- dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("neighborhood", diff = TRUE)), duration = c(52, 58, 61, 55, 81, 62, 52, 64, 52, 68, 58)) est2 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) dx3 <- netdx(est2, nsims = 5, nsteps = 100) print(dx3) plot(dx3) plot(dx3, type = "duration", plots.joined = TRUE, qnts = 0.2, legend = TRUE) plot(dx3, type = "dissolution", mean.smooth = FALSE, mean.col = "red") ## End(Not run)
Estimates statistical network models using the exponential
random graph modeling (ERGM) framework with extensions for
dynamic/temporal models (STERGM). This is typically the first
step in the network modeling pipeline, followed by netdx
for model diagnostics and netsim for epidemic simulation.
netest( nw, formation, target.stats, coef.diss, constraints = NULL, coef.form = NULL, edapprox = TRUE, set.control.ergm = control.ergm(), set.control.tergm = control.tergm(MCMC.maxchanges = .Machine$integer.max), set.control.ergm.ego = NULL, verbose = FALSE, nested.edapprox = TRUE, ergm.ego.popsize = 0, ... )netest( nw, formation, target.stats, coef.diss, constraints = NULL, coef.form = NULL, edapprox = TRUE, set.control.ergm = control.ergm(), set.control.tergm = control.tergm(MCMC.maxchanges = .Machine$integer.max), set.control.ergm.ego = NULL, verbose = FALSE, nested.edapprox = TRUE, ergm.ego.popsize = 0, ... )
nw |
An object of class |
formation |
Right-hand sided STERGM formation formula in the form
|
target.stats |
Vector of target statistics for the formation model, with
one number for each network statistic in the model. These are the
observed (or desired) values for each term in the formation formula.
For example, if |
coef.diss |
An object of class |
constraints |
Right-hand sided formula specifying constraints for the
modeled network, in the form |
coef.form |
Vector of coefficients for the offset terms in the formation formula. |
edapprox |
If |
set.control.ergm |
Control arguments passed to |
set.control.tergm |
Control arguments passed to |
set.control.ergm.ego |
Control arguments passed to |
verbose |
If |
nested.edapprox |
Logical, only used when |
ergm.ego.popsize |
Numeric. The |
... |
Additional arguments passed to other functions. |
netest is a wrapper function for the ergm, ergm.ego, and tergm
functions that estimate static and dynamic network models. Network model
estimation is the first step in simulating a stochastic network epidemic model
in EpiModel. The output from netest is a necessary input for running the
epidemic simulations in netsim. With a fitted network model, one should
always first proceed to model diagnostics, available through the netdx
function, to check model fit. A detailed description of fitting these
models, along with examples, may be found in the
Network Modeling for Epidemics
tutorials.
A fitted network model object of class netest. This object is
passed to netdx for diagnostics and to netsim for epidemic
simulation. Use print() to view the model form, including the
formation formula, target statistics, and dissolution model. Use
summary() to view the estimated model coefficients and goodness-of-fit
statistics from the underlying ERGM or STERGM fit.
The edges dissolution approximation method is described in Carnegie et al. This approximation requires that the dissolution coefficients are known, that the formation model is being fit to cross-sectional data conditional on those dissolution coefficients, and that the terms in the dissolution model are a subset of those in the formation model. Under certain additional conditions, the formation coefficients of a STERGM model are approximately equal to the coefficients of that same model fit to the observed cross-sectional data as an ERGM, minus the corresponding coefficients in the dissolution model. The approximation thus estimates this ERGM (which is typically much faster than estimating a STERGM) and subtracts the dissolution coefficients.
The conditions under which this approximation best hold are when there are
few relational changes from one time step to another; i.e. when either
average relational durations are long, or density is low, or both.
Conveniently, these are the same conditions under which STERGM estimation is
slowest. Note that the same approximation is also used to obtain starting
values for the STERGM estimate when the latter is being conducted. The
estimation does not allow for calculation of standard errors, p-values, or
likelihood for the formation model; thus, this approach is of most use when
the main goal of estimation is to drive dynamic network simulations rather
than to conduct inference on the formation model. The user is strongly
encouraged to examine the behavior of the resulting simulations to confirm
that the approximation is adequate for their purposes. For an example, see
the vignette for the package tergm.
It has recently been found that subtracting a modified version of the
dissolution coefficients from the formation coefficients provides a more
principled approximation, and this is now the form of the approximation
applied by netest for both settings of nested.edapprox. The modified
values subtracted from the formation coefficients are equivalent to the
(crude) dissolution coefficients with their target durations increased by 1.
The nested.edapprox argument does not change this approximation; it only
controls how it is implemented. When TRUE (the default), the dissolution
terms are an initial segment of the formation model, so the correction
values are subtracted in place from the corresponding initial formation
model coefficients. When FALSE, the dissolution terms need not be nested
in the formation model: they are appended to the formation model and the
corresponding correction values are appended to the vector of formation
model coefficients.
The nesting requirement is a property of the approximation, so it is only
checked when edapprox = TRUE. A direct STERGM fit (edapprox = FALSE)
estimates formation and persistence jointly and places no such requirement on
the dissolution terms. Note, however, that tergm derives the starting
values for its EGMME fit from the same approximation, so a direct fit whose
persistence terms have no formation analog needs starting values supplied
through set.control.tergm, with control.tergm(init = ...) or
control.tergm(init.method = "zeros").
The ergm, ergm.ego, and tergm functions allow control settings for the
model fitting process. When fitting a STERGM directly (setting
edapprox to FALSE), control parameters may be passed to the
tergm function with the set.control.tergm argument in netest.
The controls should be input through the control.tergm() function,
with the available parameters listed in the tergm::control.tergm help
page in the tergm package.
When fitting a STERGM indirectly (setting edapprox to TRUE), control
settings may be passed to the ergm function using set.control.ergm,
or to the ergm.ego function using set.control.ergm.ego. The controls
should be input through the control.ergm() and control.ergm.ego()
functions, respectively, with the available parameters listed in the
ergm::control.ergm help page in the ergm package and the
ergm.ego::control.ergm.ego help page in the ergm.ego
package. An example is below.
The net-controls help page lists the settings most often changed when a
fit fails, stalls, or does not reproduce its targets, and how to use
netdx to find whether the estimation or the simulation needs adjusting.
The Improving Model Estimation and Simulation
appendix of the Network Modeling for Epidemics course materials works
through examples.
The network modeling pipeline in EpiModel typically follows these steps:
Initialize a network: network_initialize
Specify formation and dissolution: a formation formula (e.g.,
~edges + concurrent) with target statistics, and dissolution
coefficients via dissolution_coefs
Estimate the network model: netest()
Diagnose model fit: netdx
Simulate the epidemic: netsim with param.net, init.net,
and control.net
Krivitsky PN, Handcock MS. "A Separable Model for Dynamic Networks." JRSS(B). 2014; 76.1: 29-46.
Carnegie NB, Krivitsky PN, Hunter DR, Goodreau SM. An Approximation Method for Improving Dynamic Network Model Fitting. Journal of Computational and Graphical Statistics. 2014; 24(2): 502-519.
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.
Use dissolution_coefs to compute dissolution coefficients
before estimation. Use netdx to diagnose the fitted network
model, and netsim to simulate epidemic spread over a simulated
dynamic network consistent with the model fit. Parameterize the
epidemic simulation with param.net, init.net, and
control.net.
# Initialize a network of 100 nodes nw <- network_initialize(n = 100) # Set formation formula formation <- ~edges + concurrent # Set target statistics for formation target.stats <- c(50, 25) # Obtain the offset coefficients coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 10) # Estimate the STERGM using the edges dissolution approximation est <- netest(nw, formation, target.stats, coef.diss, set.control.ergm = control.ergm(MCMC.burnin = 1e5, MCMC.interval = 1000)) # View the model form (formation, targets, dissolution) est # View the estimated coefficients summary(est) ## Not run: # Model with homophily on a nodal attribute nw2 <- network_initialize(n = 500) nw2 <- set_vertex_attribute(nw2, "risk", rep(0:1, each = 250)) formation2 <- ~edges + nodematch("risk") target.stats2 <- c(175, 110) coef.diss2 <- dissolution_coefs(dissolution = ~offset(edges), duration = 50) est2 <- netest(nw2, formation2, target.stats2, coef.diss2) est2 # Direct STERGM estimation (slower, for short durations or inference) est3 <- netest(nw, formation, target.stats, coef.diss, edapprox = FALSE) ## End(Not run)# Initialize a network of 100 nodes nw <- network_initialize(n = 100) # Set formation formula formation <- ~edges + concurrent # Set target statistics for formation target.stats <- c(50, 25) # Obtain the offset coefficients coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 10) # Estimate the STERGM using the edges dissolution approximation est <- netest(nw, formation, target.stats, coef.diss, set.control.ergm = control.ergm(MCMC.burnin = 1e5, MCMC.interval = 1000)) # View the model form (formation, targets, dissolution) est # View the estimated coefficients summary(est) ## Not run: # Model with homophily on a nodal attribute nw2 <- network_initialize(n = 500) nw2 <- set_vertex_attribute(nw2, "risk", rep(0:1, each = 250)) formation2 <- ~edges + nodematch("risk") target.stats2 <- c(175, 110) coef.diss2 <- dissolution_coefs(dissolution = ~offset(edges), duration = 50) est2 <- netest(nw2, formation2, target.stats2, coef.diss2) est2 # Direct STERGM estimation (slower, for short durations or inference) est3 <- netest(nw, formation, target.stats, coef.diss, edapprox = FALSE) ## End(Not run)
Simulates stochastic network epidemic models for infectious
disease. This is typically the final step in the network
modeling pipeline, after network estimation with netest
and model diagnostics with netdx.
netsim(x, param, init, control)netsim(x, param, init, control)
x |
If |
param |
Model parameters, as an object of class |
init |
Initial conditions, as an object of class |
control |
Control settings, as an object of class |
Stochastic network models explicitly represent phenomena within and across edges (pairs of nodes that remain connected) over time. This enables edges to have duration, allowing for repeated transmission-related acts within the same dyad, specification of edge formation and dissolution rates, control over the temporal sequencing of multiple edges, and specification of network-level features. A detailed description of these models, along with examples, is found in the Network Modeling for Epidemics course materials.
The netsim function performs modeling of both the base model types
and original models. Base model types include one-group and two-group models
with disease types for Susceptible-Infected (SI), Susceptible-Infected-Recovered (SIR),
and Susceptible-Infected-Susceptible (SIS).
Original models may be parameterized by writing new process modules that
either take the place of existing modules (for example, disease recovery), or
supplement the set of existing processes with a new one contained in a new
module. This functionality is documented in the
Extending EpiModel
section of the Network Modeling for Epidemics
course materials. The list of modules within netsim available for
modification is listed in modules.net().
A list of class netsim with the following elements:
param: the epidemic parameters passed into the model through
param, with additional parameters added as necessary.
control: the control settings passed into the model through
control, with additional controls added as necessary.
epi: a list of data frames, one for each epidemiological output from the model. Outputs for base models always include the size of each compartment, as well as flows in, out of, and between compartments.
stats: a list containing two sublists, nwstats for any
network statistics saved in the simulation, and transmat for
the transmission matrix saved in the simulation. See
control.net() for further
details.
network: a list of lists of networkDynamic or
networkLite objects, with one list of objects for each model
simulation.
If control$raw.output == TRUE: A list of the raw (pre-processed)
netsim_dat objects, for use in simulation continuation.
The epi data can be extracted as a data frame with
as.data.frame.netsim(), with options for per-simulation values
(out = "vals"), means (out = "mean"), standard deviations
(out = "sd"), or quantiles (out = "qnt").
At each time step, netsim executes a series of modules in sequence.
For base models, the default pipeline is:
Network resimulation (resim_nets): updates the network
structure (if resimulate.network = TRUE).
Infection (infection.net): simulates disease transmission
across discordant edges (where one partner is susceptible and the
other is infected).
Recovery (recovery.net): simulates recovery from infection
(SIR and SIS models only).
Departures (departures.net): simulates node exits from the
network (if vital dynamics are enabled).
Arrivals (arrivals.net): simulates new node entries into the
network (if vital dynamics are enabled).
Prevalence (prevalence.net): calculates summary statistics.
See modules.net() for full details on each module.
Setting tergmLite = TRUE in control.net uses a lightweight network
representation (networkLite) that is substantially faster than the full
networkDynamic representation, often by a factor of 20–50x. This is
recommended for large networks or when running many simulations. The
trade-off is that full networkDynamic objects are not available for
post-hoc analysis; use the cumulative edgelist
(cumulative.edgelist = TRUE) instead to track partnership histories.
The resimulate.network control must be set to TRUE when demographic
processes (arrivals and departures) change the network composition over
time. Without it, the network structure evolves independently of the
epidemic and demographic dynamics.
For contact tracing, partnership-duration analysis, or reachability
analysis, enable cumulative-edgelist tracking via
control.net(cumulative.edgelist = TRUE, save.cumulative.edgelist = TRUE).
This records every edge formed during the simulation along with its
start and stop time steps, and attaches the result to the returned
object as sim$cumulative.edgelist. Under tergmLite = TRUE this is
the recommended substitute for the full networkDynamic history.
The helper family (get_cumulative_edgelist,
get_cumulative_edgelists_df, get_partners, get_cumulative_degree,
get_forward_reachable, get_backward_reachable) operates on the
tracked data. See vignette("network-objects", package = "EpiModel")
for the full lifecycle.
For models with multiple overlapping network layers (e.g., sexual and
needle-sharing networks), pass a list of netest objects to the x
argument, one per network layer. Each layer has its own
formation/dissolution dynamics but shares the same node set. See the
multilayer documentation for specifying controls that vary by layer, and
the Multi-Layer Networks
chapter of the Network Modeling for Epidemics course materials for a worked
example building from independent to cross-dependent layers.
A layer made of groups that are cliques by definition, such as households,
classrooms, wards, or cabins, may instead be built with netclique and
placed in the same list. This is an addition to netest, not a replacement
for it. An ERGM remains the natural model for a network whose ties depend on
nodal and dyadic predictors (degree, mixing by attribute, clustering),
whether those ties turn over quickly, slowly, or not at all; the model is
the compact description of that structure. In a clique layer every pair of
group members is a contact and there is no tie-formation process to
estimate. An ERGM can reproduce such cliques only through a nodematch
term targeted at its maximum, where no finite coefficient exists, so the
fit is unstable and rarely completes every group. A clique layer is skipped
by the network resimulation and the edges correction, its edges are removed
with departing nodes, and arriving nodes are placed on it under the rule
chosen in netclique.
A fully observed network, a static network or a networkDynamic with
edge spells from sensors, proximity loggers, or contact tracing, may be
placed in the list with netcensus. Here estimation is skipped because
the whole network is in hand rather than a sample to generalize from; the
simulation reads the edges active at each time step from the observed
object, and the node set is fixed, so vital dynamics are refused.
The built-in infection modules read every layer alike; to give each layer
its own transmission probability or act rate, pass inf.prob and
act.rate as multilayer objects in param.net. The transmission
matrix records the layer of every transmission in its network column.
Simulations can be checkpointed and restarted if interrupted. Set
.checkpoint.steps and .checkpoint.dir in control.net to enable
automatic checkpointing. To restart a simulation from a prior netsim
output, pass the netsim object as x and set control$start to one
greater than the final time step of the prior simulation. See the
Checkpointing Simulations section of control.net for full details. The
epi trackers and network statistics of the output hold every time step from
1 to nsteps, those of x followed by the new ones, and
as.data.frame.netsim and plot.netsim label them 1 to nsteps.
When restarting, every simulation restarts from the first simulation of x,
with a warning if x holds more than one. make_restart_point makes a
lightweight x holding the single simulation to restart from (get_sims
selects one from a netsim object). The parameters are taken from param
alone, which must hold all the parameters of the model: the ones saved in
x are not used.
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.
Estimate the network model with netest and diagnose model
fit with netdx before running simulations. Extract model
results with as.data.frame.netsim(). Summarize the
time-specific model results with summary.netsim(). Plot the
model results with plot.netsim(). Extract the network with
get_network, the transmission matrix with get_transmat,
and derive new epi statistics with mutate_epi.
## Not run: ## Example 1: SI Model without Network Feedback # Network model estimation nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Epidemic model param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, verbose.int = 0) mod1 <- netsim(est1, param, init, control) # Print, plot, and summarize the results mod1 plot(mod1) summary(mod1, at = 50) ## Example 2: SIR Model with Network Feedback (Two-Group) nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 # Recalculate dissolution coefficient with departure rate coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20, d.rate = 0.0021) # Reestimate the model with new coefficient est2 <- netest(nw, formation, target.stats, coef.diss) # Set parameters to include demographic rates param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15, rec.rate = 0.02, rec.rate.g2 = 0.02, a.rate = 0.002, a.rate.g2 = NA, ds.rate = 0.001, ds.rate.g2 = 0.001, di.rate = 0.001, di.rate.g2 = 0.001, dr.rate = 0.001, dr.rate.g2 = 0.001) init <- init.net(i.num = 10, i.num.g2 = 10, r.num = 0, r.num.g2 = 0) control <- control.net(type = "SIR", nsteps = 100, nsims = 5, resimulate.network = TRUE, tergmLite = TRUE) # Simulate the model with new network fit mod2 <- netsim(est2, param, init, control) # Print, plot, and summarize the results mod2 plot(mod2) summary(mod2, at = 40) ## Example 3: Post-Simulation Analysis # Extract epi data as a data frame as.data.frame(mod1) as.data.frame(mod1, out = "mean") # Extract the transmission matrix from simulation 1 get_transmat(mod1, sim = 1) # Derive new epi statistics and plot them mod1 <- mutate_epi(mod1, prev = i.num / num) plot(mod1, y = "prev") ## End(Not run)## Not run: ## Example 1: SI Model without Network Feedback # Network model estimation nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Epidemic model param <- param.net(inf.prob = 0.3) init <- init.net(i.num = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, verbose.int = 0) mod1 <- netsim(est1, param, init, control) # Print, plot, and summarize the results mod1 plot(mod1) summary(mod1, at = 50) ## Example 2: SIR Model with Network Feedback (Two-Group) nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 # Recalculate dissolution coefficient with departure rate coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20, d.rate = 0.0021) # Reestimate the model with new coefficient est2 <- netest(nw, formation, target.stats, coef.diss) # Set parameters to include demographic rates param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15, rec.rate = 0.02, rec.rate.g2 = 0.02, a.rate = 0.002, a.rate.g2 = NA, ds.rate = 0.001, ds.rate.g2 = 0.001, di.rate = 0.001, di.rate.g2 = 0.001, dr.rate = 0.001, dr.rate.g2 = 0.001) init <- init.net(i.num = 10, i.num.g2 = 10, r.num = 0, r.num.g2 = 0) control <- control.net(type = "SIR", nsteps = 100, nsims = 5, resimulate.network = TRUE, tergmLite = TRUE) # Simulate the model with new network fit mod2 <- netsim(est2, param, init, control) # Print, plot, and summarize the results mod2 plot(mod2) summary(mod2, at = 40) ## Example 3: Post-Simulation Analysis # Extract epi data as a data frame as.data.frame(mod1) as.data.frame(mod1, out = "mean") # Extract the transmission matrix from simulation 1 get_transmat(mod1, sim = 1) # Derive new epi statistics and plot them mod1 <- mutate_epi(mod1, prev = i.num / num) plot(mod1, y = "prev") ## End(Not run)
Initialize an undirected network object for use in EpiModel workflows.
network_initialize(n)network_initialize(n)
n |
Network size. |
This function is used in EpiModel workflows to initialize an empty
network object. The network attributes directed, bipartite,
hyper, loops, and multiple are set to FALSE.
Returns an object of class network.
nw <- network_initialize(100) nwnw <- network_initialize(100) nw
This function handles all calls to the network object contained
on the main netsim_dat object handled in netsim.
nwupdate.net(dat, at)nwupdate.net(dat, at)
dat |
Main |
at |
Current time step. |
The updated netsim_dat main list object.
data.frame to initialize some attributesUses dat$init$init_attr to overwrite some attributes of the
nodes at initialization
overwrite_attrs(dat)overwrite_attrs(dat)
dat |
Main |
If an init_attr data.frame is present in dat$init, use it to overwrite
the attributes it contains.
init_attr must have a number of rows equal to the number of nodes in the
model as the attributes will be overwritten one to one, ensuring the correct
ordering.
init_attr columns MUST have a corresponding attribute already initialized.
See "R/default_attributes.R" for adding new attributes to the model.
init_attr is removed from dat$init at the end of the function to free up
its memory.
The updated netsim_dat main list object.
Grow a vector to a given size, padding it with NULL if orig is a list
and with NA otherwise
padded_vector(orig, size)padded_vector(orig, size)
orig |
A vector to grow. |
size |
The final size of the vector. |
A vector of size size padded with NULLs or NAs at the end.
Sets the epidemic parameters for deterministic compartmental
models simulated with dcm.
param.dcm( inf.prob, inter.eff, inter.start, act.rate, rec.rate, a.rate, ds.rate, di.rate, dr.rate, inf.prob.g2, act.rate.g2, rec.rate.g2, a.rate.g2, ds.rate.g2, di.rate.g2, dr.rate.g2, balance, ... )param.dcm( inf.prob, inter.eff, inter.start, act.rate, rec.rate, a.rate, ds.rate, di.rate, dr.rate, inf.prob.g2, act.rate.g2, rec.rate.g2, a.rate.g2, ds.rate.g2, di.rate.g2, dr.rate.g2, balance, ... )
inf.prob |
Probability of infection per transmissible act between a susceptible and an infected person. In two-group models, this is the probability of infection for the group 1 members. |
inter.eff |
Efficacy of an intervention which affects the per-act probability of infection. Efficacy is defined as 1 - the relative hazard of infection given exposure to the intervention, compared to no exposure. |
inter.start |
Time step at which the intervention starts, between 1 and
the number of time steps specified in the model. This will default to
1 if |
act.rate |
Average number of transmissible acts per person per unit
time. For two-group models, this is the number of acts per group 1
person per unit time; a balance between the acts in groups 1 and 2 is
necessary, and set using the |
rec.rate |
Average rate of recovery with immunity (in |
a.rate |
Arrival or entry rate. For one-group models, the arrival rate
is the rate of new arrivals per person per unit time. For two-group
models, the arrival rate is parameterized as a rate per group 1
person per unit time, with the |
ds.rate |
Departure or exit rate for susceptible persons. For two-group models, it is the rate for the group 1 susceptible persons only. |
di.rate |
Departure or exit rate for infected persons. For two-group models, it is the rate for the group 1 infected persons only. |
dr.rate |
Departure or exit rate for recovered persons. For two-group
models, it is the rate for the group 1 recovered persons only. This
parameter is only used for |
inf.prob.g2 |
Probability of infection per transmissible act between a susceptible group 2 person and an infected group 1 person. It is the probability of infection to group 2 members. |
act.rate.g2 |
Average number of transmissible acts per group 2 person
per unit time; a balance between the acts in groups 1 and 2 is
necessary, and set using the |
rec.rate.g2 |
Average rate of recovery with immunity (in |
a.rate.g2 |
Arrival or entry rate for group 2. This may either be
specified numerically as the rate of new arrivals per group 2 persons
per unit time, or as |
ds.rate.g2 |
Departure or exit rate for group 2 susceptible persons. |
di.rate.g2 |
Departure or exit rate for group 2 infected persons. |
dr.rate.g2 |
Departure or exit rate for group 2 recovered persons. This
parameter is only used for |
balance |
For two-group models, balance the |
... |
Additional arguments passed to model. |
param.dcm sets the epidemic parameters for deterministic compartmental
models solved with the dcm() function. The models may use the
base types, for which these parameters are used, or original model
specifications for which these parameters may be used (but not necessarily).
For base models, the model specification will be selected as a function
of the model parameters entered here and the control settings in
control.dcm(). One-group and two-group models are available,
where the former assumes a homogeneous mixing in the population and the
latter assumes some form of heterogeneous mixing between two distinct
partitions in the population (e.g., men and women). Specifying any group two
parameters (those with a .g2) implies the simulation of a two-group
model. All the parameters for a desired model type must be specified, even if
they are zero.
An EpiModel object of class param.dcm.
In two-group models, a balance between the number of acts for group 1 members
and those for group 2 members must be maintained. With purely heterogeneous
mixing, the product of one group size and act rate must equal the product of
the other group size and act rate: , where
is the group size and the group-specific act rate
at time . The balance parameter here specifies which group's
act rate should control the others with respect to balancing.
dcm has been designed to easily run DCM sensitivity analyses, where a
series of models varying one or more of the model parameters is run. This is
possible by setting any parameter as a vector of length greater than one.
An original model may use either the existing model parameters named here,
an original set of parameters, or a combination of both. The ...
argument allows the user to pass an arbitrary set of new model parameters into
param.dcm. Whereas there are strict checks for base models that the
model parameters are valid, parameter validity is the user's responsibility
with these original models.
Use init.dcm() to specify the initial conditions and
control.dcm() to specify the control settings. Run the
parameterized model with dcm().
# SI model parameters param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) # SIS model with sensitivity analysis over act.rate param <- param.dcm(inf.prob = 0.2, act.rate = seq(0.1, 0.5, 0.1), rec.rate = 1/50)# SI model parameters param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) # SIS model with sensitivity analysis over act.rate param <- param.dcm(inf.prob = 0.2, act.rate = seq(0.1, 0.5, 0.1), rec.rate = 1/50)
Sets the epidemic parameters for stochastic individual contact
models simulated with icm.
param.icm( inf.prob, inter.eff, inter.start, act.rate, rec.rate, a.rate, ds.rate, di.rate, dr.rate, inf.prob.g2, act.rate.g2, rec.rate.g2, a.rate.g2, ds.rate.g2, di.rate.g2, dr.rate.g2, balance, ... )param.icm( inf.prob, inter.eff, inter.start, act.rate, rec.rate, a.rate, ds.rate, di.rate, dr.rate, inf.prob.g2, act.rate.g2, rec.rate.g2, a.rate.g2, ds.rate.g2, di.rate.g2, dr.rate.g2, balance, ... )
inf.prob |
Probability of infection per transmissible act between a susceptible and an infected person. In two-group models, this is the probability of infection for the group 1 members. |
inter.eff |
Efficacy of an intervention which affects the per-act probability of infection. Efficacy is defined as 1 - the relative hazard of infection given exposure to the intervention, compared to no exposure. |
inter.start |
Time step at which the intervention starts, between 1 and
the number of time steps specified in the model. This will default to
1 if |
act.rate |
Average number of transmissible acts per person per unit
time. For two-group models, this is the number of acts per group 1
person per unit time; a balance between the acts in groups 1 and 2 is
necessary, and set using the |
rec.rate |
Average rate of recovery with immunity (in |
a.rate |
Arrival or entry rate. For one-group models, the arrival rate
is the rate of new arrivals per person per unit time. For two-group
models, the arrival rate is parameterized as a rate per group 1
person per unit time, with the |
ds.rate |
Departure or exit rate for susceptible persons. For two-group models, it is the rate for the group 1 susceptible persons only. |
di.rate |
Departure or exit rate for infected persons. For two-group models, it is the rate for the group 1 infected persons only. |
dr.rate |
Departure or exit rate for recovered persons. For two-group
models, it is the rate for the group 1 recovered persons only. This
parameter is only used for |
inf.prob.g2 |
Probability of infection per transmissible act between a susceptible group 2 person and an infected group 1 person. It is the probability of infection to group 2 members. |
act.rate.g2 |
Average number of transmissible acts per group 2 person
per unit time; a balance between the acts in groups 1 and 2 is
necessary, and set using the |
rec.rate.g2 |
Average rate of recovery with immunity (in |
a.rate.g2 |
Arrival or entry rate for group 2. This may either be
specified numerically as the rate of new arrivals per group 2 persons
per unit time, or as |
ds.rate.g2 |
Departure or exit rate for group 2 susceptible persons. |
di.rate.g2 |
Departure or exit rate for group 2 infected persons. |
dr.rate.g2 |
Departure or exit rate for group 2 recovered persons. This
parameter is only used for |
balance |
For two-group models, balance the |
... |
Additional arguments passed to model. |
param.icm sets the epidemic parameters for the stochastic individual
contact models simulated with the icm() function. ICMs support the
built-in SI, SIR, and SIS disease types only; for custom or extension
epidemic models, use param.net() with the network model class.
The model specification will be chosen as a result of the model parameters
entered here and the control settings in
control.icm(). One-group and two-group models are available,
where the former assumes a homogeneous mixing in the population and the
latter assumes some form of heterogeneous mixing between two distinct
partitions in the population (e.g., men and women). Specifying any group two
parameters (those with a .g2) implies the simulation of a two-group
model. All the parameters for a desired model type must be specified, even if
they are zero.
An EpiModel object of class param.icm.
In two-group models, a balance between the number of acts for group 1 members
and those for group 2 members must be maintained. With purely heterogeneous
mixing, the product of one group size and act rate must equal the product of
the other group size and act rate: , where
is the group size and the group-specific act rate
at time . The balance parameter here specifies which group's
act rate should control the others with respect to balancing.
Use init.icm() to specify the initial conditions and
control.icm() to specify the control settings. Run the
parameterized model with icm().
Sets the epidemic parameters for stochastic network models
simulated with netsim().
param.net( inf.prob, inter.eff, inter.start, act.rate, rec.rate, a.rate, ds.rate, di.rate, dr.rate, inf.prob.g2, rec.rate.g2, a.rate.g2, ds.rate.g2, di.rate.g2, dr.rate.g2, ... )param.net( inf.prob, inter.eff, inter.start, act.rate, rec.rate, a.rate, ds.rate, di.rate, dr.rate, inf.prob.g2, rec.rate.g2, a.rate.g2, ds.rate.g2, di.rate.g2, dr.rate.g2, ... )
inf.prob |
Probability of infection per transmissible act between
a susceptible and an infected person. In two-group models, this is the
probability of infection to the group 1 nodes. This may also vary
with the infected partner's duration of infection, given as a
|
inter.eff |
Efficacy of an intervention which affects the per-act probability of infection. Efficacy is defined as 1 - the relative hazard of infection given exposure to the intervention, compared to no exposure. |
inter.start |
Time step at which the intervention starts, between 1 and
the number of time steps specified in the model. This will default to
1 if |
act.rate |
Average number of transmissible acts per partnership
per unit time (see |
rec.rate |
Average rate of recovery with immunity (in |
a.rate |
Arrival or entry rate. For one-group models, the arrival rate
is the rate of new arrivals per person per unit time. For two-group
models, the arrival rate is parameterized as a rate per group 1
person per unit time, with the |
ds.rate |
Departure or exit rate for susceptible persons. For two-group models, it is the rate for group 1 susceptible persons only. |
di.rate |
Departure or exit rate for infected persons. For two-group models, it is the rate for group 1 infected persons only. |
dr.rate |
Departure or exit rate for recovered persons. For two-group
models, it is the rate for group 1 recovered persons only. This
parameter is only used for |
inf.prob.g2 |
Probability of transmission given a transmissible act
between a susceptible group 2 person and an infected group 1 person.
It is the probability of transmission to group 2 members. As for
|
rec.rate.g2 |
Average rate of recovery with immunity (in |
a.rate.g2 |
Arrival or entry rate for group 2. This may either be
specified numerically as the rate of new arrivals per group 2 person
per unit time, or as |
ds.rate.g2 |
Departure or exit rate for group 2 susceptible persons. |
di.rate.g2 |
Departure or exit rate for group 2 infected persons. |
dr.rate.g2 |
Departure or exit rate for group 2 recovered persons. This
parameter is only used for |
... |
Additional arguments passed to model. |
param.net sets the epidemic parameters for the stochastic network
models simulated with the netsim() function. Models
may use the base types, for which these parameters are used, or new process
modules which may use these parameters (but not necessarily). A detailed
description of network model parameterization for base models is found in
the Network Modeling for Epidemics
tutorials.
For base models, the model specification will be chosen as a result of
the model parameters entered here and the control settings in
control.net(). One-group and two-group models are available,
where the latter assumes a heterogeneous mixing between two distinct
partitions in the population (e.g., men and women). Specifying any two-group
parameters (those with a .g2) implies the simulation of a two-group
model. All the parameters for a desired model type must be specified, even if
they are zero.
An EpiModel object of class param.net.
act.rate ParameterA key difference between these network models and DCM/ICM classes is the
treatment of transmission events. With DCM and ICM, contacts or partnerships
are mathematically instantaneous events: they have no duration in time, and
thus no changes may occur within them over time. In contrast, network models
allow for partnership durations defined by the dynamic network model,
summarized in the model dissolution coefficients calculated in
dissolution_coefs(). Therefore, the act.rate parameter has
a different interpretation here, where it is the number of transmissible acts
per partnership per unit time.
The inf.prob, act.rate, and rec.rate arguments (and their .g2
companions) may vary with the duration of infection, given as
by_infection_duration() objects, by stage or one value per time step
since infection. For example,
inf.prob = by_infection_duration(c(acute = 0.5, chronic = 0.1), durations = c(2, Inf))
gives a 0.5 transmission probability for the first two time steps of the
infected partner's infection and 0.1 from the third time step on, until the
person recovers, departs, or the simulation ends. This is variation over the course of each infection, not
over calendar time; to change a parameter at a given time step of the
simulation, use scenarios or parameter updaters (see
vignette("model-parameters", package = "EpiModel")).
With the built-in model types, a plain vector of length greater than one
passed to these arguments is an error. Before EpiModel 2.7.0, the built-in
modules read such a vector as varying with the duration of infection; wrap
it in by_infection_duration() for the same model. Custom modules read
their parameters as they choose, so plain vectors remain available to
them.
In models with more than one network layer (a list of netest() and
netclique() objects passed to netsim()), the inf.prob, inf.prob.g2,
and act.rate arguments may be given per layer as multilayer() objects
with one entry per layer, in the order of the layer list:
inf.prob = multilayer(0.45, 0.10) sets a per-act transmission probability
of 0.45 on the first layer and 0.10 on the second. Each entry may itself be
a by_infection_duration() object. The built-in infection modules look up
the entry for the layer each discordant edge belongs to; a parameter that
is not a multilayer object applies to every layer. The transmission
matrix records the layer of each transmission in its network column.
It is possible to set input parameters using a specifically formatted
data.frame object. The first 3 columns of this data.frame must
be:
param: The name of the parameter. If this is a non-scalar
parameter (a vector of length > 1), end the parameter name with the
position on the vector (e.g., "p_1", "p_2", ...).
value: the value for the parameter (or the value of the
parameter in the Nth position if non-scalar).
type: a character string containing either "numeric",
"logical", or "character" to define the parameter object
class.
In addition to these 3 columns, the data.frame can contain any number
of other columns, such as details or source columns to document
parameter meta-data. However, these extra columns will not be used by
EpiModel.
This data.frame is then passed in to param.net under a
data.frame.params argument. Further details and examples are provided in
the "Working with Model Parameters in EpiModel" vignette. Note that releases
through v2.6.1 documented this argument as data.frame.parameters, which
was never an accepted name; passing it now produces an error pointing to
data.frame.params.
To vary parameter values across simulations for uncertainty or sensitivity
analysis, draw the values in advance into a data.frame with one row per
draw, convert it with create_scenario_list(), and apply each resulting
scenario to the base parameters with use_scenario(). The "Working with
Model Parameters in EpiModel" vignette works through an example. The
random.params argument that served this purpose through v2.6.2 has been
removed; passing it now produces an error.
To build original models outside of the base models, new process modules
may be constructed to replace the existing modules or to supplement the
existing set. These are passed into the control settings in
control.net(). New modules may use either the existing model
parameters named here, an original set of parameters, or a combination of
both. The ... allows the user to pass an arbitrary set of original
model parameters into param.net. Whereas there are strict checks with
default modules for parameter validity, this becomes a user
responsibility when using new modules.
Use init.net() to specify the initial conditions and
control.net() to specify the control settings. Run the
parameterized model with netsim().
## Example SIR model parameterization # Network model estimation nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Parameters, initial conditions, and control settings param <- param.net(inf.prob = 0.3, act.rate = 2, rec.rate = 0.02) param init <- init.net(i.num = 10, r.num = 0) control <- control.net(type = "SIR", nsteps = 10, nsims = 3, verbose = FALSE) # Simulate the model sim <- netsim(est, param, init, control) sim## Example SIR model parameterization # Network model estimation nw <- network_initialize(n = 100) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Parameters, initial conditions, and control settings param <- param.net(inf.prob = 0.3, act.rate = 2, rec.rate = 0.02) param init <- init.net(i.num = 10, r.num = 0) control <- control.net(type = "SIR", nsteps = 10, nsims = 3, verbose = FALSE) # Simulate the model sim <- netsim(est, param, init, control) sim
Sets the epidemic parameters for stochastic network models with
netsim() using a specially formatted data frame of
parameters.
param.net_from_table(long.param.df)param.net_from_table(long.param.df)
long.param.df |
A |
A list object of class param.net, which can be passed to
netsim().
It is possible to set input parameters using a specifically formatted
data.frame object. The first 3 columns of this data.frame must
be:
param: The name of the parameter. If this is a non-scalar
parameter (a vector of length > 1), end the parameter name with the
position on the vector (e.g., "p_1", "p_2", ...).
value: the value for the parameter (or the value of the
parameter in the Nth position if non-scalar).
type: a character string containing either "numeric",
"logical", or "character" to define the parameter object
class.
In addition to these 3 columns, the data.frame can contain any number
of other columns, such as details or source columns to document
parameter meta-data. However, these extra columns will not be used by
EpiModel.
long.param.df
Coerce a list of parameters to a long.param.df
param.net_to_table(params)param.net_to_table(params)
params |
A list of parameters to be formatted into a |
Parameters given per network layer with multilayer() or by duration of
infection with by_infection_duration() are not supported and stop with
an error. A parameter table records each element of a vector as its own row
but not what the vector means, so such a value would read back as a plain
vector, which the built-in modules do not accept. Remove these parameters
before converting and set them again after reading the table back.
A data.frame of parameters.
It is possible to set input parameters using a specifically formatted
data.frame object. The first 3 columns of this data.frame must
be:
param: The name of the parameter. If this is a non-scalar
parameter (a vector of length > 1), end the parameter name with the
position on the vector (e.g., "p_1", "p_2", ...).
value: the value for the parameter (or the value of the
parameter in the Nth position if non-scalar).
type: a character string containing either "numeric",
"logical", or "character" to define the parameter object
class.
In addition to these 3 columns, the data.frame can contain any number
of other columns, such as details or source columns to document
parameter meta-data. However, these extra columns will not be used by
EpiModel.
Plots epidemiological data from a deterministic compartment
epidemic model solved with dcm().
## S3 method for class 'dcm' plot( x, y = NULL, popfrac = FALSE, run = NULL, col = NULL, lwd = NULL, lty = NULL, alpha = 0.9, legend = NULL, leg.name = NULL, leg.cex = 0.8, grid = FALSE, add = FALSE, main = "", xlim = NULL, ylim = NULL, xlab = "Time", ylab = NULL, ... )## S3 method for class 'dcm' plot( x, y = NULL, popfrac = FALSE, run = NULL, col = NULL, lwd = NULL, lty = NULL, alpha = 0.9, legend = NULL, leg.name = NULL, leg.cex = 0.8, grid = FALSE, add = FALSE, main = "", xlim = NULL, ylim = NULL, xlab = "Time", ylab = NULL, ... )
x |
An |
y |
Output compartments or flows from |
popfrac |
If |
run |
Run number to plot, for models with multiple runs (default is run 1). |
col |
Color for lines, either specified as a single color in a standard R color format, or alternatively as a color palette from RColorBrewer::RColorBrewer (see details). |
lwd |
Line width for output lines. |
lty |
Line type for output lines. |
alpha |
Transparency level for lines, where 0 = transparent and
1 = opaque (see |
legend |
Type of legend to plot. Values are |
leg.name |
Character string to use for legend, with the default
determined automatically based on the |
leg.cex |
Legend scale size. |
grid |
If |
add |
If |
main |
a main title for the plot, see also |
xlim |
the x limits (x1, x2) of the plot. Note that The default value, |
ylim |
The y limits (y1, y2) of the plot. The default, |
xlab |
a label for the x axis, defaults to a description of |
ylab |
a label for the y axis, defaults to a description of |
... |
Additional arguments to pass to main plot window (see
|
This function plots epidemiological outcomes from a deterministic
compartmental model solved with dcm(). Depending on the number of
model runs (sensitivity analyses) and number of groups, the default plot is
the fractional proportion of each compartment in the model over time. The
specific compartments or flows to plot may be set using the y
parameter, and in multiple run models the specific run may also be specified.
popfrac ArgumentCompartment prevalence is the size of a compartment over some denominator.
To plot the raw numbers from any compartment, use popfrac=FALSE; this
is the default. The popfrac parameter calculates
and plots the denominators of all specified compartments using these rules:
for one-group models, the prevalence of any compartment is the compartment size divided by the total population size; 2) for two-group models, the prevalence of any compartment is the compartment size divided by the group size.
Since dcm() supports multiple run sensitivity models, plotting
the results of such models uses a complex color scheme for distinguishing
runs. This is accomplished using the RColorBrewer::RColorBrewer color
palettes, which include a range of linked colors using named palettes. For
plot.dcm, one may either specify a brewer color palette listed in
RColorBrewer::brewer.pal.info, or, alternatively, a vector of standard R
colors (named, hexidecimal, or positive integers; see col2rgb()).
There are three automatic legend types available, and the legend is
added by default for plots. To turn off the legend, use legend="n". To
plot a legend with values for every line in a sensitivity analysis, use
legend="full". With models with many runs, this may be visually
overwhelming. In those cases, use legend="lim" to plot a legend
limited to the highest and lowest values of the varying parameter in the
model. In cases where the default legend names are not helpful, one may
override those names with the leg.name argument.
dcm(), RColorBrewer::brewer.pal.info
# Deterministic SIR model with varying act rate param <- param.dcm(inf.prob = 0.2, act.rate = 1:10, rec.rate = 1/3, a.rate = 0.011, ds.rate = 0.01, di.rate = 0.03, dr.rate = 0.01) init <- init.dcm(s.num = 1000, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 100, dt = 0.25) mod <- dcm(param, init, control) # Plot disease prevalence by default plot(mod) # Plot prevalence of susceptibles plot(mod, y = "s.num", popfrac = TRUE, col = "Greys") # Plot number of susceptibles plot(mod, y = "s.num", popfrac = FALSE, col = "Greys", grid = TRUE) # Plot multiple runs of multiple compartments together plot(mod, y = c("s.num", "i.num"), run = 5, xlim = c(0, 50), grid = TRUE) plot(mod, y = c("s.num", "i.num"), run = 10, lty = 2, legend = "n", add = TRUE)# Deterministic SIR model with varying act rate param <- param.dcm(inf.prob = 0.2, act.rate = 1:10, rec.rate = 1/3, a.rate = 0.011, ds.rate = 0.01, di.rate = 0.03, dr.rate = 0.01) init <- init.dcm(s.num = 1000, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 100, dt = 0.25) mod <- dcm(param, init, control) # Plot disease prevalence by default plot(mod) # Plot prevalence of susceptibles plot(mod, y = "s.num", popfrac = TRUE, col = "Greys") # Plot number of susceptibles plot(mod, y = "s.num", popfrac = FALSE, col = "Greys", grid = TRUE) # Plot multiple runs of multiple compartments together plot(mod, y = c("s.num", "i.num"), run = 5, xlim = c(0, 50), grid = TRUE) plot(mod, y = c("s.num", "i.num"), run = 10, lty = 2, legend = "n", add = TRUE)
This function is a wrapper around plot.netsim accepting a
data.frame obtain with as.data.frame(netsim_object).
## S3 method for class 'epi.data.frame' plot( x, y = NULL, sims = NULL, legend = NULL, mean.col = NULL, qnts.col = NULL, sim.lwd = NULL, sim.col = NULL, sim.alpha = NULL, popfrac = FALSE, qnts = 0.5, qnts.alpha = 0.5, qnts.smooth = TRUE, mean.line = TRUE, mean.smooth = TRUE, add = FALSE, mean.lwd = 2, mean.lty = 1, xlim = NULL, ylim = NULL, main = NULL, xlab = NULL, ylab = NULL, sim.lines = FALSE, grid = FALSE, leg.cex = 0.8, ... )## S3 method for class 'epi.data.frame' plot( x, y = NULL, sims = NULL, legend = NULL, mean.col = NULL, qnts.col = NULL, sim.lwd = NULL, sim.col = NULL, sim.alpha = NULL, popfrac = FALSE, qnts = 0.5, qnts.alpha = 0.5, qnts.smooth = TRUE, mean.line = TRUE, mean.smooth = TRUE, add = FALSE, mean.lwd = 2, mean.lty = 1, xlim = NULL, ylim = NULL, main = NULL, xlab = NULL, ylab = NULL, sim.lines = FALSE, grid = FALSE, leg.cex = 0.8, ... )
x |
A |
y |
Output compartments or flows from |
sims |
If |
legend |
If |
mean.col |
Vector of any standard R color format for mean lines. |
qnts.col |
Vector of any standard R color format for polygons. |
sim.lwd |
Line width for simulation lines. |
sim.col |
Vector of any standard R color format for simulation lines. |
sim.alpha |
Transparency level for simulation lines, where
0 = transparent and 1 = opaque (see |
popfrac |
If |
qnts |
If numeric, plot polygon of simulation quantiles based on the
range implied by the argument (see details). If |
qnts.alpha |
Transparency level for quantile polygons, where 0 =
transparent and 1 = opaque (see |
qnts.smooth |
If |
mean.line |
If |
mean.smooth |
If |
add |
If |
mean.lwd |
Line width for mean lines. |
mean.lty |
Line type for mean lines. |
xlim |
the x limits (x1, x2) of the plot. Note that The default value, |
ylim |
The y limits (y1, y2) of the plot. The default, |
main |
a main title for the plot, see also |
xlab |
a label for the x axis, defaults to a description of |
ylab |
a label for the y axis, defaults to a description of |
sim.lines |
If |
grid |
If |
leg.cex |
Legend scale size. |
... |
Additional arguments to pass. |
Plots epidemiological data from a stochastic individual contact
model simulated with icm().
## S3 method for class 'icm' plot( x, y = NULL, popfrac = FALSE, sim.lines = FALSE, sims = NULL, sim.col = NULL, sim.lwd = NULL, sim.alpha = NULL, mean.line = TRUE, mean.smooth = TRUE, mean.col = NULL, mean.lwd = 2, mean.lty = 1, qnts = 0.5, qnts.col = NULL, qnts.alpha = 0.5, qnts.smooth = TRUE, legend = NULL, leg.cex = 0.8, grid = FALSE, add = FALSE, xlim = NULL, ylim = NULL, main = "", xlab = "Time", ylab = NULL, ... )## S3 method for class 'icm' plot( x, y = NULL, popfrac = FALSE, sim.lines = FALSE, sims = NULL, sim.col = NULL, sim.lwd = NULL, sim.alpha = NULL, mean.line = TRUE, mean.smooth = TRUE, mean.col = NULL, mean.lwd = 2, mean.lty = 1, qnts = 0.5, qnts.col = NULL, qnts.alpha = 0.5, qnts.smooth = TRUE, legend = NULL, leg.cex = 0.8, grid = FALSE, add = FALSE, xlim = NULL, ylim = NULL, main = "", xlab = "Time", ylab = NULL, ... )
x |
An |
y |
Output compartments or flows from |
popfrac |
If |
sim.lines |
If |
sims |
A vector of simulation numbers to plot. The plot then describes those simulations alone: the mean line and quantile bands are calculated over them, not over the full set. |
sim.col |
Vector of any standard R color format for simulation lines. |
sim.lwd |
Line width for simulation lines. |
sim.alpha |
Transparency level for simulation lines, where
0 = transparent and 1 = opaque (see |
mean.line |
If |
mean.smooth |
If |
mean.col |
Vector of any standard R color format for mean lines. |
mean.lwd |
Line width for mean lines. |
mean.lty |
Line type for mean lines. |
qnts |
If numeric, plot polygon of simulation quantiles based on the
range implied by the argument (see details). If |
qnts.col |
Vector of any standard R color format for polygons. |
qnts.alpha |
Transparency level for quantile polygons, where 0 =
transparent and 1 = opaque (see |
qnts.smooth |
If |
legend |
If |
leg.cex |
Legend scale size. |
grid |
If |
add |
If |
xlim |
the x limits (x1, x2) of the plot. Note that The default value, |
ylim |
The y limits (y1, y2) of the plot. The default, |
main |
a main title for the plot, see also |
xlab |
a label for the x axis, defaults to a description of |
ylab |
a label for the y axis, defaults to a description of |
... |
Additional arguments to pass. |
This plotting function will extract the epidemiological output from a model
object of class icm and plot the time series data of disease
prevalence and other results. The summary statistics that the function
calculates and plots are individual simulation lines, means of the individual
simulation lines, and quantiles of those individual simulation lines. The
mean line, toggled on with mean.line=TRUE, is calculated as the row
mean across simulations at each time step.
Compartment prevalences are the size of a compartment over some denominator.
To plot the raw numbers from any compartment, use popfrac=FALSE; this
is the default for any plots of flows. The popfrac parameter
calculates and plots the denominators of all specified compartments using
these rules: 1) for one-group models, the prevalence of any compartment is
the compartment size divided by the total population size; 2) for two-group
models, the prevalence of any compartment is the compartment size divided by
the group population size. For any prevalences that are not automatically
calculated, the mutate_epi() function may be used to add new
variables to the icm object to plot or analyze.
The quantiles show the range of outcome values within a certain specified
quantile range. By default, the interquartile range is shown: that is the
middle 50\
middle 95\
where they are plotted by default, specify qnts=FALSE.
## Example 1: Plotting multiple compartment values from SIR model param <- param.icm(inf.prob = 0.5, act.rate = 0.5, rec.rate = 0.02) init <- init.icm(s.num = 500, i.num = 1, r.num = 0) control <- control.icm(type = "SIR", nsteps = 100, nsims = 3, verbose = FALSE) mod <- icm(param, init, control) plot(mod, grid = TRUE) ## Example 2: Plot only infected with specific output from SI model param <- param.icm(inf.prob = 0.25, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 10) control <- control.icm(type = "SI", nsteps = 100, nsims = 3, verbose = FALSE) mod2 <- icm(param, init, control) # Plot prevalence plot(mod2, y = "i.num", mean.line = FALSE, sim.lines = TRUE) # Plot incidence oldpar <- par(mfrow = c(1, 2)) plot(mod2, y = "si.flow", mean.smooth = TRUE, grid = TRUE) plot(mod2, y = "si.flow", qnts.smooth = FALSE, qnts = 1) par(oldpar)## Example 1: Plotting multiple compartment values from SIR model param <- param.icm(inf.prob = 0.5, act.rate = 0.5, rec.rate = 0.02) init <- init.icm(s.num = 500, i.num = 1, r.num = 0) control <- control.icm(type = "SIR", nsteps = 100, nsims = 3, verbose = FALSE) mod <- icm(param, init, control) plot(mod, grid = TRUE) ## Example 2: Plot only infected with specific output from SI model param <- param.icm(inf.prob = 0.25, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 10) control <- control.icm(type = "SI", nsteps = 100, nsims = 3, verbose = FALSE) mod2 <- icm(param, init, control) # Plot prevalence plot(mod2, y = "i.num", mean.line = FALSE, sim.lines = TRUE) # Plot incidence oldpar <- par(mfrow = c(1, 2)) plot(mod2, y = "si.flow", mean.smooth = TRUE, grid = TRUE) plot(mod2, y = "si.flow", qnts.smooth = FALSE, qnts = 1) par(oldpar)
Plots dynamic network model diagnostics calculated in
netdx().
## S3 method for class 'netdx' plot( x, type = "formation", method = "l", sims = NULL, stats = NULL, duration.imputed = TRUE, sim.lines = FALSE, sim.col = NULL, sim.lwd = NULL, mean.line = TRUE, mean.smooth = TRUE, mean.col = NULL, mean.lwd = 2, mean.lty = 1, qnts = 0.5, qnts.col = NULL, qnts.alpha = 0.5, qnts.smooth = TRUE, targ.line = TRUE, targ.col = NULL, targ.lwd = 2, targ.lty = 2, plots.joined = NULL, legend = NULL, grid = FALSE, xlim = NULL, xlab = NULL, ylim = NULL, ylab = NULL, momentary = FALSE, window = NULL, maxdeg = NULL, unique.partners = TRUE, ... )## S3 method for class 'netdx' plot( x, type = "formation", method = "l", sims = NULL, stats = NULL, duration.imputed = TRUE, sim.lines = FALSE, sim.col = NULL, sim.lwd = NULL, mean.line = TRUE, mean.smooth = TRUE, mean.col = NULL, mean.lwd = 2, mean.lty = 1, qnts = 0.5, qnts.col = NULL, qnts.alpha = 0.5, qnts.smooth = TRUE, targ.line = TRUE, targ.col = NULL, targ.lwd = 2, targ.lty = 2, plots.joined = NULL, legend = NULL, grid = FALSE, xlim = NULL, xlab = NULL, ylim = NULL, ylab = NULL, momentary = FALSE, window = NULL, maxdeg = NULL, unique.partners = TRUE, ... )
x |
An |
type |
Plot type, with options of |
method |
Plot method, with options of |
sims |
A vector of simulation numbers to plot. |
stats |
Statistics to plot. For |
duration.imputed |
If |
sim.lines |
If |
sim.col |
Vector of any standard R color format for simulation lines. |
sim.lwd |
Line width for simulation lines. |
mean.line |
If |
mean.smooth |
If |
mean.col |
Vector of any standard R color format for mean lines. |
mean.lwd |
Line width for mean lines. |
mean.lty |
Line type for mean lines. |
qnts |
If numeric, plot polygon of simulation quantiles based on the
range implied by the argument (see details). If |
qnts.col |
Vector of any standard R color format for polygons. |
qnts.alpha |
Transparency level for quantile polygons, where 0 =
transparent and 1 = opaque (see |
qnts.smooth |
If |
targ.line |
If |
targ.col |
Vector of standard R colors for target statistic lines, with
default colors based on |
targ.lwd |
Line width for the line showing the target statistic values. |
targ.lty |
Line type for the line showing the target statistic values. |
plots.joined |
If |
legend |
If |
grid |
If |
xlim |
the x limits (x1, x2) of the plot. Note that The default value, |
xlab |
a label for the x axis, defaults to a description of |
ylim |
The y limits (y1, y2) of the plot. The default, |
ylab |
a label for the y axis, defaults to a description of |
momentary |
If |
window |
A vector of length 2 giving the first and last time step over
which degrees are counted, with the default of the full simulation.
Used only when |
maxdeg |
Highest degree to show on the x-axis, with degrees above it
collapsed into a final |
unique.partners |
If |
... |
Additional arguments to pass. |
The plot function for netdx objects will generate plots of two types
of model diagnostic statistics that run as part of the diagnostic tools
within that function. The formation plot shows the summary statistics
requested in nwstats.formula, where the default includes those
statistics in the network model formation formula specified in the original
call to netest().
The duration plot shows the average age of existing edges at each time
step, up until the maximum time step requested. The age is used as an
estimator of the average duration of edges in the equilibrium state. When
duration.imputed = FALSE, edges that exist at the beginning of the
simulation are assumed to start with an age of 1, yielding a burn-in period
before the observed mean approaches its target. When
duration.imputed = TRUE, expected ages prior to the start of the
simulation are calculated from the dissolution model, typically eliminating
the need for a burn-in period.
The dissolution plot shows the proportion of the extant ties that are
dissolved at each time step, up until the maximum time step requested.
Typically, the proportion of ties that are dissolved is the reciprocal of the
mean relational duration. This plot thus contains similar information to that
in the duration plot, but should reach its expected value more quickly, since
it is not subject to censoring.
The plots.joined argument will control whether the statistics
are joined in one plot or plotted separately, assuming there are multiple
statistics in the model. The default is based on the number of network
statistics requested. The layout of the separate plots within the larger plot
window is also based on the number of statistics.
The cumldeg plot shows the cumulative degree distribution: the proportion
of nodes with each count of partners accumulated over the simulation, rather
than the count held at one point in time. It requires a netdx object run
with keep.tedgelist = TRUE, since it is calculated from the timed edgelist
with get_degree_dist(). Setting momentary = TRUE adds the momentary
degree distribution over the same window, calculated from the same edgelist,
which is the distribution summarized by the degree(k) terms of the
formation plot. Two models with the same mean degree and mean partnership
duration have the same mean cumulative degree even when their momentary
degree distributions differ, as the example below shows for models with high
and low concurrency. Legend entries report the mean of each distribution.
Because the cumulative degree grows with the length of the observation
window, use window to restrict it to a substantively meaningful period
when comparing across models. The lines or bars show the mean across
simulations, with qnts giving the inter-simulation quantile band; the
targ.line, mean.smooth, qnts.smooth, and plots.joined arguments do
not apply to this plot type.
netdx(), and get_degree_dist() for the degree distributions
behind type = "cumldeg".
## Not run: # Network initialization and model parameterization nw <- network_initialize(n = 500) nw <- set_vertex_attribute(nw, "sex", rbinom(500, 1, 0.5)) formation <- ~edges + nodematch("sex") target.stats <- c(500, 300) coef.diss <- dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("sex")), duration = c(50, 40)) # Estimate the model est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Static diagnostics dx1 <- netdx(est, nsims = 1e4, dynamic = FALSE, nwstats.formula = ~edges + meandeg + concurrent + nodefactor("sex", levels = NULL) + nodematch("sex")) dx1 # Plot diagnostics plot(dx1) plot(dx1, stats = c("edges", "concurrent"), mean.col = "black", sim.lines = TRUE, plots.joined = FALSE) plot(dx1, stats = "edges", method = "b", col = "seagreen3", grid = TRUE) # Dynamic diagnostics dx2 <- netdx(est, nsims = 10, nsteps = 500, nwstats.formula = ~edges + meandeg + concurrent + nodefactor("sex", levels = NULL) + nodematch("sex")) dx2 # Formation statistics plots, joined and separate plot(dx2, grid = TRUE) plot(dx2, type = "formation", plots.joined = TRUE) plot(dx2, type = "formation", sims = 1, plots.joined = TRUE, qnts = FALSE, sim.lines = TRUE, mean.line = FALSE) plot(dx2, type = "formation", plots.joined = FALSE, stats = c("edges", "concurrent"), grid = TRUE) plot(dx2, method = "b", col = "bisque", grid = TRUE) plot(dx2, method = "b", stats = "meandeg", col = "dodgerblue") # Duration statistics plot oldpar <- par(mfrow = c(1, 2)) # With duration imputed plot(dx2, type = "duration", sim.line = TRUE, sim.lwd = 0.3, targ.lty = 1, targ.lwd = 0.5) # Without duration imputed plot(dx2, type = "duration", sim.line = TRUE, sim.lwd = 0.3, targ.lty = 1, targ.lwd = 0.5, duration.imputed = FALSE) # Dissolution statistics plot plot(dx2, type = "dissolution", qnts = 0.25, grid = TRUE) plot(dx2, type = "dissolution", method = "b", col = "pink1") # Cumulative degree distribution: two models with the same mean degree and # the same mean partnership duration, differing only in how much # concurrency (overlapping partnerships) they allow nw <- network_initialize(n = 500) coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 25) est.hi <- netest(nw, formation = ~edges + concurrent, target.stats = c(200, 150), coef.diss = coef.diss, verbose = FALSE) est.lo <- netest(nw, formation = ~edges + concurrent, target.stats = c(200, 40), coef.diss = coef.diss, verbose = FALSE) dx.hi <- netdx(est.hi, nsims = 5, nsteps = 250, keep.tedgelist = TRUE, nwstats.formula = ~edges + concurrent + degree(0:3)) dx.lo <- netdx(est.lo, nsims = 5, nsteps = 250, keep.tedgelist = TRUE, nwstats.formula = ~edges + concurrent + degree(0:3)) # The momentary degree distributions are far apart: about half the nodes in # the high-concurrency model have no partner at any given time and a quarter # have two, while most nodes in the low-concurrency model have exactly one. # Over 250 time steps both accumulate about 8.5 partners per node. par(mfrow = c(1, 2)) plot(dx.hi, type = "cumldeg", momentary = TRUE, xlim = c(0, 25), main = "High concurrency") plot(dx.lo, type = "cumldeg", momentary = TRUE, xlim = c(0, 25), main = "Low concurrency") # As bars, with the tail of the distribution collapsed into one category # and the inter-simulation range shown par(oldpar) plot(dx.hi, type = "cumldeg", method = "b", maxdeg = 15, qnts = 0.95) # Partners accumulated over the last 100 steps only plot(dx.hi, type = "cumldeg", window = c(150, 250), momentary = TRUE) # The plotted distributions are returned invisibly dd <- plot(dx.hi, type = "cumldeg") tapply(dd$degree * dd$prop, dd$sim, sum) ## End(Not run)## Not run: # Network initialization and model parameterization nw <- network_initialize(n = 500) nw <- set_vertex_attribute(nw, "sex", rbinom(500, 1, 0.5)) formation <- ~edges + nodematch("sex") target.stats <- c(500, 300) coef.diss <- dissolution_coefs(dissolution = ~offset(edges) + offset(nodematch("sex")), duration = c(50, 40)) # Estimate the model est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Static diagnostics dx1 <- netdx(est, nsims = 1e4, dynamic = FALSE, nwstats.formula = ~edges + meandeg + concurrent + nodefactor("sex", levels = NULL) + nodematch("sex")) dx1 # Plot diagnostics plot(dx1) plot(dx1, stats = c("edges", "concurrent"), mean.col = "black", sim.lines = TRUE, plots.joined = FALSE) plot(dx1, stats = "edges", method = "b", col = "seagreen3", grid = TRUE) # Dynamic diagnostics dx2 <- netdx(est, nsims = 10, nsteps = 500, nwstats.formula = ~edges + meandeg + concurrent + nodefactor("sex", levels = NULL) + nodematch("sex")) dx2 # Formation statistics plots, joined and separate plot(dx2, grid = TRUE) plot(dx2, type = "formation", plots.joined = TRUE) plot(dx2, type = "formation", sims = 1, plots.joined = TRUE, qnts = FALSE, sim.lines = TRUE, mean.line = FALSE) plot(dx2, type = "formation", plots.joined = FALSE, stats = c("edges", "concurrent"), grid = TRUE) plot(dx2, method = "b", col = "bisque", grid = TRUE) plot(dx2, method = "b", stats = "meandeg", col = "dodgerblue") # Duration statistics plot oldpar <- par(mfrow = c(1, 2)) # With duration imputed plot(dx2, type = "duration", sim.line = TRUE, sim.lwd = 0.3, targ.lty = 1, targ.lwd = 0.5) # Without duration imputed plot(dx2, type = "duration", sim.line = TRUE, sim.lwd = 0.3, targ.lty = 1, targ.lwd = 0.5, duration.imputed = FALSE) # Dissolution statistics plot plot(dx2, type = "dissolution", qnts = 0.25, grid = TRUE) plot(dx2, type = "dissolution", method = "b", col = "pink1") # Cumulative degree distribution: two models with the same mean degree and # the same mean partnership duration, differing only in how much # concurrency (overlapping partnerships) they allow nw <- network_initialize(n = 500) coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 25) est.hi <- netest(nw, formation = ~edges + concurrent, target.stats = c(200, 150), coef.diss = coef.diss, verbose = FALSE) est.lo <- netest(nw, formation = ~edges + concurrent, target.stats = c(200, 40), coef.diss = coef.diss, verbose = FALSE) dx.hi <- netdx(est.hi, nsims = 5, nsteps = 250, keep.tedgelist = TRUE, nwstats.formula = ~edges + concurrent + degree(0:3)) dx.lo <- netdx(est.lo, nsims = 5, nsteps = 250, keep.tedgelist = TRUE, nwstats.formula = ~edges + concurrent + degree(0:3)) # The momentary degree distributions are far apart: about half the nodes in # the high-concurrency model have no partner at any given time and a quarter # have two, while most nodes in the low-concurrency model have exactly one. # Over 250 time steps both accumulate about 8.5 partners per node. par(mfrow = c(1, 2)) plot(dx.hi, type = "cumldeg", momentary = TRUE, xlim = c(0, 25), main = "High concurrency") plot(dx.lo, type = "cumldeg", momentary = TRUE, xlim = c(0, 25), main = "Low concurrency") # As bars, with the tail of the distribution collapsed into one category # and the inter-simulation range shown par(oldpar) plot(dx.hi, type = "cumldeg", method = "b", maxdeg = 15, qnts = 0.95) # Partners accumulated over the last 100 steps only plot(dx.hi, type = "cumldeg", window = c(150, 250), momentary = TRUE) # The plotted distributions are returned invisibly dd <- plot(dx.hi, type = "cumldeg") tapply(dd$degree * dd$prop, dd$sim, sum) ## End(Not run)
Plots epidemiological and network data from a stochastic network
model simulated with netsim().
## S3 method for class 'netsim' plot( x, type = "epi", y = NULL, popfrac = FALSE, sim.lines = FALSE, sims = NULL, sim.col = NULL, sim.lwd = NULL, sim.alpha = NULL, mean.line = TRUE, mean.smooth = TRUE, mean.col = NULL, mean.lwd = 2, mean.lty = 1, qnts = 0.5, qnts.col = NULL, qnts.alpha = 0.5, qnts.smooth = TRUE, legend = NULL, leg.cex = 0.8, grid = FALSE, add = FALSE, network = 1, at = 1, col.status = FALSE, shp.g2 = NULL, vertex.cex = NULL, stats = NULL, targ.line = TRUE, targ.col = NULL, targ.lwd = 2, targ.lty = 2, plots.joined = NULL, duration.imputed = TRUE, method = "l", main = NULL, xlim = NULL, xlab = NULL, ylim = NULL, ylab = NULL, ... )## S3 method for class 'netsim' plot( x, type = "epi", y = NULL, popfrac = FALSE, sim.lines = FALSE, sims = NULL, sim.col = NULL, sim.lwd = NULL, sim.alpha = NULL, mean.line = TRUE, mean.smooth = TRUE, mean.col = NULL, mean.lwd = 2, mean.lty = 1, qnts = 0.5, qnts.col = NULL, qnts.alpha = 0.5, qnts.smooth = TRUE, legend = NULL, leg.cex = 0.8, grid = FALSE, add = FALSE, network = 1, at = 1, col.status = FALSE, shp.g2 = NULL, vertex.cex = NULL, stats = NULL, targ.line = TRUE, targ.col = NULL, targ.lwd = 2, targ.lty = 2, plots.joined = NULL, duration.imputed = TRUE, method = "l", main = NULL, xlim = NULL, xlab = NULL, ylim = NULL, ylab = NULL, ... )
x |
An |
type |
Type of plot: |
y |
Output compartments or flows from |
popfrac |
If |
sim.lines |
If |
sims |
If |
sim.col |
Vector of any standard R color format for simulation lines. |
sim.lwd |
Line width for simulation lines. |
sim.alpha |
Transparency level for simulation lines, where
0 = transparent and 1 = opaque (see |
mean.line |
If |
mean.smooth |
If |
mean.col |
Vector of any standard R color format for mean lines. |
mean.lwd |
Line width for mean lines. |
mean.lty |
Line type for mean lines. |
qnts |
If numeric, plot polygon of simulation quantiles based on the
range implied by the argument (see details). If |
qnts.col |
Vector of any standard R color format for polygons. |
qnts.alpha |
Transparency level for quantile polygons, where 0 =
transparent and 1 = opaque (see |
qnts.smooth |
If |
legend |
If |
leg.cex |
Legend scale size. |
grid |
If |
add |
If |
network |
Network number, for simulations with multiple networks representing the population. |
at |
If |
col.status |
If |
shp.g2 |
If |
vertex.cex |
Relative size of plotted vertices if |
stats |
If |
targ.line |
If |
targ.col |
Vector of standard R colors for target statistic lines, with
default colors based on |
targ.lwd |
Line width for the line showing the target statistic values. |
targ.lty |
Line type for the line showing the target statistic values. |
plots.joined |
If |
duration.imputed |
If |
method |
Plot method for |
main |
a main title for the plot, see also |
xlim |
the x limits (x1, x2) of the plot. Note that The default value, |
xlab |
a label for the x axis, defaults to a description of |
ylim |
The y limits (y1, y2) of the plot. The default, |
ylab |
a label for the y axis, defaults to a description of |
... |
Additional arguments to pass. |
This plot function can produce three types of plots with a stochastic network
model simulated through netsim():
type="epi": epidemic model results (e.g., disease
prevalence and incidence) may be plotted.
type="network": a static network plot will be
generated. A static network plot of a dynamic network is a
cross-sectional extraction of that dynamic network at a specific
time point. This plotting function wraps the
network::plot.network function in the network package.
Consult the help page for plot.network for all of the plotting
parameters. In addition, four plotting parameters specific to
netsim plots are available: sim, at,
col.status, and shp.g2.
type="formation": summary network statistics related
to the network model formation are plotted. These plots are similar
to the formation plots for netdx objects. When running a
netsim simulation, one must specify there that
save.nwstats=TRUE; the plot here will then show the network
statistics requested explicitly in nwstats.formula, or will use
the formation formula set in netest otherwise.
type="duration","dissolution": as in
plot.netdx(); supported in plot.netsim only when
the dissolution model is ~offset(edges), tergmLite is
FALSE, and save.network is TRUE.
When type="epi", this plotting function will extract the
epidemiological output from a model object of class netsim and plot
the time series data of disease prevalence and other results. The summary
statistics that the function calculates and plots are individual simulation
lines, means of the individual simulation lines, and quantiles of those
individual simulation lines. The mean line, toggled on with
mean.line=TRUE, is calculated as the row mean across simulations at
each time step.
Compartment prevalences are the size of a compartment over some denominator.
To plot the raw numbers from any compartment, use popfrac=FALSE; this
is the default for any plots of flows. The popfrac parameter
calculates and plots the denominators of all specified compartments using
these rules: 1) for one-group models, the prevalence of any compartment is
the compartment size divided by the total population size; 2) for two-group
models, the prevalence of any compartment is the compartment size divided by
the group population size. For any prevalences that are not automatically
calculated, the mutate_epi() function may be used to add new
variables to the netsim object to plot or analyze.
The quantiles show the range of outcome values within a certain specified
quantile range. By default, the interquartile range is shown: that is the
middle 50% of the data. This is specified by qnts=0.5. To show the
middle 95% of the data, specify qnts=0.95. To toggle off the polygons
where they are plotted by default, specify qnts=FALSE.
When type="network", this function will plot cross sections of the
simulated networks at specified time steps. Because it is only possible to
plot one time step from one simulation at a time, it is necessary to enter
these in the at and sims parameters. To aid in visualizing
representative and extreme simulations at specific time steps, the
sims parameter may be set to "mean" to plot the simulation in
which the disease prevalence is closest to the average across all
simulations, "min" to plot the simulation in which the prevalence is
lowest, and "max" to plot the simulation in which the prevalence is
highest.
network::plot.network, mutate_epi()
## SI Model without Network Feedback # Initialize network and set network model parameters nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Estimate the network model est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Simulate the epidemic model param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 20, nsims = 3, verbose = FALSE, save.nwstats = TRUE, nwstats.formula = ~edges + meandeg + concurrent) mod <- netsim(est, param, init, control) # Plot epidemic trajectory plot(mod) plot(mod, type = "epi", grid = TRUE) plot(mod, type = "epi", popfrac = TRUE) plot(mod, type = "epi", y = "si.flow", qnts = 1, ylim = c(0, 4)) # Plot static networks oldpar <- par(no.readonly = TRUE) par(mar = c(0, 0, 0, 0)) plot(mod, type = "network", vertex.cex = 1.5) # Automatic coloring of infected nodes as red par(mfrow = c(1, 2), mar = c(0, 0, 2, 0)) plot(mod, type = "network", main = "Min Prev | Time 20", col.status = TRUE, at = 20, sims = "min", vertex.cex = 1.25) plot(mod, type = "network", main = "Max Prev | Time 20", col.status = TRUE, at = 20, sims = "max", vertex.cex = 1.25) # Automatic shape by group number (circle = group 1) par(mar = c(0, 0, 0, 0)) plot(mod, type = "network", at = 20, col.status = TRUE, shp.g2 = "square") plot(mod, type = "network", at = 20, col.status = TRUE, shp.g2 = "triangle", vertex.cex = 2) # Plot formation statistics par(mfrow = c(1,1), mar = c(3,3,1,1), mgp = c(2,1,0)) plot(mod, type = "formation", grid = TRUE) plot(mod, type = "formation", plots.joined = FALSE) plot(mod, type = "formation", sims = 2:3) plot(mod, type = "formation", plots.joined = FALSE, stats = c("edges", "concurrent")) plot(mod, type = "formation", stats = "meandeg", mean.lwd = 1, qnts.col = "seagreen", mean.col = "black") par(oldpar)## SI Model without Network Feedback # Initialize network and set network model parameters nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Estimate the network model est <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Simulate the epidemic model param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 20, nsims = 3, verbose = FALSE, save.nwstats = TRUE, nwstats.formula = ~edges + meandeg + concurrent) mod <- netsim(est, param, init, control) # Plot epidemic trajectory plot(mod) plot(mod, type = "epi", grid = TRUE) plot(mod, type = "epi", popfrac = TRUE) plot(mod, type = "epi", y = "si.flow", qnts = 1, ylim = c(0, 4)) # Plot static networks oldpar <- par(no.readonly = TRUE) par(mar = c(0, 0, 0, 0)) plot(mod, type = "network", vertex.cex = 1.5) # Automatic coloring of infected nodes as red par(mfrow = c(1, 2), mar = c(0, 0, 2, 0)) plot(mod, type = "network", main = "Min Prev | Time 20", col.status = TRUE, at = 20, sims = "min", vertex.cex = 1.25) plot(mod, type = "network", main = "Max Prev | Time 20", col.status = TRUE, at = 20, sims = "max", vertex.cex = 1.25) # Automatic shape by group number (circle = group 1) par(mar = c(0, 0, 0, 0)) plot(mod, type = "network", at = 20, col.status = TRUE, shp.g2 = "square") plot(mod, type = "network", at = 20, col.status = TRUE, shp.g2 = "triangle", vertex.cex = 2) # Plot formation statistics par(mfrow = c(1,1), mar = c(3,3,1,1), mgp = c(2,1,0)) plot(mod, type = "formation", grid = TRUE) plot(mod, type = "formation", plots.joined = FALSE) plot(mod, type = "formation", sims = 2:3) plot(mod, type = "formation", plots.joined = FALSE, stats = c("edges", "concurrent")) plot(mod, type = "formation", stats = "meandeg", mean.lwd = 1, qnts.col = "seagreen", mean.col = "black") par(oldpar)
Plots the transmission matrix tree from from get_transmat
in one of three styles: a phylogram, a directed network, or
a transmission timeline.
## S3 method for class 'transmat' plot(x, style = c("phylo", "network", "transmissionTimeline"), ...)## S3 method for class 'transmat' plot(x, style = c("phylo", "network", "transmissionTimeline"), ...)
x |
A |
style |
Character name of plot style. One of |
... |
Additional plot arguments to be passed to lower-level plot
functions ( |
The phylo plot requires the ape package. The
transmissionTimeline plot requires that the ndtv package.
network::plot.network, ape::plot.phylo(),
ndtv::transmissionTimeline().
Prints a summary of a deterministic compartmental model object, including the model type, number of runs, time steps, model parameters, and output variable names.
## S3 method for class 'dcm' print(x, ...)## S3 method for class 'dcm' print(x, ...)
x |
An object of class |
... |
Additional arguments (currently ignored). |
Given a dcm object, print.dcm displays:
Simulation summary: model class, model type (e.g., SI, SIR, SIS; omitted for new/custom models), number of runs, number of time steps, and number of groups.
Model parameters: all parameters passed via param.dcm(), excluding
internal bookkeeping parameters (groups, vital).
Model output: the names of all epidemic output variables stored in the model.
Prints a summary of a stochastic individual contact model object, including the model type, number of simulations, time steps, model parameters, and output variable names.
## S3 method for class 'icm' print(x, ...)## S3 method for class 'icm' print(x, ...)
x |
An object of class |
... |
Additional arguments (currently ignored). |
Given an icm object, print.icm displays:
Simulation summary: model class, model type (e.g., SI, SIR, SIS), number of simulations, number of time steps, and number of groups.
Model parameters: all parameters passed via param.icm(), excluding
internal bookkeeping parameters (groups, vital).
Model output: the names of all epidemic output variables stored in the model.
Prints basic information and statistics from a netdx
object.
## S3 method for class 'netdx' print(x, digits = 3, ...)## S3 method for class 'netdx' print(x, digits = 3, ...)
x |
an object of class |
digits |
number of digits to print in statistics tables |
... |
additional arguments (currently ignored) |
Given a netdx object, print.netdx prints the diagnostic method
(static/dynamic), number of simulations, and (if dynamic) the number of time
steps per simulation used in generating the netdx object, as well as
printing the formation statistics table and (if present) the duration and
dissolution statistics tables. The statistics tables are interpreted as
follows.
Each row has the name of a particular network statistic. In the formation
table, these correspond to actual network statistics in the obvious way.
In the duration and dissolution tables, these correspond to dissolution
model dyad types: in a homogeneous dissolution model, all dyads are of the
edges type; in a heterogeneous dissolution model, a dyad with a
nonzero nodematch or nodemix change statistic in the
dissolution model has type equal to that statistic, and has type equal to
edges otherwise. The statistics of interest for the duration and
dissolution tables are, respectively, the mean age of extant edges and the
edge dissolution rate, broken down by dissolution model dyad type. (The
current convention is to treat the mean age and dissolution rate for a
particular dissolution dyad type as 0 on time steps with no edges of that
type; this behavior may be changed in the future.)
The columns are named Target, Sim Mean, Pct Diff,
Sim SE, Z Score, SD(Sim Means), and
SD(Statistic). The Sim Mean column refers to the mean
statistic value, across all time steps in all simulations in the dynamic
case, and across all sampled networks in all simulations in the static case.
The Sim SE column refers to the standard error in the mean, estimated
using coda::effectiveSize. The Target
column indicates the target value (if present) for the statistic, and the
Pct Diff column gives (Sim Mean - Target)/Target when
Target is present. The Z Score column gives
(Sim Mean - Target)/(Sim SE). The SD(Sim Means) column gives
the empirical standard deviation across simulations of the mean statistic
value within simulation, and SD(Statistic) gives the empirical
standard deviation of the statistic value across all the simulated data.
Prints a detailed summary of a stochastic network model simulation object, including simulation metadata, model parameters, output variables, and (optionally) network formation, duration, and dissolution statistics with target comparisons.
## S3 method for class 'netsim' print(x, nwstats = TRUE, digits = 3, network = 1, ...)## S3 method for class 'netsim' print(x, nwstats = TRUE, digits = 3, network = 1, ...)
x |
An object of class |
nwstats |
If |
digits |
Number of digits to print in the network statistics tables. |
network |
Integer index of the network for which to display statistics,
for multi-network models. Default is |
... |
Additional arguments (currently ignored). |
Given a netsim object, print.netsim displays the following sections:
Simulation summary: model class, model type (e.g., SI, SIR, SIS), number of simulations, number of time steps, and number of network groups.
Model parameters: printed via print.param.net().
Model functions: for extension models (type = NULL), lists the names
of all custom module functions.
Model output: the names of all epidemic output variables, saved network objects, transmission matrices, and any other saved elements.
Network statistics (when nwstats = TRUE and network statistics were
saved during the simulation):
The formation, duration, and dissolution statistics tables are computed and
displayed in the same way as for print.netdx(). Each table contains the
columns Target, Sim Mean, Pct Diff, Sim SE, Z Score,
SD(Sim Means), and SD(Statistic). The Sim Mean column is the mean
statistic value across all time steps and simulations. Sim SE is the
standard error estimated using coda::effectiveSize. Pct Diff gives
(Sim Mean - Target) / Target and Z Score gives
(Sim Mean - Target) / Sim SE when a target is available. SD(Sim Means)
is the standard deviation of per-simulation means, and SD(Statistic) is
the overall standard deviation of the statistic.
Formation statistics: each row corresponds to a network statistic from the
formation formula (e.g., edges, nodematch), compared against the target
statistics from network estimation. These statistics assess whether the
network structure is maintained at target levels during the epidemic
simulation (which is particularly important in open-population models where
demographic turnover can shift network structure).
Duration statistics: each row corresponds to a dissolution model dyad
type. In a homogeneous dissolution model (~offset(edges)), all dyads are
of the edges type. The statistic of interest is the mean age of extant
edges, compared against the target duration from dissolution_coefs().
Dissolution statistics: same row structure as the duration table. The
statistic of interest is the edge dissolution rate (proportion of edges
dissolving per time step), compared against 1 / target duration.
Duration and dissolution tables are only available when
control$save.diss.stats = TRUE, control$save.network = TRUE,
control$tergmLite = FALSE, and the dissolution formula is
~offset(edges). When these conditions are not met, a note listing the
requirements is printed instead.
netsim(), print.netdx(), summary.netsim().
These functions return the forward or backward reachable nodes of a set of
nodes in a network over a time period. Forward reachability answers "who
could a node have infected?"; backward reachability answers "who could
have infected this node?". Both operate on a cumulative edgelist, the
same structure produced by get_cumulative_edgelist() /
get_cumulative_edgelists_df() from a netsim run, or by
as_cumulative_edgelist() applied to an external networkDynamic
object.
Warning: these functions ignore nodes without edges in the period of
interest. See the Number of Nodes section for details. The distance
to each node can be back-calculated using the length of the reachable
set at each time step and the fact that the reachable sets are ordered
by the time to arrival. These functions are much faster than iterating
tsna::tPath().
get_forward_reachable( el_cuml, from_step, to_step, nodes = NULL, dense_optim = "auto" ) get_backward_reachable( el_cuml, from_step, to_step, nodes = NULL, dense_optim = "auto" )get_forward_reachable( el_cuml, from_step, to_step, nodes = NULL, dense_optim = "auto" ) get_backward_reachable( el_cuml, from_step, to_step, nodes = NULL, dense_optim = "auto" )
el_cuml |
a cumulative edgelist object. That is a data.frame with at least columns: head, tail, start and stop. Start and stop are inclusive. |
from_step |
the beginning of the time period. |
to_step |
the end of the time period. |
nodes |
the subset of nodes to calculate the FRP for. (default = NULL, all nodes) |
dense_optim |
pre-process the adjacency list to speed up the
computations on dense networks. "auto" (default), enable the
optimisation when |
A named list containing:
reached: the set of reachable nodes for each of the nodes.
lengths: A matrix of length(nodes) rows and one column per timestep + 1
with the length of the reachable set at each step from from_step - 1
to to_step. The first column is always one as the set of reachables
at the beginning is just the node itself.
To speed up the calculations and lower the memory usage, these functions
only take into account nodes with edges in the cumulative edgelist over the
period of interest. The nodes are identified in the reached and lengths
sublists by names (e.g. node_1093). Nodes without any edges are therefore
not calculated as the only node they reach is themselve (length of 1).
Take this fact into account when exploring the distribution of Forward
Reachable Paths for example. As the nodes with FRP == 1 are not in the
output.
These functions may be used to efficiently calculate multiple sets of
reachable nodes. As cumulative edgelists are way smaller than full
networkDynamic objects, theses functions are suited for large and dense
networks.
Also, as long as the size of the nodes set is greater than 5, theses
functions are faster than iterating over tsna::tPath.
get_cumulative_edgelist() / get_cumulative_edgelists_df()
for the typical input source from a netsim run;
as_cumulative_edgelist() to derive a cumulative edgelist from a
networkDynamic object; dedup_cumulative_edgelist() when the input
has been concatenated from multiple sources.
vignette("network-objects", package = "EpiModel") walks through the
full lifecycle.
Other cumulative_edgelist:
as_cumulative_edgelist(),
dedup_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelist(),
get_cumulative_edgelists_df(),
get_partners(),
update_cumulative_edgelist()
## Not run: # load a network dynamic object nd <- readRDS("nd_obj.Rds") # convert it to a cumulative edgelist el_cuml <- as_cumulative_edgelist(nd) # sample 100 node indexes nnodes <- max(el_cuml$head, el_cuml$tail) nodes <- sample(nnodes, 100) # `get_forward_reachable` uses steps [from_step, to_step] inclusive el_fwd <- get_forward_reachable(el_cuml, 1, 52, nodes)[["reached"]] # check if the results are consistent with `tsna::tPath` nodes <- strsplit(names(el_fwd), "_") for (i in seq_along(el_fwd)) { node <- as.integer(nodes[[i]][2]) t_fwd <- tsna::tPath( nd, v = node, start = 1, end = 52 + 1, # tPath works from [start, end) right exclusive direction = "fwd" ) t_fwd_set <- which(t_fwd$tdist < Inf) if(!setequal(el_fwd[[i]], t_fwd_set)) stop("Mismatch on node: ", node) } # Backward: el_bkwd <- get_backward_reachable(el_cuml, 1, 52, nodes = 1)[["reached"]] nodes <- strsplit(names(el_bkwd), "_") t_bkwd <- tsna::tPath( nd, v = as.integer(nodes[[1]][2]), start = 1, end = 52 + 1, direction = "bkwd", type = "latest.depart" ) t_bkwd_set <- which(t_bkwd$tdist < Inf) setequal(el_bkwd[[1]], t_bkwd_set) ## End(Not run)## Not run: # load a network dynamic object nd <- readRDS("nd_obj.Rds") # convert it to a cumulative edgelist el_cuml <- as_cumulative_edgelist(nd) # sample 100 node indexes nnodes <- max(el_cuml$head, el_cuml$tail) nodes <- sample(nnodes, 100) # `get_forward_reachable` uses steps [from_step, to_step] inclusive el_fwd <- get_forward_reachable(el_cuml, 1, 52, nodes)[["reached"]] # check if the results are consistent with `tsna::tPath` nodes <- strsplit(names(el_fwd), "_") for (i in seq_along(el_fwd)) { node <- as.integer(nodes[[i]][2]) t_fwd <- tsna::tPath( nd, v = node, start = 1, end = 52 + 1, # tPath works from [start, end) right exclusive direction = "fwd" ) t_fwd_set <- which(t_fwd$tdist < Inf) if(!setequal(el_fwd[[i]], t_fwd_set)) stop("Mismatch on node: ", node) } # Backward: el_bkwd <- get_backward_reachable(el_cuml, 1, 52, nodes = 1)[["reached"]] nodes <- strsplit(names(el_bkwd), "_") t_bkwd <- tsna::tPath( nd, v = as.integer(nodes[[1]][2]), start = 1, end = 52 + 1, direction = "bkwd", type = "latest.depart" ) t_bkwd_set <- which(t_bkwd$tdist < Inf) setequal(el_bkwd[[1]], t_bkwd_set) ## End(Not run)
Record values for a set of nodes at a specific time step. Records are stored
in dat[["attr.history"]] as a collections::queue and can be accessed
from the netsim object with get_attr_history.
This function is called automatically by the tracked attributes system when
tracked.attributes is set in control.net, but can also be called
manually inside custom modules for ad-hoc recording.
record_attr_history( dat, item, value, ..., at = NULL, posit_ids = NULL, unique_ids = NULL )record_attr_history( dat, item, value, ..., at = NULL, posit_ids = NULL, unique_ids = NULL )
dat |
Main |
item |
The name of the attribute to record. |
value |
The values to be recorded. Must be of length 1 (recycled for
all nodes) or the same length as the number of nodes identified by
|
... |
Must be empty. It makes |
at |
The time step at which the recording happens. Defaults to the
current time step if |
posit_ids |
A numeric vector of positional IDs to which the values
apply. Converted internally to unique IDs. Either |
unique_ids |
A numeric vector of unique IDs to which the values apply. When provided, skips the positional-to-unique ID conversion. |
Exactly one of posit_ids or unique_ids must be non-NULL. When both
are NULL, the function errors. When unique_ids is provided directly,
the conversion from positional IDs is skipped, which is more efficient
when unique IDs are already known (e.g., from the automatic tracking
system).
See the "Historical Nodal Attributes" section of the "Working with Custom
Attributes and Summary Statistics" vignette
(vignette("attributes-and-summary-statistics", package = "EpiModel")).
The updated netsim_dat main list object.
## Not run: # Manual recording inside a custom module dat <- record_attr_history(dat, "status", get_attr(dat, "status"), posit_ids = get_posit_ids(dat)) # Record for a subset of nodes using unique IDs directly some_uids <- c(10, 25, 42) dat <- record_attr_history(dat, "risk", c(1, 0, 1), unique_ids = some_uids) ## End(Not run)## Not run: # Manual recording inside a custom module dat <- record_attr_history(dat, "status", get_attr(dat, "status"), posit_ids = get_posit_ids(dat)) # Record for a subset of nodes using unique IDs directly some_uids <- c(10, 25, 42) dat <- record_attr_history(dat, "risk", c(1, 0, 1), unique_ids = some_uids) ## End(Not run)
This function records any object during a simulation to allow its
inspection afterward. The records are stored in dat[["raw.records"]]
during the simulation, where dat is the main netsim_dat class
object, and in the netsim object under the raw.records
collections::queue object.
record_raw_object(dat, label, object, ..., at = NULL)record_raw_object(dat, label, object, ..., at = NULL)
dat |
Main |
label |
The name to give to the recorded object. |
object |
The object to be recorded. |
... |
Must be empty. It makes |
at |
The time step at which the recording happens. Defaults to the
current time step if |
See the "Recording Arbitrary Objects (Advanced Debugging)" section of the
"Working with Custom Attributes and Summary Statistics" vignette
(vignette("attributes-and-summary-statistics", package = "EpiModel")).
The updated netsim_dat main list object.
## Not run: dat <- record_raw_object(dat, "a.df", data.frame(x = 2:200)) dat <- record_raw_object(dat, "a.message", "I recorded something") ## End(Not run)## Not run: dat <- record_raw_object(dat, "a.df", data.frame(x = 2:200)) dat <- record_raw_object(dat, "a.message", "I recorded something") ## End(Not run)
Builds a population one group at a time from a table of group
types, such as household compositions, returning each node's
group id and the attributes its group type implies. The result
supplies both the grouping attribute for netclique() and the
nodal attributes for the dynamic layers of the same model.
sample_groups(n, types, prob = NULL, attr.name = "member", sep = " ")sample_groups(n, types, prob = NULL, attr.name = "member", sep = " ")
n |
Number of nodes in the population. |
types |
The group types. Either a character vector in which each
element lists the members of one type separated by |
prob |
Sampling weights for the types, one per type. They are normalized to sum to one. The default draws every type with equal probability. |
attr.name |
Name of the attribute column in the result when |
sep |
Separator between member labels within a character template. |
Types are drawn with replacement until the population reaches n. The
final group is drawn from the types whose size fits the remaining slots, so
that the population has exactly n nodes without cutting a group short.
When no type fits (no type has size one, and the remainder is smaller than
every type), the last group is truncated and a message says so.
The realized distribution of group types, and so of group sizes and of the
attribute values, follows the prob weights up to sampling variation; the
expected mean group size is the weighted mean of the type sizes. The
expected share of nodes with a given attribute value is the weighted share
of that value among the members of all types. Tune the type table to hit
both.
A data.frame with one row per node and n rows, in group order:
group (integer group id, 1 to the number of groups), type (index of
the type the group was drawn from), and the attribute columns (one column
named attr.name for character templates, or the columns of the
data.frames in types).
netclique() to turn the group column into a clique
layer, and assign_groups() for the reverse problem of assigning group
ids to a population whose attributes already exist.
# Household types by age group, weights chosen so that every child lives # with at least one adult and about a quarter of older adults live alone hh_types <- c("adult" = 0.15, "adult adult" = 0.20, "elderly" = 0.12, "elderly elderly" = 0.10, "adult elderly" = 0.03, "adult child" = 0.05, "adult adult child" = 0.15, "adult adult child child" = 0.15, "adult adult child elderly" = 0.05) pop <- sample_groups(1000, hh_types, attr.name = "age") head(pop, 10) table(tabulate(pop$group)) # household size distribution prop.table(table(pop$age)) # person-level age distribution # Every child shares a household with an adult has_adult <- tapply(pop$age == "adult", pop$group, any) all(has_adult[as.character(pop$group[pop$age == "child"])]) # Types with more than one attribute per member types <- list( data.frame(age = "adult", sex = "F"), data.frame(age = c("adult", "adult"), sex = c("F", "M")), data.frame(age = c("adult", "adult", "child"), sex = c("F", "M", "F")) ) pop2 <- sample_groups(100, types, prob = c(0.3, 0.4, 0.3)) head(pop2)# Household types by age group, weights chosen so that every child lives # with at least one adult and about a quarter of older adults live alone hh_types <- c("adult" = 0.15, "adult adult" = 0.20, "elderly" = 0.12, "elderly elderly" = 0.10, "adult elderly" = 0.03, "adult child" = 0.05, "adult adult child" = 0.15, "adult adult child child" = 0.15, "adult adult child elderly" = 0.05) pop <- sample_groups(1000, hh_types, attr.name = "age") head(pop, 10) table(tabulate(pop$group)) # household size distribution prop.table(table(pop$age)) # person-level age distribution # Every child shares a household with an adult has_adult <- tapply(pop$age == "adult", pop$group, any) all(has_adult[as.character(pop$group[pop$age == "child"])]) # Types with more than one attribute per member types <- list( data.frame(age = "adult", sex = "F"), data.frame(age = c("adult", "adult"), sex = c("F", "M")), data.frame(age = c("adult", "adult", "child"), sex = c("F", "M", "F")) ) pop2 <- sample_groups(100, types, prob = c(0.3, 0.4, 0.3)) head(pop2)
Changes the current timestep in the netsim_dat object.
Use with caution. This function exists to work around unforeseen
corner cases. In most situation, increment_timestep is
preferred.
set_current_timestep(dat, timestep)set_current_timestep(dat, timestep)
dat |
Main |
timestep |
The new value for the timestep. |
The updated netsim_dat main list object.
This DOES NOT modify the netsim_dat object in place. The result must
be assigned back to dat in order to be registered:
dat <- increment_timestep(dat).
This function appends the transmission matrix created during
infection.net and infection.2g.net.
set_transmat(dat, del, at)set_transmat(dat, del, at)
dat |
Main |
del |
Discordant edgelist created within |
at |
Current time step. |
This internal function works within the parent infection.net()
functions to save the transmission matrix created at time step at to
the main netsim_dat class object dat.
The updated netsim_dat main list object.
Sets a vertex attribute on an object of class network.
This function simplifies the related function in the
network package.
set_vertex_attribute(x, attrname, value, v = NULL)set_vertex_attribute(x, attrname, value, v = NULL)
x |
An object of class network. |
attrname |
The name of the attribute to set. |
value |
A vector of values of the attribute to be set. |
v |
IDs for the vertices whose attributes are to be altered. |
This function is used in EpiModel workflows to set vertex attributes
on an initialized empty network object (see network_initialize()).
Returns an object of class network.
nw <- network_initialize(100) nw <- set_vertex_attribute(nw, "age", runif(100, 15, 65)) nwnw <- network_initialize(100) nw <- set_vertex_attribute(nw, "age", runif(100, 15, 65)) nw
Extracts and prints model statistics solved with dcm.
## S3 method for class 'dcm' summary(object, at, run = 1, digits = 3, ...)## S3 method for class 'dcm' summary(object, at, run = 1, digits = 3, ...)
object |
An |
at |
Time step for model statistics. Must be one of the times the model
was solved over, held in |
run |
Model run number, for |
digits |
Number of significant digits to print. |
... |
Additional summary function arguments (not used). |
This function provides summary statistics for the main epidemiological
outcomes (state and transition size and prevalence) from a dcm model.
Time-specific summary measures are provided, so it is necessary to input a
time of interest. For multiple-run models (sensitivity analyses), input a
model run number. See examples below.
## Deterministic SIR model with varying act.rate param <- param.dcm(inf.prob = 0.2, act.rate = 2:4, rec.rate = 1/3, a.rate = 0.011, ds.rate = 0.01, di.rate = 0.03, dr.rate = 0.01) init <- init.dcm(s.num = 1000, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 50) mod <- dcm(param, init, control) summary(mod, at = 25, run = 1) summary(mod, at = 25, run = 3) summary(mod, at = 26, run = 3)## Deterministic SIR model with varying act.rate param <- param.dcm(inf.prob = 0.2, act.rate = 2:4, rec.rate = 1/3, a.rate = 0.011, ds.rate = 0.01, di.rate = 0.03, dr.rate = 0.01) init <- init.dcm(s.num = 1000, i.num = 1, r.num = 0) control <- control.dcm(type = "SIR", nsteps = 50) mod <- dcm(param, init, control) summary(mod, at = 25, run = 1) summary(mod, at = 25, run = 3) summary(mod, at = 26, run = 3)
Extracts and prints model statistics simulated with icm.
## S3 method for class 'icm' summary(object, at, digits = 3, ...)## S3 method for class 'icm' summary(object, at, digits = 3, ...)
object |
An |
at |
Time step for model statistics. |
digits |
Number of significant digits to print. |
... |
Additional summary function arguments. |
This function provides summary statistics for the main epidemiological
outcomes (state and transition size and prevalence) from an icm model.
Time-specific summary measures are provided, so it is necessary to input a
time of interest.
## Stochastic ICM SI model with 3 simulations param <- param.icm(inf.prob = 0.2, act.rate = 1) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 50, nsims = 5, verbose = FALSE) mod <- icm(param, init, control) summary(mod, at = 25) summary(mod, at = 50)## Stochastic ICM SI model with 3 simulations param <- param.icm(inf.prob = 0.2, act.rate = 1) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 50, nsims = 5, verbose = FALSE) mod <- icm(param, init, control) summary(mod, at = 25) summary(mod, at = 50)
Extracts and prints model statistics simulated with
netsim.
## S3 method for class 'netsim' summary(object, at, digits = 3, ...)## S3 method for class 'netsim' summary(object, at, digits = 3, ...)
object |
An |
at |
Time step for model statistics. |
digits |
Number of significant digits to print. |
... |
Additional summary function arguments. |
This function provides summary statistics for the main epidemiological
outcomes (state and transition size and prevalence) from a netsim
model. Time-specific summary measures are provided, so it is necessary to
input a time of interest.
## Not run: ## SI Model without Network Feedback # Initialize network and set network model parameters nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Estimate the ERGM models (see help for netest) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Parameters, initial conditions, and controls for model param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, verbose.int = 0) # Run the model simulation mod <- netsim(est1, param, init, control) summary(mod, at = 1) summary(mod, at = 50) summary(mod, at = 100) ## End(Not run)## Not run: ## SI Model without Network Feedback # Initialize network and set network model parameters nw <- network_initialize(n = 100) nw <- set_vertex_attribute(nw, "group", rep(1:2, each = 50)) formation <- ~edges target.stats <- 50 coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 20) # Estimate the ERGM models (see help for netest) est1 <- netest(nw, formation, target.stats, coef.diss, verbose = FALSE) # Parameters, initial conditions, and controls for model param <- param.net(inf.prob = 0.3, inf.prob.g2 = 0.15) init <- init.net(i.num = 10, i.num.g2 = 10) control <- control.net(type = "SI", nsteps = 100, nsims = 5, verbose.int = 0) # Run the model simulation mod <- netsim(est1, param, init, control) summary(mod, at = 1) summary(mod, at = 50) summary(mod, at = 100) ## End(Not run)
netest ObjectTrims formula environments from the netest object.
Optionally converts the newnetwork element of the
netest object to a networkLite class, and removes
the fit element (if present) from the netest
object.
trim_netest( object, as.networkLite = TRUE, keep.fit = FALSE, keep = character(0) )trim_netest( object, as.networkLite = TRUE, keep.fit = FALSE, keep = character(0) )
object |
A |
as.networkLite |
If |
keep.fit |
If |
keep |
Character vector of object names to keep in formula environments. By default, all objects are removed. |
With larger, more complex network structures with epidemic models, it is
generally useful to reduce the memory footprint of the fitted TERGM model
object (estimated with netest()). This utility function removes
all but the bare essentials needed for simulating a network model with
netsim().
The function always trims the environments of object$constraints and
object$coef.diss$dissolution.
When both edapprox = TRUE and nested.edapprox = TRUE in the
netest call, also trims the environments of object$formula
and object$formation.
When both edapprox = TRUE and nested.edapprox = FALSE in the
netest call, also trims the environments of object$formula,
environment(object$formation)$formation, and
environment(object$formation)$dissolution.
When edapprox = FALSE in the netest call, also trims the
environments of object$formation,
environment(object$formula)$formation and
environment(object$formula)$dissolution.
By default all objects are removed from these trimmed environments. Specific
objects may be retained by passing their names as the keep argument.
For the output of trim_netest to be usable in netsim()
simulation, any objects referenced in the formulas should be included in the
keep argument.
If as.networkLite = TRUE, converts object$newnetwork to a
networkLite object. If keep.fit = FALSE, removes fit (if
present) from object.
A model-free layer has no fit and no formulas, and its summary describes
the layer rather than a fit, so only its network is converted. A
netclique() layer is built as a networkLite already. A dynamic
netcensus() layer is returned unchanged, since netsim reads its edge
spells from the networkDynamic object.
A netest object with formula environments trimmed, optionally with the
newnetwork element converted to a networkLite and the
fit element removed; or the model-free layer, with its network
converted to a networkLite.
nw <- network_initialize(n = 100) formation <- ~edges + concurrent target.stats <- c(50, 25) coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 10) est <- netest(nw, formation, target.stats, coef.diss, set.control.ergm = control.ergm(MCMC.burnin = 1e5, MCMC.interval = 1000)) print(object.size(est), units = "KB") est.small <- trim_netest(est) print(object.size(est.small), units = "KB")nw <- network_initialize(n = 100) formation <- ~edges + concurrent target.stats <- c(50, 25) coef.diss <- dissolution_coefs(dissolution = ~offset(edges), duration = 10) est <- netest(nw, formation, target.stats, coef.diss, set.control.ergm = control.ergm(MCMC.burnin = 1e5, MCMC.interval = 1000)) print(object.size(est), units = "KB") est.small <- trim_netest(est) print(object.size(est.small), units = "KB")
Left-truncates simulation epidemiological summary statistics and network statistics at a specified time step.
truncate_sim(x, at, reset.time) ## S3 method for class 'dcm' truncate_sim(x, at, reset.time = TRUE) ## S3 method for class 'icm' truncate_sim(x, at, reset.time = TRUE) ## S3 method for class 'netsim' truncate_sim(x, at, reset.time = TRUE)truncate_sim(x, at, reset.time) ## S3 method for class 'dcm' truncate_sim(x, at, reset.time = TRUE) ## S3 method for class 'icm' truncate_sim(x, at, reset.time = TRUE) ## S3 method for class 'netsim' truncate_sim(x, at, reset.time = TRUE)
x |
Object of class |
at |
Time step at which to left-truncate the time series. |
reset.time |
If |
This function would be used when running a follow-up simulation from time
steps b to c after a burn-in period from time a to
b, where the final time window of interest for data analysis is
b to c only.
For icm and netsim objects, at is a time step as labeled by
as.data.frame.icm(). With reset.time = FALSE, the time step of the first
row kept is stored in control$epi.start, from which as.data.frame.icm(),
the plot and summary methods, and comp_plot() label the time steps.
Without it, the rows are labeled from 1, as in the output of icm() and
netsim(), including restarted simulations.
For netsim objects, the network statistics are truncated along with the
epi trackers, as both hold one row per time step. With reset.time = TRUE,
the times of the attribute history, the raw records, the transmission
matrix, and the cumulative edgelist are shifted to the new time steps as
well, so that get_attr_at(), get_transmat() and make_networkDynamic()
read them in the same frame. Their records before at are kept, with times
of 0 or less, as the state of the nodes and edges at at depends on them
and the transmissions before at remain part of the transmission chains.
The saved networks and the run sublists, which hold the state needed to
restart a simulation, keep their original time steps. Build a restart point
with make_restart_point() from the object before truncating it.
The updated object of class dcm, netsim, or icm.
# DCM examples param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SI", nsteps = 200) mod1 <- dcm(param, init, control) plot(mod1) # Reset time mod2a <- truncate_sim(mod1, at = 150) plot(mod2a) head(as.data.frame(mod2a)) # Do not reset time mod2b <- truncate_sim(mod1, at = 150, reset.time = FALSE) plot(mod2b) head(as.data.frame(mod2b)) # ICM example param <- param.icm(inf.prob = 0.2, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 200, nsims = 1) mod1 <- icm(param, init, control) # Reset time mod2a <- truncate_sim(mod1, at = 150) plot(mod2a) head(as.data.frame(mod2a)) # Do not reset time mod2b <- truncate_sim(mod1, at = 150, reset.time = FALSE) plot(mod2b) head(as.data.frame(mod2b))# DCM examples param <- param.dcm(inf.prob = 0.2, act.rate = 0.25) init <- init.dcm(s.num = 500, i.num = 1) control <- control.dcm(type = "SI", nsteps = 200) mod1 <- dcm(param, init, control) plot(mod1) # Reset time mod2a <- truncate_sim(mod1, at = 150) plot(mod2a) head(as.data.frame(mod2a)) # Do not reset time mod2b <- truncate_sim(mod1, at = 150, reset.time = FALSE) plot(mod2b) head(as.data.frame(mod2b)) # ICM example param <- param.icm(inf.prob = 0.2, act.rate = 0.25) init <- init.icm(s.num = 500, i.num = 1) control <- control.icm(type = "SI", nsteps = 200, nsims = 1) mod1 <- icm(param, init, control) # Reset time mod2a <- truncate_sim(mod1, at = 150) plot(mod2a) head(as.data.frame(mod2a)) # Do not reset time mod2b <- truncate_sim(mod1, at = 150, reset.time = FALSE) plot(mod2b) head(as.data.frame(mod2b))
EpiModel refers to its nodes either by positional identifiers
(posit_ids), which describe the position of a node in the
attr vector, or by unique identifiers
(unique_ids), which allow references to nodes even after
they are deactivated.
get_unique_ids(dat, posit_ids = NULL) get_posit_ids(dat, unique_ids = NULL)get_unique_ids(dat, posit_ids = NULL) get_posit_ids(dat, unique_ids = NULL)
dat |
Main |
posit_ids |
A vector of node positional identifiers (default = NULL). |
unique_ids |
A vector of node unique identifiers (default = NULL). |
A vector of unique or positional identifiers.
When unique_ids or posit_ids is NULL (default)
the full list of positional IDs or unique IDs is returned.
When providing unique_ids of deactivated nodes to
get_posit_ids, NAs are returned instead and a warning is
produced.
Records the current network state into the cumulative edgelist, stamping
newly observed edges with their start step and edges that have just
dissolved with their stop step. Returns dat unchanged when
cumulative-edgelist tracking is disabled.
update_cumulative_edgelist(dat, network, truncate = 0)update_cumulative_edgelist(dat, network, truncate = 0)
dat |
Main |
network |
Numerical index of the network for which the cumulative edgelist will be updated. (May be > 1 for models with multiple overlapping networks.) |
truncate |
After how many time steps a partnership that is no longer active should be removed from the output. See the Truncation section. |
Calling this function is a no-op unless control.net(cumulative.edgelist = TRUE). With tracking enabled, the built-in network-resimulation module
resim_nets() calls this once per network at every time step, using
truncate = control$truncate.el.cuml. Custom modules that mutate the
network outside the TERGM machinery (e.g., forming or dissolving edges
directly) should call this manually after the change so the cumulative
record stays consistent.
The updated netsim_dat main list object.
To avoid storing a cumulative edgelist too long, the truncate
parameter defines a number of steps after which an edge that is no longer
active is dropped from the stored history.
When truncate = Inf, no edges are ever removed. When
truncate = 0 (the default), only currently active edges are kept; this
is useful for tracking the start step of each active edge while keeping
memory low.
control.net() (cumulative.edgelist, truncate.el.cuml),
get_cumulative_edgelist() to read the result.
Other cumulative_edgelist:
as_cumulative_edgelist(),
dedup_cumulative_edgelist(),
get_cumulative_degree(),
get_cumulative_edgelist(),
get_cumulative_edgelists_df(),
get_partners(),
reachable-nodes
## Not run: # Inside a custom module, after editing the network outside the TERGM: for (n in seq_len(dat$num.nw)) { dat <- update_cumulative_edgelist(dat, n, truncate = get_control(dat, "truncate.el.cuml")) } ## End(Not run)## Not run: # Inside a custom module, after editing the network outside the TERGM: for (n in seq_len(dat$num.nw)) { dat <- update_cumulative_edgelist(dat, n, truncate = get_control(dat, "truncate.el.cuml")) } ## End(Not run)
Adjusts the dissolution component of a dynamic ERGM fit using
the netest() function with the edges dissolution
approximation method.
update_dissolution(old.netest, new.coef.diss, nested.edapprox = TRUE)update_dissolution(old.netest, new.coef.diss, nested.edapprox = TRUE)
old.netest |
An object of class |
new.coef.diss |
An object of class |
nested.edapprox |
Logical, only used when |
Fitting an ERGM is a computationally intensive process when the model includes dyad dependent terms. With the edges dissolution approximation method of Carnegie et al, the coefficients for a temporal ERGM are approximated by fitting a static ERGM and adjusting the formation coefficients to account for edge dissolution. This function provides a very efficient method to adjust the coefficients of that model when one wants to use a different dissolution model; a typical use case may be to fit several different models with different average edge durations as targets. The example below exhibits that case.
An updated network model object of class netest.
## Not run: nw <- network_initialize(n = 1000) # Two dissolutions: an average duration of 300 versus 200 diss.300 <- dissolution_coefs(~offset(edges), 300, 0.001) diss.200 <- dissolution_coefs(~offset(edges), 200, 0.001) # Fit the two reference models est300 <- netest(nw = nw, formation = ~edges, target.stats = c(500), coef.diss = diss.300) est200 <- netest(nw = nw, formation = ~edges, target.stats = c(500), coef.diss = diss.200) # Alternatively, update the 300 model with the 200 coefficients est200.compare <- update_dissolution(est300, diss.200) identical(est200$coef.form, est200.compare$coef.form) ## End(Not run)## Not run: nw <- network_initialize(n = 1000) # Two dissolutions: an average duration of 300 versus 200 diss.300 <- dissolution_coefs(~offset(edges), 300, 0.001) diss.200 <- dissolution_coefs(~offset(edges), 200, 0.001) # Fit the two reference models est300 <- netest(nw = nw, formation = ~edges, target.stats = c(500), coef.diss = diss.300) est200 <- netest(nw = nw, formation = ~edges, target.stats = c(500), coef.diss = diss.200) # Alternatively, update the 300 model with the 200 coefficients est200.compare <- update_dissolution(est300, diss.200) identical(est200$coef.form, est200.compare$coef.form) ## End(Not run)
Updates epidemic model parameters originally set with
param.net() and adds new parameters.
update_params(param, new.param.list)update_params(param, new.param.list)
param |
Object of class |
new.param.list |
Named list of new parameters to add to original parameters. |
This function can update any original parameters specified with
param.net() and add new parameters. This function would be used
if the inputs to param.net() were a long list of fixed model
parameters that needed supplemental replacements or additions for particular
model runs (e.g., changing an intervention efficacy parameter but leaving all
other parameters fixed).
The new.param.list object should be a named list object containing
named parameters matching those already in x (in which case those
original parameter values will be replaced) or not matching (in which case
new parameters will be added to param).
update_params modifies a param.net object before it is passed
to netsim(); it is the recommended helper for tweaking parameters
outside of a running simulation. To modify parameters from inside a
module function during a simulation, use set_param() on the live
dat object instead. There is no analogous update_controls() or
update_inits() helper: for a control.net or init.net object,
edit the list directly (e.g., ctrl$nsteps <- 1000) or rebuild it
with a fresh call to the constructor. For scheduled mid-simulation
changes to parameters or control settings, see the
.param.updater.list argument to param.net() and the
.control.updater.list argument to control.net().
An updated list object of class param.net, which can be passed to the
EpiModel function netsim().
set_param() for editing parameters inside a module function
during a simulation; param.net() for the parameter constructor;
netsim() for running a simulation.
x <- param.net(inf.prob = 0.5, act.rate = 2) y <- list(inf.prob = 0.75, dx.rate = 0.2) z <- update_params(x, y) print(z)x <- param.net(inf.prob = 0.5, act.rate = 2) y <- list(inf.prob = 0.75, dx.rate = 0.2) z <- update_params(x, y) print(z)
Apply a scenario object to a param.net object
use_scenario(param, scenario)use_scenario(param, scenario)
param |
Object of class |
scenario |
a scenario object usually created from a |
An updated list object of class param.net, which can be passed to the
EpiModel function netsim().
A scenario is a list containing an "id" field, the name of the scenario and
a ".param.updater.list" containing a list of updaters that modifies the
parameters of the model at given time steps. If a scenario contains a
parameter not defined in the param object, an error will be produced.
A scenario column with a position suffix (x_2) sets only that position of
a vector parameter; see the "Vector parameters" section of
create_scenario_list().
See the vignette "model-parameters" for the technical detail of their
implementation.