#Packages
library(dplyr); library(magrittr);
library(ggplot2); library(ggsci)
library(reshape2)
theme_set(theme_minimal())
This document serves as a technical companion to the piece titled Flattning the Curve at OR/MS Today. As a starter, we repeat the Kermack-McKendric S-I-R model,
\[ dS/dt = -\alpha SI \\ dI/dt = \alpha SI -\rho I \\ dR/dt = \rho I .\]
This is a classic ‘cohort model’; written in matrix form, we can see that the system is closed and the total differential (sum over columns when properly formatted) is zero.
Of interest are the parameters \(\alpha\), which is a measure of both a virus’ infectivity and speed of spread, and \(\rho\) which is a measure (Markovian) of how long the infectious period lasts.
Here’s a function that returns a time-trace of the SIR Model from given Initial Conditions. h is a parameter that controls the internal time-step; i.e. \(dx/dt = lim \space h \rightarrow 0 \space (x(t+h)-x(t))/h\) We are using Euler’s method to evaluate this system of ordinary differential equations. Smaller values of h lead to more accuracy (and also more computing time!)
KMC = function(So = .99, Io = .01, Ro = 0, h = .1,
alpha = .1, rho = 1/14, tmax = 365){
Time = seq(0, tmax, by = h)
#Normalize
Tot = So + Io + Ro
S = So/Tot; I = Io/Tot ;R = Ro/Tot
St = vector(); It = vector(); Rt = vector()
St[1] = S; It[1] = I; Rt[1] = R
#Loop
for(i in 2:length(Time)){
St[i] = max(0, St[i-1] -
(St[i-1]* It[i-1]*alpha *h))
It[i] = max(0, It[i-1] +
(St[i-1]* It[i-1]*alpha *h) - (rho*h*It[i-1]))
Rt[i] = Rt[i-1] +
(rho*h*It[i-1])
}
res = data.frame(t = Time, S = St, I = It, R = Rt)
return(res)
}
Below is a plot of the process, accepting all default values from above:
X = KMC()
X %>% melt(id.vars = "t") %>% ggplot(aes(x = t, y = value, color = variable)) +
geom_line() + scale_color_manual(values = c("blue", "red", "green")) +
xlab("Time (days)") + scale_y_continuous(labels = scales::percent, name = "Proportion of Population" ) + labs(color = "Population")
Our approach is as follows: We wish to vary the virulance of the disease, \(\alpha\) against a fixed, realistic choice for Removals, \(R\). Thus, we wish to benchmark the sojourn time of any given individual to the disease in the presumed incubation period, which is currently estimated at 14 days (Carol check this). While there are several ways to fit data to an epidemic, we will propose the following straightforward application of differential equations.
Let’s consider the equation for I(t):
\[ dI/dt = \alpha SI - \rho I \]
Imagine, if you will, that you have just been infected, and you have immediately been placed alone in quarantine until you are no longer infective. Therefore, the equation above collapses to:
\[ dI/dt = -\rho I \\ s.t. \\ I(0) = 1 \]
Which has the solution
\[I(t) = 1- e^{-\rho t}, \] which the probabilisits will immediately recognize as the CDF of the exponential distribution (this is not a coincidence!) and given estimates of a 2-week infective period 1, we conclude that \(\rho \approx .07\)
We use data from the CDC (table at bottom of article),
CD = read.csv("CDCData.csv")
CD %>% ggplot(aes(x = Julian, y = Cumulative)) + geom_line() + xlab("Julian Date 2020") + ylab("Cumulative cases")
CDD = CD %>% filter(Julian > 45) #Truncates early effects
CDD$Log = log(CDD$Cumulative)
CDD$JD = CDD$Julian - 45
lm1 = lm(Log~JD, data = CDD)
lm1 %>% broom::tidy() %>% knitr::kable()
| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| (Intercept) | 3.1072382 | 0.0759074 | 40.93459 | 0 |
| JD | 0.1036235 | 0.0055415 | 18.69961 | 0 |
We will use \(\alpha = .1\) as a starting point for analysis. This is consistent with a number distilled separately by a group of researchers at LANL 2
Note that the LANL paper uses \(\alpha = .1, R_0 \approx 2.3\) based on infections in Wuhan, China after control measures, with an implied \(\rho = .04\) Our estimate is roughly
The point of this is not the specific values of \(\alpha\) or \(\rho\), but rather how incremental reductions in \(\alpha\) can change the
rho = 1/14;alpha_0 = .1; tmax = 2*365
effects = c(0, .01, .05, .07,.1, .15, .25, .35)
names = c("t", paste0(100*effects,"Pct"))
names = c("t", paste0(100*effects,"%"))
n = length(effects)
X = KMC(tmax = tmax)
output = data.frame(t = X$t) #Infection Curve
out2 = vector() #Total Infection amount
for(i in 1:n){
X = KMC(So = .9999, Io = 1-.9999, rho = rho, alpha = alpha_0*(1-effects[i]), tmax = tmax)
output %<>% cbind(X$I)
out2[i] = max(X$R)
}
names(output) = names
output %>% melt(id.vars = "t") %>%
ggplot(aes(x = t, y = value, color = variable)) + geom_line() +
xlab("time (days)") + scale_y_continuous(labels = scales::percent, name = "Infected") + labs(color = "Countermeasure Effectiveness")
Ultimate size of the epidemic:
data.frame(effect = effects, Size = out2) %>% ggplot(aes(x = effect, y= Size)) + geom_line() + scale_y_continuous(name = "Ultimate size of Epidemic", labels = scales::percent) + xlab("Effectiveness of Countermeasures") + scale_x_continuous(labels = scales::percent)
Data from CDC:
library(knitr)
CD %>% kable()
| Julian | New.Cases | Cumulative |
|---|---|---|
| 11 | 0 | 0 |
| 12 | 0 | 0 |
| 13 | 2 | 2 |
| 14 | 0 | 2 |
| 15 | 1 | 3 |
| 16 | 0 | 3 |
| 17 | 0 | 3 |
| 18 | 0 | 3 |
| 19 | 0 | 3 |
| 20 | 1 | 4 |
| 21 | 1 | 5 |
| 22 | 0 | 5 |
| 23 | 1 | 6 |
| 24 | 2 | 8 |
| 25 | 0 | 8 |
| 26 | 0 | 8 |
| 27 | 2 | 10 |
| 28 | 2 | 12 |
| 29 | 0 | 12 |
| 30 | 0 | 12 |
| 30 | 0 | 12 |
| 31 | 0 | 12 |
| 32 | 0 | 12 |
| 33 | 0 | 12 |
| 34 | 0 | 12 |
| 35 | 0 | 12 |
| 36 | 0 | 12 |
| 37 | 0 | 12 |
| 38 | 0 | 12 |
| 39 | 1 | 13 |
| 40 | 1 | 14 |
| 41 | 0 | 14 |
| 42 | 2 | 16 |
| 43 | 1 | 17 |
| 44 | 0 | 17 |
| 45 | 0 | 17 |
| 46 | 3 | 20 |
| 47 | 4 | 24 |
| 48 | 1 | 25 |
| 49 | 3 | 28 |
| 50 | 6 | 34 |
| 51 | 9 | 43 |
| 52 | 5 | 48 |
| 53 | 11 | 59 |
| 54 | 5 | 64 |
| 55 | 14 | 78 |
| 56 | 6 | 84 |
| 57 | 13 | 97 |
| 58 | 9 | 106 |
| 60 | 19 | 125 |
| 61 | 10 | 135 |
| 62 | 9 | 144 |
| 63 | 7 | 151 |
| 64 | 12 | 163 |
| 65 | 2 | 165 |
| 66 | 7 | 172 |
| 67 | 0 | 172 |
| 68 | 0 | 172 |
“we have little confidence in these estimates”↩
“https://www.medrxiv.org/content/10.1101/2020.02.07.20021154v1.full.pdf”↩