Skip to content

Commit b582900

Browse files
committed
differences for PR #145
1 parent e559a21 commit b582900

10 files changed

Lines changed: 225 additions & 173 deletions

.DS_Store

-6 KB
Binary file not shown.

compare-interventions.md

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ exercises: 30 # exercise time in minutes
2727

2828
Learners should familiarise themselves with following concept dependencies before working through this tutorial:
2929

30-
**Outbreak response** : [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/).
30+
**Outbreak response**: [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/).
3131
:::::::::::::::::::::::::::::::::
3232

3333

@@ -213,7 +213,7 @@ There is no vaccination scheme in place
213213

214214
::::::::::::::::: hint
215215

216-
### HINT : Running the model with default parameter values
216+
### HINT: Running the model with default parameter values
217217

218218
We can run the Vacamole model with [default parameter values](https://epiverse-trace.github.io/epidemics/articles/model_vacamole.html#model-epidemic-using-vacamole) by just specifying the population object and number of time steps to run the model for:
219219

@@ -236,19 +236,25 @@ output <- epidemics::model_vacamole(
236236

237237

238238
``` r
239-
polymod <- socialmixr::polymod
240-
contact_data <- socialmixr::contact_matrix(
241-
survey = polymod,
239+
survey_files_uk <- contactsurveys::download_survey(
240+
survey = "https://doi.org/10.5281/zenodo.3874557",
241+
verbose = FALSE
242+
)
243+
survey_load_uk <- socialmixr::load_survey(files = survey_files_uk)
244+
245+
contacts_byage_uk <- socialmixr::contact_matrix(
246+
survey = survey_load_uk,
242247
countries = "United Kingdom",
243-
age.limits = c(0, 20, 40),
244-
symmetric = TRUE
248+
age_limits = c(0, 20, 40),
249+
symmetric = TRUE,
250+
return_demography = TRUE
245251
)
246252
# prepare contact matrix
247-
contact_matrix <- t(contact_data$matrix)
253+
contacts_byage_matrix_uk <- t(contacts_byage_uk$matrix)
248254

249255
# extract demography vector
250-
demography_vector <- contact_data$demography$population
251-
names(demography_vector) <- rownames(contact_matrix)
256+
demography_vector <- contacts_byage_uk$demography$population
257+
names(demography_vector) <- rownames(contacts_byage_matrix_uk)
252258

253259
# prepare initial conditions
254260
initial_i <- 1e-6
@@ -266,12 +272,12 @@ initial_conditions_vacamole <- rbind(
266272
initial_conditions_vacamole,
267273
initial_conditions_vacamole
268274
)
269-
rownames(initial_conditions_vacamole) <- rownames(contact_matrix)
275+
rownames(initial_conditions_vacamole) <- rownames(contacts_byage_matrix_uk)
270276

271277
# prepare population object
272278
uk_population_vacamole <- epidemics::population(
273279
name = "UK",
274-
contact_matrix = contact_matrix,
280+
contact_matrix = contacts_byage_matrix_uk,
275281
demography_vector = demography_vector,
276282
initial_conditions = initial_conditions_vacamole
277283
)
@@ -415,9 +421,9 @@ output_baseline <- epidemics::model_default(
415421

416422
Then, we create a list of all the interventions we want to include in our comparison. We define our scenarios as follows:
417423

418-
+ scenario 1 : close schools
419-
+ scenario 2 : mask mandate
420-
+ scenario 3 : close schools and mask mandate.
424+
+ scenario 1: close schools
425+
+ scenario 2: mask mandate
426+
+ scenario 3: close schools and mask mandate.
421427

422428
In R we specify this as:
423429

@@ -480,7 +486,7 @@ head(output)
480486

481487
Now that we have our model output for all of our scenarios, we want to compare the outputs of the interventions to our baseline.
482488

483-
We can do this using `outcomes_averted()` in `{epidemics}`. This function calculates the final epidemic size for each scenario, and then calculates the number of infections averted in each scenario compared to the baseline. To use this function we specify the :
489+
We can do this using `outcomes_averted()` in `{epidemics}`. This function calculates the final epidemic size for each scenario, and then calculates the number of infections averted in each scenario compared to the baseline. To use this function we specify the:
484490

485491
+ output of the baseline scenario
486492
+ outputs of the intervention scenario(s).
@@ -542,9 +548,9 @@ We recommend to read the vignette on [Modelling responses to a stochastic Ebola
542548

543549
::::::::::::::::::::::::::::::::::::: challenge
544550

545-
## Challenge : Ebola outbreak analysis
551+
## Challenge: Ebola outbreak analysis
546552

547-
You have been tasked to investigate the potential impact of an intervention on an Ebola outbreak in Guinea (e.g. a reduction in risky contacts with cases). Using `model_ebola()` and the the information detailed below, find the number of infections averted when :
553+
You have been tasked to investigate the potential impact of an intervention on an Ebola outbreak in Guinea (e.g. a reduction in risky contacts with cases). Using `model_ebola()` and the the information detailed below, find the number of infections averted when:
548554

549555
+ an intervention is applied to reduce the transmission rate by 50% from day 60 and,
550556
+ an intervention is applied to reduce transmission by 10% from day 30.
@@ -553,11 +559,11 @@ For both interventions, we assume there is some uncertainty about the baseline t
553559

554560
*Note: Depending on the number of replicates used, this simulation may take several minutes to run.*
555561

556-
+ Population size : 14 million
557-
+ Initial number of exposed individuals : 10
558-
+ Initial number of infectious individuals : 5
559-
+ Time of simulation : 120 days
560-
+ Parameter values :
562+
+ Population size: 14 million
563+
+ Initial number of exposed individuals: 10
564+
+ Initial number of infectious individuals: 5
565+
+ Time of simulation: 120 days
566+
+ Parameter values:
561567
+ $R_0$ (`r0`) = 1.1,
562568
+ $p^I$ (`infectious_period`) = 12,
563569
+ $p^E$ (`preinfectious_period`) = 5,

contact-matrices.md

Lines changed: 72 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,10 @@ Some groups of individuals have more contacts than others; the average schoolchi
3636

3737

3838
``` r
39+
library(contactsurveys)
3940
library(socialmixr)
4041
```
4142

42-
43-
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor
44-
45-
46-
47-
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
48-
4943
## The contact matrix
5044

5145
The basic contact matrix represents the amount of contact or mixing within and between different subgroups of a population. The subgroups are often age categories but can also be:
@@ -63,40 +57,62 @@ $$
6357
\end{bmatrix}
6458
$$
6559

66-
In this example, we would use this to represent that children meet, on average, 2 other children and 2 adult per day (first row), and adults meet, on average, 1 child and 3 other adults per day (second row). We can use this kind of information to account for the role heterogeneity in contact plays in infectious disease transmission.
60+
In this example, we would use this to represent that children meet, on average, 2 other children and 2 adult per day (first row), and adults meet, on average, 1 child and 3 other adults per day (second row). We can use this kind of information to account for the role that heterogeneity in contact plays in infectious disease transmission.
6761

6862
::::::::::::::::::::::::::::::::::::: callout
6963

7064
### A Note on Notation
71-
For a contact matrix with rows $i$ and columns $j$:
65+
In a contact matrix, the entry $C[i,j]$, at row $i$ and column $j$:
7266

73-
- $C[i,j]$ represents the average number of contacts that individuals in group $i$ have with individuals in group $j$
74-
- This average is calculated as the total number of contacts between groups $i$ and $j$, divided by the number of individuals in group $i$
67+
- Represents the average number of contacts an individual in group $i$ has with individuals in group $j$
68+
- This is calculated by dividing the total number of contacts between groups $i$ and $j$ by the size of group $i$
7569
::::::::::::::::::::::::::::::::::::::::::::::::
7670

7771
## Using `socialmixr`
7872

7973
Contact matrices are commonly estimated from studies that use diaries to record interactions. For example, the POLYMOD survey measured contact patterns in 8 European countries using data on the location and duration of contacts reported by the study participants [(Mossong et al. 2008)](https://doi.org/10.1371/journal.pmed.0050074).
8074

81-
The R package `{socialmixr}` contains functions which can estimate contact matrices from POLYMOD and other surveys. We can load the POLYMOD survey data:
75+
The R package `{socialmixr}` contains functions which can estimate contact matrices from POLYMOD and other surveys. We can download and load the POLYMOD survey data directly from Zenodo using `{contactsurveys}` and `{socialmixr}`:
8276

8377

78+
``` r
79+
survey_files <- contactsurveys::download_survey(
80+
survey = "https://doi.org/10.5281/zenodo.3874557",
81+
verbose = FALSE
82+
)
83+
84+
survey_load <- socialmixr::load_survey(files = survey_files)
85+
```
86+
87+
::::::::::::::::::::::::::::::::::::: callout
88+
### Inspect available countries
89+
90+
A single survey file can contain data from multiple countries. You can inspect the available countries with:
91+
8492

8593
``` r
86-
polymod <- socialmixr::polymod
94+
levels(survey_load$participants$country)
95+
```
96+
97+
``` output
98+
[1] "Belgium" "Finland" "Germany" "Italy"
99+
[5] "Luxembourg" "Netherlands" "Poland" "United Kingdom"
87100
```
88101

89-
Then we can obtain the contact matrix for the age categories we want by specifying `age_limits`.
102+
::::::::::::::::::::::::::::::::::::::::::::::::
103+
104+
We obtain the contact matrix for the United Kingdom — passing `countries = "United Kingdom"` to select data from the intended country, `age_limits` to define age categories, and `return_demography = TRUE` to include demographic information required by `{epidemics}`.
90105

91106

92107
``` r
93-
contact_data <- socialmixr::contact_matrix(
94-
survey = polymod,
108+
contacts_byage <- socialmixr::contact_matrix(
109+
survey = survey_load,
95110
countries = "United Kingdom",
96111
age_limits = c(0, 20, 40),
97-
symmetric = TRUE
112+
symmetric = TRUE,
113+
return_demography = TRUE
98114
)
99-
contact_data
115+
contacts_byage
100116
```
101117

102118
``` output
@@ -124,9 +140,9 @@ $participants
124140

125141

126142

127-
**Note: although the contact matrix `contact_data$matrix` is not itself mathematically symmetric, it satisfies the condition that the total number of contacts of one group with another is the same as the reverse. In other words:
128-
`contact_data$matrix[j,i]*contact_data$demography$proportion[j] = contact_data$matrix[i,j]*contact_data$demography$proportion[i]`.
129-
For the mathematical explanation see [the corresponding section in the socialmixr documentation](https://epiforecasts.io/socialmixr/articles/socialmixr.html#symmetric-contact-matrices).**
143+
**Note**: although the contact matrix `contacts_byage$matrix` is not itself mathematically symmetric, it satisfies the condition that the total number of contacts of one group with another is the same as the reverse. In other words:
144+
`contacts_byage$matrix[j,i]*contacts_byage$demography$proportion[j] = contacts_byage$matrix[i,j]*contacts_byage$demography$proportion[i]`.
145+
For the mathematical explanation see [the corresponding section in the socialmixr documentation](https://epiforecasts.io/socialmixr/articles/socialmixr.html#symmetric-contact-matrices).
130146

131147

132148
::::::::::::::::::::::::::::::::::::: callout
@@ -145,30 +161,40 @@ If `symmetric` is set to TRUE, the `contact_matrix()` function will internally u
145161

146162
::::::::::::::::::::::::::::::::::::::::::::::::
147163

148-
The example above uses the POLYMOD survey. There are a number of surveys available in `socialmixr`. To list the available surveys, use `socialmixr::list_surveys()`. To download a survey, we can use `socialmixr::get_survey()`
164+
The example above uses the POLYMOD survey. Other surveys are available in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/). To use a different survey, first identify its DOI (see below), then download and load it with `contactsurveys::download_survey()` and `socialmixr::load_survey()`. Here we use the Zambia and South Africa contact survey:
149165

150166

151167
``` r
152-
# Access the contact survey data from Zenodo
153-
zambia_sa_survey <- socialmixr::get_survey(
154-
"https://doi.org/10.5281/zenodo.3874675"
168+
# Download and load the contact survey data for Zambia from Zenodo
169+
survey_files_zambia <- contactsurveys::download_survey(
170+
survey = "https://doi.org/10.5281/zenodo.3874675",
171+
verbose = FALSE
155172
)
173+
174+
survey_load_zambia <- socialmixr::load_survey(files = survey_files_zambia)
156175
```
157176

158177
:::::::::::::::::: spoiler
159178

160-
You can explore all the available surveys from the Zenodo repository at <https://zenodo.org/communities/social_contact_data/>. If you are interested in accessing to a specific URL within R, you can try:
179+
**Find a survey DOI with contactsurveys**
161180

162-
```r
163-
library(socialmixr)
181+
Browse available surveys in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/), or list them programmatically:
182+
183+
184+
``` r
185+
library(contactsurveys)
164186
library(tidyverse)
165187

166-
# Get URL for Zambia contact survey data from {socialmixr}
167-
socialmixr::list_surveys() %>%
188+
# Get URL for Zambia contact survey data from {contactsurveys}
189+
contactsurveys::list_surveys() %>%
168190
dplyr::filter(stringr::str_detect(title, "Zambia")) %>%
169191
dplyr::pull(url)
170192
```
171193

194+
``` output
195+
[1] "https://doi.org/10.5281/zenodo.3874675"
196+
```
197+
172198
::::::::::::::::::
173199

174200

@@ -188,12 +214,12 @@ The R package {socialmixr} contains functions which can estimate contact matrice
188214

189215
::::::::::::::::::::: hint
190216

191-
The survey object `zambia_sa_survey` contains data from two countries. If you need to estimate the social contact matrix from data of the specific country of Zambia, identify what argument in `socialmixr::contact_matrix()` you need for this.
217+
The survey object `survey_load_zambia` contains data from two countries. If you need to estimate the social contact matrix from data of the specific country of Zambia, identify what argument in `socialmixr::contact_matrix()` you need for this.
192218

193219

194220
``` r
195221
# Inspect the countries within the survey object
196-
levels(zambia_sa_survey$participants$country)
222+
levels(survey_load_zambia$participants$country)
197223
```
198224

199225
``` output
@@ -211,11 +237,12 @@ Similar to the code above, to access vector values within a dataframe, you can u
211237

212238
``` r
213239
# Generate the contact matrix for Zambia only
214-
contact_data_zambia <- socialmixr::contact_matrix(
215-
survey = zambia_sa_survey,
240+
contacts_byage_zambia <- socialmixr::contact_matrix(
241+
survey = survey_load_zambia,
216242
countries = "Zambia", # key argument
217243
age_limits = c(0, 20),
218-
symmetric = TRUE
244+
symmetric = TRUE,
245+
return_demography = TRUE
219246
)
220247
```
221248

@@ -228,7 +255,7 @@ participants).
228255

229256
``` r
230257
# Print the contact matrix for Zambia only
231-
contact_data_zambia
258+
contacts_byage_zambia
232259
```
233260

234261
``` output
@@ -253,7 +280,7 @@ $participants
253280

254281
``` r
255282
# Print the vector of population size for {epidemics}
256-
contact_data_zambia$demography$population
283+
contacts_byage_zambia$demography$population
257284
```
258285

259286
``` output
@@ -269,8 +296,6 @@ Contact matrices can be estimated from data obtained from diary (such as POLYMOD
269296
::::::::::::::::::::::::::::::::::::::::::::::::
270297

271298

272-
273-
274299
## Analyses with contact matrices
275300

276301
Contact matrices can be used in a wide range of epidemiological analyses, they can be used:
@@ -293,7 +318,7 @@ Whereas a contact matrix gives the average number of contacts that one groups ma
293318

294319
### In mathematical models
295320

296-
Consider the SIR model where individuals are categorized as either susceptible $S$, infected but not yet infectious $E$, infectious $I$ or recovered $R$. The schematic below shows the processes which describe the flow of individuals between the disease states $S$, $I$ and $R$ and the key parameters for each process.
321+
Consider the SIR model where individuals are categorized as either susceptible $S$, infected $I$ and recovered $R$. The schematic below shows the processes which describe the flow of individuals between the disease states $S$, $I$ and $R$ and the key parameters for each process.
297322

298323
<img src="fig/contact-matrices-rendered-diagram-1.png" alt="" style="display: block; margin: auto;" />
299324

@@ -308,11 +333,11 @@ $$
308333
\end{aligned}
309334
$$
310335

311-
To add age structure to our model, we need to add additional equations for the infection states $S$, $I$ and $R$ for each age group $i$. If we want to assume that there is heterogeneity in contacts between age groups then we must adapt the transmission term $\beta SI$ to include the contact matrix $C$ as follows :
336+
To add age structure to our model, we need to add additional equations for the infection states $S$, $I$ and $R$ for each age group $i$. If we want to assume that there is heterogeneity in contacts between age groups then we must adapt the transmission term $\beta SI$ to include the contact matrix $C$ as follows:
312337

313338
$$ \beta S_i \sum_j C_{i,j} I_j/N_j. $$
314339

315-
Susceptible individuals in age group $i$ become infected dependent on their rate of contact with individuals in each age group. For each disease state ($S$, $E$, $I$ and $R$) and age group ($i$), we have a differential equation describing the rate of change with respect to time.
340+
Susceptible individuals in age group $i$ become infected dependent on their rate of contact with individuals in each age group. For each disease state ($S$, $I$ and $R$) and age group ($i$), we have a differential equations describing the rate of change with respect to time.
316341

317342
$$
318343
\begin{aligned}
@@ -329,13 +354,13 @@ When simulating an epidemic, we often want to ensure that the average number of
329354

330355
Rather than just using the raw number of contacts, we can instead normalise the contact matrix to make it easier to work in terms of $R_0$. In particular, we normalise the matrix by scaling it so that if we were to calculate the average number of secondary cases based on this normalised matrix, the result would be 1 (in mathematical terms, we are scaling the matrix so the largest eigenvalue is 1). This transformation scales the entries but preserves their relative values.
331356

332-
In the case of the above model, we want to define $\beta C_{i,j}$ so that the model has a specified valued of $R_0$. If the entry of the contact matrix $C[i,j]$ represents the contacts of population $i$ with $j$, it is equivalent to `contact_data$matrix[i,j]`, and the maximum eigenvalue of this matrix represents the typical magnitude of contacts, not typical magnitude of transmission. We must therefore normalise the matrix $C$ so the maximum eigenvalue is one; we call this matrix $C_{normalised}$. Because the rate of recovery is $\gamma$, individuals will be infectious on average for $1/\gamma$ days. So $\beta$ as a model input is calculated from $R_0$, the scaling factor and the value of $\gamma$ (i.e. mathematically we use the fact that the dominant eigenvalue of the matrix $R_0 \times C_{normalised}$ is equal to $\beta / \gamma$).
357+
In the case of the above model, we want to define $\beta C_{i,j}$ so that the model has a specified valued of $R_0$. If the entry of the contact matrix $C[i,j]$ represents the contacts of population $i$ with $j$, it is equivalent to `contacts_byage$matrix[i,j]`, and the maximum eigenvalue of this matrix represents the typical magnitude of contacts, not typical magnitude of transmission. We must therefore normalise the matrix $C$ so the maximum eigenvalue is one; we call this matrix $C_{normalised}$. Because the rate of recovery is $\gamma$, individuals will be infectious on average for $1/\gamma$ days. So $\beta$ as a model input is calculated from $R_0$, the scaling factor and the value of $\gamma$ (i.e. mathematically we use the fact that the dominant eigenvalue of the matrix $R_0 \times C_{normalised}$ is equal to $\beta / \gamma$).
333358

334359

335360
``` r
336-
contact_matrix <- t(contact_data$matrix)
337-
scaling_factor <- 1 / max(eigen(contact_matrix)$values)
338-
normalised_matrix <- contact_matrix * scaling_factor
361+
contacts_byage_matrix <- t(contacts_byage$matrix)
362+
scaling_factor <- 1 / max(eigen(contacts_byage_matrix)$values)
363+
normalised_matrix <- contacts_byage_matrix * scaling_factor
339364
```
340365

341366
As a result, if we multiply the scaled matrix by $R_0$, then converting to the number of expected secondary cases would give us $R_0$, as required.
@@ -363,7 +388,7 @@ Normalisation can be performed by the function `contact_matrix()` in `{socialmix
363388

364389
``` r
365390
contact_data_split <- socialmixr::contact_matrix(
366-
survey = polymod,
391+
survey = survey_load,
367392
countries = "United Kingdom",
368393
age_limits = c(0, 20, 40),
369394
symmetric = TRUE,

0 commit comments

Comments
 (0)