Social distancing and sampling effect
Background
This example tries to simulate a decent sized population with
- Effect of increased social distancing following government guidelines.
- Estimation of population incidence rate and seroprevalence through sampling.
Assumptions
- The population has size
popsize
in which everyone is equally susceptible. - Initial seroprevalence is
initial_seroprevalence
, withinitial_incidence_rate
active cases. - Incomplete social distancing in that while 80% of symptomatic cases are quarantined for 14-days, the rest of 20% of symptomatic cases are not, perhaps due to the mildness of symptoms.
- Starting from day 15, stronger social distancing was adviced, which reduces the effective production number of everyone by
distancing
. - Although sampling in real world would be far less frequent, we sample
sample_size
individuals from the population every day to estimate the true incidence and seroprevalence of the population.
Simulation of sampling
# this is a papermill parameter cell.
# 50k population size
popsize = 50000
# 0.6% reported cases
initial_incidence_rate = 0.006
# assuming that seoprevalence is 5 times higher than incidence rate
initial_seroprevalence = 0.03
# effect of social distancing
distancing = 0.5
# 1% population size
sample_size = 500
This scenario can be simulated with the following command:
outbreak_simulator --popsize {popsize} --handle-symptomatic quarantine_14 0.8 --stop-if 't>45' --logfile distancing.log \
--plugin init --at 0 --seroprevalence {seroprevalance} --incidence-rate {incidence_rate} --leadtime any \
--plugin sample --interval 1 --size {sample_size} \
--plugin stat --interval 1 \
--plugin setparam --at 15 --symptomatic-r0 {1.4 * distancing} {2.8 * distancing} --asymptomatic-r0 {0.28 * distancing} {0.56 * distancing} \
> distancing.txt
where plugins init
and sample
are used to initialize and sample from the population, setparam
is used to set $R_0$ for sympatomatic and asymptomatic cases at day 15, and stat
is to report true population incidence rate and seroprevalence every day.
%expand
outbreak_simulator --popsize {popsize} --handle-symptomatic quarantine_14 0.8 \
--stop-if 't>45' --repeat 10 --logfile distancing.log \
--plugin init --at 0 --leadtime any --seroprevalence {initial_seroprevalence} --incidence-rate {initial_incidence_rate} \
--plugin setparam --at 15 --symptomatic-r0 {1.4 * distancing} {2.8 * distancing} --asymptomatic-r0 {0.28 * distancing} {0.56 * distancing} \
--plugin sample --interval 1 --size {sample_size} \
--plugin stat --interval 1 \
> distancing.txt
100%|███████████████████████████████████████████| 10/10 [01:08<00:00, 6.81s/it]
Results
Although a large number of statistics such as number of affected, recovered, seroprevalence are reported, we extract the following statistics from the output of the simulations (distancing.txt
) for this report:
incidence_rate_0.00
toincidence_rate_45.00
as population incidence rate for 10 replicate simulations.sample_incidence_rate_0.00
tosample_incidence_rate_45.00
as sample incidence rate for 10 replicate simulations.
import pandas as pd
def get_seq(filename, field_name):
result = {}
with open(filename) as stat:
for line in stat:
if line.startswith(field_name):
key, value = line.strip().split('\t')
t = int(key[len(field_name)+1:].split('.')[0])
if ':' in value:
value = eval('{' + value + '}')
else:
value = {idx+1:value for idx, value in enumerate(eval(value))}
result[t] = value
return pd.DataFrame(result).transpose()[[x for x in range(1, 11)]]
%preview incidence_rate
incidence_rate = get_seq('distancing.txt', 'incidence_rate')
sample_incidence_rate = get_seq('distancing.txt', 'sample_incidence_rate')
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0060 | 0.0060 | 0.0060 | 0.0060 | 0.0060 | 0.0060 | 0.0060 | 0.0060 | 0.0060 | 0.0060 |
1 | 0.0056 | 0.0057 | 0.0055 | 0.0058 | 0.0058 | 0.0057 | 0.0059 | 0.0057 | 0.0059 | 0.0057 |
2 | 0.0056 | 0.0055 | 0.0053 | 0.0057 | 0.0058 | 0.0055 | 0.0059 | 0.0058 | 0.0058 | 0.0056 |
3 | 0.0057 | 0.0054 | 0.0054 | 0.0055 | 0.0058 | 0.0057 | 0.0060 | 0.0058 | 0.0058 | 0.0057 |
4 | 0.0055 | 0.0056 | 0.0053 | 0.0052 | 0.0057 | 0.0059 | 0.0061 | 0.0057 | 0.0060 | 0.0059 |
5 | 0.0059 | 0.0055 | 0.0053 | 0.0050 | 0.0058 | 0.0060 | 0.0060 | 0.0058 | 0.0061 | 0.0060 |
6 | 0.0059 | 0.0057 | 0.0059 | 0.0054 | 0.0058 | 0.0060 | 0.0063 | 0.0061 | 0.0063 | 0.0065 |
7 | 0.0062 | 0.0057 | 0.0063 | 0.0052 | 0.0058 | 0.0064 | 0.0066 | 0.0060 | 0.0064 | 0.0068 |
8 | 0.0067 | 0.0058 | 0.0066 | 0.0055 | 0.0060 | 0.0065 | 0.0069 | 0.0063 | 0.0067 | 0.0072 |
9 | 0.0071 | 0.0059 | 0.0071 | 0.0055 | 0.0059 | 0.0067 | 0.0072 | 0.0065 | 0.0069 | 0.0077 |
10 | 0.0072 | 0.0062 | 0.0077 | 0.0056 | 0.0061 | 0.0068 | 0.0077 | 0.0065 | 0.0072 | 0.0080 |
11 | 0.0074 | 0.0064 | 0.0086 | 0.0058 | 0.0062 | 0.0071 | 0.0082 | 0.0066 | 0.0080 | 0.0084 |
12 | 0.0076 | 0.0067 | 0.0096 | 0.0063 | 0.0065 | 0.0075 | 0.0086 | 0.0067 | 0.0082 | 0.0090 |
13 | 0.0082 | 0.0070 | 0.0106 | 0.0069 | 0.0067 | 0.0080 | 0.0091 | 0.0070 | 0.0085 | 0.0096 |
14 | 0.0087 | 0.0072 | 0.0116 | 0.0074 | 0.0071 | 0.0085 | 0.0097 | 0.0073 | 0.0089 | 0.0101 |
15 | 0.0091 | 0.0074 | 0.0125 | 0.0077 | 0.0073 | 0.0089 | 0.0098 | 0.0076 | 0.0091 | 0.0103 |
16 | 0.0094 | 0.0077 | 0.0133 | 0.0079 | 0.0072 | 0.0089 | 0.0100 | 0.0078 | 0.0093 | 0.0106 |
17 | 0.0094 | 0.0078 | 0.0142 | 0.0085 | 0.0072 | 0.0093 | 0.0103 | 0.0076 | 0.0093 | 0.0110 |
18 | 0.0096 | 0.0080 | 0.0148 | 0.0086 | 0.0071 | 0.0096 | 0.0103 | 0.0076 | 0.0094 | 0.0110 |
19 | 0.0097 | 0.0080 | 0.0154 | 0.0084 | 0.0070 | 0.0095 | 0.0103 | 0.0073 | 0.0093 | 0.0107 |
20 | 0.0095 | 0.0083 | 0.0158 | 0.0082 | 0.0068 | 0.0095 | 0.0100 | 0.0070 | 0.0091 | 0.0107 |
21 | 0.0092 | 0.0080 | 0.0159 | 0.0079 | 0.0064 | 0.0093 | 0.0097 | 0.0067 | 0.0087 | 0.0102 |
22 | 0.0091 | 0.0074 | 0.0154 | 0.0078 | 0.0062 | 0.0090 | 0.0095 | 0.0063 | 0.0084 | 0.0099 |
23 | 0.0087 | 0.0071 | 0.0152 | 0.0076 | 0.0058 | 0.0087 | 0.0089 | 0.0060 | 0.0081 | 0.0090 |
24 | 0.0086 | 0.0070 | 0.0148 | 0.0071 | 0.0054 | 0.0080 | 0.0083 | 0.0056 | 0.0079 | 0.0085 |
25 | 0.0080 | 0.0066 | 0.0140 | 0.0067 | 0.0050 | 0.0074 | 0.0077 | 0.0050 | 0.0074 | 0.0079 |
26 | 0.0076 | 0.0062 | 0.0133 | 0.0063 | 0.0044 | 0.0068 | 0.0070 | 0.0044 | 0.0067 | 0.0073 |
27 | 0.0070 | 0.0056 | 0.0126 | 0.0057 | 0.0039 | 0.0062 | 0.0066 | 0.0038 | 0.0063 | 0.0067 |
28 | 0.0063 | 0.0052 | 0.0118 | 0.0051 | 0.0035 | 0.0055 | 0.0061 | 0.0034 | 0.0057 | 0.0059 |
29 | 0.0058 | 0.0047 | 0.0107 | 0.0047 | 0.0032 | 0.0047 | 0.0054 | 0.0030 | 0.0052 | 0.0051 |
30 | 0.0052 | 0.0040 | 0.0098 | 0.0042 | 0.0026 | 0.0043 | 0.0048 | 0.0025 | 0.0046 | 0.0045 |
31 | 0.0046 | 0.0033 | 0.0087 | 0.0039 | 0.0024 | 0.0037 | 0.0043 | 0.0021 | 0.0041 | 0.0040 |
32 | 0.0043 | 0.0030 | 0.0078 | 0.0035 | 0.0020 | 0.0030 | 0.0038 | 0.0017 | 0.0037 | 0.0037 |
33 | 0.0040 | 0.0027 | 0.0073 | 0.0032 | 0.0018 | 0.0027 | 0.0035 | 0.0015 | 0.0034 | 0.0032 |
34 | 0.0035 | 0.0024 | 0.0067 | 0.0026 | 0.0016 | 0.0022 | 0.0033 | 0.0013 | 0.0030 | 0.0027 |
35 | 0.0032 | 0.0021 | 0.0060 | 0.0024 | 0.0013 | 0.0019 | 0.0030 | 0.0011 | 0.0025 | 0.0024 |
36 | 0.0028 | 0.0018 | 0.0055 | 0.0021 | 0.0011 | 0.0016 | 0.0025 | 0.0009 | 0.0022 | 0.0020 |
37 | 0.0026 | 0.0015 | 0.0050 | 0.0019 | 0.0010 | 0.0014 | 0.0023 | 0.0008 | 0.0018 | 0.0017 |
38 | 0.0024 | 0.0014 | 0.0044 | 0.0016 | 0.0009 | 0.0013 | 0.0022 | 0.0007 | 0.0016 | 0.0014 |
39 | 0.0022 | 0.0013 | 0.0041 | 0.0015 | 0.0007 | 0.0011 | 0.0019 | 0.0006 | 0.0014 | 0.0012 |
40 | 0.0020 | 0.0011 | 0.0038 | 0.0013 | 0.0005 | 0.0009 | 0.0016 | 0.0005 | 0.0012 | 0.0010 |
41 | 0.0019 | 0.0010 | 0.0037 | 0.0013 | 0.0004 | 0.0008 | 0.0013 | 0.0004 | 0.0010 | 0.0009 |
42 | 0.0017 | 0.0009 | 0.0034 | 0.0012 | 0.0003 | 0.0006 | 0.0012 | 0.0004 | 0.0009 | 0.0007 |
43 | 0.0015 | 0.0008 | 0.0032 | 0.0010 | 0.0002 | 0.0006 | 0.0011 | 0.0003 | 0.0007 | 0.0007 |
44 | 0.0013 | 0.0007 | 0.0029 | 0.0008 | 0.0002 | 0.0005 | 0.0010 | 0.0003 | 0.0007 | 0.0006 |
45 | 0.0012 | 0.0006 | 0.0027 | 0.0007 | 0.0002 | 0.0005 | 0.0008 | 0.0003 | 0.0006 | 0.0005 |
Incidence rates
The following figure shows the change of incidence rate for 10 replicate simulations. As you can see, the incidence rates increase rapidly at first. After day 15, due to the increase of social distancing, reflected by lowered production number, the population incidence rates start to decline after a few days of lag.
incidence_rate.plot(xlabel='days', ylabel='incidence rate')
The following figure shows sample incidence rates from 3 of the simulations, estimated from sampling 10% of the population (~ 500 people). Due to the overall low incidence rate, the estimates from the samples vary greatly.
sample_incidence_rate[[1, 2, 3]].plot(xlabel='days', ylabel='sample incidence rate')
Availability
This notebook is available under the Applications
directory of the GitHub repository of the COVID19 Outbreak Simulator. It can be executed with sos-papermill
with the following parameters, or using a docker image bcmictr/outbreak-simulator-notebook
as described in here.
- Older
- Newer