knitr::opts_chunk$set(echo=TRUE, results='hide', message=FALSE, warning=FALSE)
You will need to install the package, "pfilterCOVID", before using the pfilter function in the document
# devtools::load_all() # devtools::install() devtools::install_github("kimfinale/pfilterCOVID", force = TRUE)
library(pfilterCOVID) library(deSolve) library(tidyverse) library(cowplot) library(EpiEstim) library(foreach) library(doParallel) source('R/deconvolve.R') theme_set(theme_bw())
# beta is updated by R0 THETA <- list(beta = 0.3, R0 = 1.2, epsilon = 1/2.5, delta = 1/5, gamma = 1/2.5, bp = 1, ba = 1, fa = 0.3, fd = 1, I0 = 1e2, time_dep_Rt = FALSE) # This changes the default y0 in the pfilterCOVID package THETA$Y0 <- c(S = 1e7 - THETA$I0, E = 0, P = 0, A = 0, I = THETA$I0, R = 0, CE = 0, CI = 10, CR = 0) THETA$tend <- 200 usethis::use_data(THETA, overwrite = TRUE) params <- THETA
params <- THETA tend <- params$tend params$I0 <- 100 params$Y0 <- c(S = 1e7 - params$I0, E = 0, P = 0, A = 0, I = params$I0, R = 0, CE = 0, CI = 0, CR = 0) tstamp <- format(Sys.time(), "%Y%m%d") times <- seq(0, tend, by = 1) params$time_dep_Rt <- TRUE ode(y = params$Y0, times = times, func = ode_sepair, parms = params) %>% as.data.frame() -> out out$daily_infected <- c(0, diff(out$CE)) out$daily_symptom <- c(0, diff(out$CI)) out$daily_confirmed <- c(0, diff(out$CR)) out$daily_Rt <- sapply(0:tend, function(x) get_Rt(x)) # saveRDS(out, paste0("outputs/ode_I0_100_", tstamp, ".rds"))
tstamp <- "20230619" out <- readRDS(paste0("outputs/ode_I0_100_", tstamp, ".rds")) out_long <- out %>% pivot_longer(-time) out_long$name <- factor(out_long$name, levels = c("S", "E", "P", "A", "I", "R", "CE", "CI", "CR", "daily_infected", "daily_symptom", "daily_confirmed", "daily_Rt")) fig2a <- out_long %>% filter(name == "daily_infected" | name == "daily_symptom" | name == "daily_confirmed") %>% ggplot(aes(x = time, y = value, color = name)) + geom_line(linewidth=1.2) + labs(x='Time (day)', y = 'Number of individuals', color = "") + theme(legend.position = c(.2, .9), legend.background = element_rect(fill='transparent')) + scale_color_hue(labels=c("daily_infected" = "Infection", "daily_symptom"="Symptom", "daily_confirmed"="Confirmation"))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13))
Plots of Rt and infection/confirmation time series of stoch outputs NB. Figure 1 is a compartment flow diagram which was not generated by code
# Rt data set; Rt_dataset_I0=100_20220105.rds, Rt_dataset_I0=10_20220105.rds tstamp <- "20220105" dat <- readRDS(paste0("outputs/Rt_dataset_I0=100_", tstamp, ".rds")) # Generate Figure 2B. # plot for the pre-defined Rt fig2b <- ggplot() + geom_line(aes(x=dat$time, y = dat$Rt), linewidth=1.4) + labs(x="Time (day)", y = expression(paste(italic(R)[italic(t)])))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text = element_text(size=13)) figure2 <- plot_grid(fig2a, fig2b, nrow = 2, labels = "AUTO") figure2 # Generate plots for a comparison of simulated data (deterministic vs. stochastic, both with perfect observation) for daily_infected or confirmed. oderes <- dat$ode[, c("time", "daily_infected", "daily_confirmed")] oderes %>% pivot_longer(cols = -time) -> oderes stochres <- dat$stoch_perfect_obs$daily_confirmed[,1:length(dat$stoch_perfect_obs$daily_confirmed)] stochres$time <- dat$time stochres %>% pivot_longer(cols = -time) -> stochres # plt_case <- ggplot() + # geom_line(data = stochres, aes(time, value, group=name), color="grey50") + # geom_line(data = oderes, aes(time, value, color=name), size=1.2) + # labs(x="time", y="", color="")
This is to create a stochastic data set based on the Gillespie's direct method
set.seed(42) # tstamp <- format(Sys.time(), "%Y%m%d") nrun <- 20 # increase the number to obtain large samples res <- gillespie_run(func = gillespie_sepair, tend = tend, nrun = nrun, y0 = params$Y0, params = params, report_dt = 1) # saveRDS(res, "outputs/res_20230619.rds")
res <- readRDS("outputs/res_20230619.rds") nrun <- 20 tend <- params$tend daily_infected <- data.frame(matrix(0, nrow = tend + 1, ncol = nrun)) daily_symptom <- data.frame(matrix(0, nrow = tend + 1, ncol = nrun)) daily_confirmed <- data.frame(matrix(0, nrow = tend + 1, ncol = nrun)) for (i in seq_len(length(res))) { inf <- diff(res[[i]]$CE) onset <- diff(res[[i]]$CI) conf <- diff(res[[i]]$CR) daily_infected[1:(length(inf)+1), i] <- c(0, inf) daily_symptom[1:(length(onset)+1), i] <- c(0, onset) daily_confirmed[1:(length(conf)+1), i] <- c(0, conf) } daily_infected <- data.frame(matrix(0, nrow = tend + 1, ncol = nrow(dat$stoch_perfect_obs$daily_infected))) for (i in 1:nrow(dat$stoch_perfect_obs$daily_infected)) { daily_infected[,i] <- dat$stoch_perfect_obs$daily_infected[[i]] } stoch <- list() stoch$daily_confirmed <- daily_confirmed stoch$daily_symptom <- daily_symptom stoch$daily_infected <- daily_infected stoch$daily_Rt <- sapply(0:tend, function(x) get_Rt(x)) # "stoch" contains daily time series for infection, symptom, and confirmation (corresponds to the dataset, D2, in the manuscript) # saveRDS(stoch, paste0("outputs/stoch_I0_100_", tstamp, ".rds")) df <- daily_infected df$time <- 0:tend df %>% pivot_longer(cols = -time) -> df # Generate Figure 3. locy = c(2000,1920,1840) fig3 <- ggplot() + geom_line(data = df, aes(time, value, group = name), color = "grey80") + geom_line(data = out, aes(time, daily_infected), # ODE model output color = "darkred", size = 1.5, inherit.aes = FALSE) + labs(x="Time (day)", y="Daily infected cases", color="") + geom_segment(aes(x=c(0,0,0), xend=c(5,5,5), y=locy, yend=locy), size=c(1,1,1), color = c("grey80", "darkred","black"), linetype = c("solid","solid","dotted")) + geom_line(aes(dat$time, rowMeans(dat$stoch_perfect_obs$daily_infected)), # mean of stochastic simulations ## simply to load the data we are using (2,000 simulations) - save time linetype = "dotted", size = 1.5, inherit.aes = FALSE) + geom_text(aes(x=c(7,7,7), y=locy), size=c(4.6,4.6,4.6), hjust = c(0,0,0), vjust = c(0.5,0.5,0.5), label = c("Stochastic simulations", "Determinstic simulation", "Mean of stochastic simulations"))+ theme(text = element_text(size=16), axis.text = element_text(size=15), legend.text=element_text(size=15)) fig3 # ggsave("plots/daily_case_20230619.png", plot=figure2, # width=3.4*3, height=2.7*3, units="in")
The data set that contains all the necessary information: Rt trajectory, ODE and stochastic model result
Rt_dataset <- list() Rt_dataset$README <- "To see if potential bias of Rt estimation based on the confirmation data set, especially in the most recent time, is reduced or eliminated when the number of cases are large" Rt_dataset$ode <- out Rt_dataset$stoch_perfect_obs <- stoch Rt_dataset$Rt <- sapply(0:tend, function(x) get_Rt(x)) Rt_dataset$time <- out$time Rt_dataset$params <- params Rt_dataset$y0 <- params$Y0 # saveRDS(Rt_dataset, paste0("outputs/Rt_dataset_I0=100_", tstamp, ".rds"))
Particle filtering - particle_filter Expect errors since backward sampling is not in place
set.seed(1) tstamp <- "20220105" I0 <- 100 dat <- readRDS(paste0("outputs/Rt_dataset_I0=", I0, "_", tstamp, ".rds")) # determine the data type to model (infection vs. confirmation) dtype <- "confirmation" # dtype <- "infection" if (dtype == "confirmation") { d <- dat$ode[, c("time", "daily_confirmed")] } else { d <- dat$ode[, c("time", "daily_infected")] } dat$params$time_dep_Rt <- FALSE # this must be set FALSE to produce daily estimates params <- dat$params params[["betavol"]] <- 0.2 #standard deviation of the prior distribution npart = 1e4 # increase the number of particles to obtain more accurate estimates pf <- pfilter( params = params, y = params$Y0, data = d, data_type = dtype, npart = npart, tend = nrow(d), dt = 0.1, error_pdf = "pois", systematic_resampling = FALSE, backward_sampling = TRUE, stoch = FALSE) # Rt <- readRDS("outputs/Rt_default.rds") epsilon <- params[["epsilon"]] delta <- params[["delta"]] gamma <- params[["gamma"]] bp <- params[["bp"]] # relative infectiousness of pre-symptomatic state ba <- params[["ba"]] # relative infectiousness of asymptomatic state fa <- params[["fa"]] # fraction of asymptomatic state durP <- (1 / delta - 1 / epsilon) durI <- (1 / gamma) R0_dur <- ((1 - fa) + fa * ba) * durI + bp * durP med <- apply(pf$beta_filtered, 1, quantile, probs = c(0.5)) # plot(dat$time + 2, dat$daily_Rt, type="l", ylim=c(0, max(upper * R0_dur))) # Comarison between the pre-determined Rt and PF (without backward sampling) inferred Rt based on ODE daily_confirmed plot(dat$ode$time + 2, dat$ode$daily_Rt, type="l") lines(med * R0_dur, lwd=2, col=3)
This uses the extract_trace function that calls pfilter function and also executes backward sampling
# apply on infection time series tstamp <- "20220105" dat <- readRDS(paste0("outputs/Rt_dataset_I0=100_", tstamp, ".rds")) params <- dat$params params$time_dep_Rt <- FALSE params[["betavol"]] <- 0.2 # increase the number to improve accuracy nrep <- 1e3 npart <- 1e4 dt <- 0.2 library(parallel) library(doParallel) ncores <- detectCores() - 1 d_inf <- data.frame(date = dat$time, daily_infected = round(dat$ode$daily_infected)) set.seed(42) cl <- makeCluster(getOption("cl.cores", ncores)) doParallel::registerDoParallel(cl)
pf_inf <- foreach(i = 1:nrep, .packages = c("pfilterCOVID"), .inorder = F) %dopar% { extract_trace(params = params, y = params$Y0, data = d_inf, data_type = "infection", npart = npart, tend = nrow(d_inf), dt = dt, error_pdf = "pois", negbin_size = 15, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_inf, "outputs/pf_inf_20230619.rds")
pf_inf <- readRDS("outputs/pf_inf_20230619.rds") nrep <- 1e3 npart <- 1e4 dt <- 0.2 dtype <- "infection" tstamp <- "20220105" parset_chr <- paste0(dtype, "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) pr <- c(0.025, 0.25, 0.5, 0.75, 0.975) Rt_est <- as.data.frame(sapply(pf_inf, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) df_inf <- cbind(Rt_quantile, d_inf) col_fill <- "deepskyblue4" col_dat <- "grey70" df_inf$Rt <- dat$ode$daily_Rt fig4a <- ggplot(df_inf[81:201,], aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill = col_fill, alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill = col_fill, alpha = 0.8) + geom_line(aes(y = `50%`), color = "darkblue", size = 1.2) + geom_line(aes(x = date, y = dat$ode$daily_Rt[80:200]), size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.25))+scale_y_continuous(breaks=seq(0,2.25,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig4a # ggsave(paste0("plots/", parset_chr, ".png"), plt)
# apply on confirmation time series d_conf <- data.frame(date = dat$time, daily_confirmed = round(dat$ode$daily_confirmed))
set.seed(42) cl <- makeCluster(getOption("cl.cores", ncores)) doParallel::registerDoParallel(cl) pf_conf <- foreach(i = 1:nrep, .packages = c("pfilterCOVID"), .inorder = F) %dopar% { extract_trace(params = params, y = params$Y0, data = d_conf, data_type = "confirmation", npart = npart, tend = nrow(d_conf), dt = dt, error_pdf = "pois", negbin_size = 15, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_conf, "outputs/pf_conf_20230619.rds")
pf_conf <- readRDS("outputs/pf_conf_20230619.rds") parset_chr <- paste0(dtype, "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) Rt_est <- as.data.frame(sapply(pf_conf, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) df_conf <- cbind(Rt_quantile, d_conf) df_conf$Rt <- dat$ode$daily_Rt fig4b <- ggplot(df_conf[81:201,], aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill = "orange", alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill = "orange", alpha = 0.8) + geom_line(aes(y = `50%`), color = "brown", size = 1.2) + geom_line(aes(x = date, y = dat$ode$daily_Rt[80:200]), size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.25))+scale_y_continuous(breaks=seq(0,2.25,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig4b # put all together for figure 3 figure4 <- plot_grid(fig4a, fig4b, nrow = 2, labels = "AUTO") figure4 # ggsave("plots/Rt_recovered_20230619.png", plot=figure3, # width=3.4*2, height=2.7*2, units="in")
tstamp <- "20220105" dat <- readRDS(paste0("outputs/Rt_dataset_I0=100_", tstamp, ".rds")) params <- dat$params params$time_dep_Rt <- FALSE params[["betavol"]] <- 0.2 nrep <- 1e3 npart <- 1e4 dt <- 0.2 d_stoc_19 <- data.frame(date = dat$time, daily_confirmed = round(dat$stoch_perfect_obs$daily_confirmed[,19]))
library(parallel) library(doParallel) set.seed(42) ncores <- detectCores() cl <- makeCluster(getOption("cl.cores", 2)) doParallel::registerDoParallel(cl) # apply on the stochastic seed #19 (fig 4b) pf_stoc_19 <- foreach(i = 1:nrep, .packages = c("pfilterCOVID"), .inorder = F) %dopar% { extract_trace(params = params, y = params$Y0, data = d_stoc_19, data_type = "confirmation", npart = npart, tend = nrow(d_stoc_19), dt = dt, error_pdf = "pois", negbin_size = 15, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_stoc_19, "outputs/pf_stoc_19_20230619.rds")
pf_stoc_19 <- readRDS("outputs/pf_stoc_19_20230619.rds") parset_chr <- paste0(dtype, "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) pr <- c(0.025, 0.25, 0.5, 0.75, 0.975) Rt_est <- as.data.frame(sapply(pf_stoc_19, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) df_stoc_19 <- cbind(Rt_quantile, d_stoc_19) col_fill <- "red" col_dat <- "grey70" df_stoc_19$Rt <- dat$ode$daily_Rt fig5b <- ggplot(df_stoc_19[81:201,], aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill = col_fill, alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill = col_fill, alpha = 0.8) + geom_line(aes(y = `50%`), color = "darkred", size = 1.2) + geom_line(aes(x = date + 1, y = Rt), size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.75))+ scale_y_continuous(breaks=seq(0,2.75,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig5b
# apply on the stochastic seed #04 (fig 4c) d_stoc_04 <- data.frame(date = dat$time, daily_confirmed = round(dat$stoch_perfect_obs$daily_confirmed[,4]))
set.seed(42) cl <- makeCluster(getOption("cl.cores", 2)) doParallel::registerDoParallel(cl) pf_stoc_04 <- foreach(i = 1:nrep, .packages = c("pfilterCOVID"), .inorder = F) %dopar% { extract_trace(params = params, y = params$Y0, data = d_stoc_04, data_type = "confirmation", npart = npart, tend = nrow(d_stoc_04), dt = dt, error_pdf = "pois", negbin_size = 15, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_stoc_04, "outputs/pf_stoc_04_20230619.rds")
pf_stoc_04 <- readRDS("outputs/pf_stoc_04_20230619.rds") parset_chr <- paste0(dtype, "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) pr <- c(0.025, 0.25, 0.5, 0.75, 0.975) Rt_est <- as.data.frame(sapply(pf_stoc_04, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) df_stoc_04 <- cbind(Rt_quantile, d_stoc_04) col_fill <- "green" col_dat <- "grey70" df_stoc_04$Rt <- dat$ode$daily_Rt fig5c <- ggplot(df_stoc_04[81:201,], aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill = "#76ff7a", alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill = "green", alpha = 0.8) + geom_line(aes(y = `50%`), color = "darkgreen", size = 1.2) + geom_line(aes(x = date + 1, y = Rt), size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.5))+ scale_y_continuous(breaks=seq(0,2.5,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig5c
Incidence level is lower than the deterministic model
# apply on the stochastic seed #02 (fig 4d) d_stoc_02 <- data.frame(date = dat$time, daily_confirmed = round(dat$stoch_perfect_obs$daily_confirmed[,2]))
set.seed(42) cl <- makeCluster(getOption("cl.cores", 2)) doParallel::registerDoParallel(cl) pf_stoc_02 <- foreach(i = 1:nrep, .packages = c("pfilterCOVID"), .inorder = F) %dopar% { extract_trace(params = params, y = params$Y0, data = d_stoc_02, data_type = "confirmation", npart = npart, tend = nrow(d_stoc_02), dt = dt, error_pdf = "pois", negbin_size = 15, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_stoc_02, "outputs/pf_stoc_02_20230619.rds")
pf_stoc_02 <- readRDS("outputs/pf_stoc_02_20230619.rds") parset_chr <- paste0(dtype, "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) pr <- c(0.025, 0.25, 0.5, 0.75, 0.975) Rt_est <- as.data.frame(sapply(pf_stoc_02, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) df_stoc_02 <- cbind(Rt_quantile, d_stoc_02) col_fill <- "blue" col_dat <- "grey70" df_stoc_02$Rt <- dat$ode$daily_Rt fig5d <- ggplot(df_stoc_02[81:201,], aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill = "orange", alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill = "orange", alpha = 0.8) + geom_line(aes(y = `50%`), color = "brown", size = 1.2) + geom_line(aes(x = date + 1, y = Rt), size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.5))+ scale_y_continuous(breaks=seq(0, 2.5, by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig5d # Generate figure 5 df_stoc <- data.frame(date=dat$ode$time, ode=dat$ode$daily_confirmed, c2=dat$stoch_perfect_obs$daily_confirmed[,2], c4=dat$stoch_perfect_obs$daily_confirmed[,4], c19=dat$stoch_perfect_obs$daily_confirmed[,19]) fig5a <- ggplot(df_stoc) + geom_line(aes(x=date, y=ode), linewidth=1, color="black")+geom_line(aes(x=date,y=c2),linewidth=1,color="orange")+geom_line(aes(x=date,y=c4),color="green")+geom_line(aes(x=date,y=c19),color="red") + labs(y = "Number of confirmation", x = "Time (day)") + scale_color_hue(labels=c("ode" = "ODE", "c2"="Low", "c4"="Medium", "c19"="High")) + geom_segment(aes(x=0, xend=5, y=1000, yend=1000), size=1.1, color = "red", linetype = "solid") + geom_segment(aes(x=0, xend=5, y=950, yend=950), size=1.1, color = "green", linetype = "solid") + geom_segment(aes(x=0, xend=5, y=900, yend=900), size=1.1, color = "orange", linetype = "solid") + geom_text(aes(x=7, y=1000), size=4.6, hjust=0, vjust=0.5, label="High intensity") + geom_text(aes(x=7, y=950), size=4.6, hjust=0, vjust=0.5, label="Medium intensity") + geom_text(aes(x=7, y=900), size=4.6, hjust=0, vjust=0.5, label="Low intensity")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig5a left_col <- plot_grid(fig5a, labels = c("A")) right_col <- plot_grid(fig5b, fig5c, fig5d, nrow = 3, labels = c("B", "C", "D")) figure5 <- plot_grid(left_col, right_col, ncol = 2) figure5 # ggsave("plots/Rt_stoch_recovered_20230619.png", plot=figure4, # width=3.4*2, height=2.7*2, units="in")
Computing mean and std of generation time
# infection (disease) age for generation time norm_factor <- integrate(function(x) { 1 - pgamma(x, shape = 2, rate = 1/2.5)}, 0, Inf) f <- function(x) { (1 - pgamma(x, shape = 2, rate = 1/2.5))/norm_factor$value} # latent time g <- function(x) { dexp(x, rate = 1/2.5) } z <- function(z) { integrate(function(x, z) g(z-x)*f(x), 0, Inf, z)$value} fz <- Vectorize(z) ## upper is set to arbitrarily large number mean_int <- integrate(function(y) y*fz(y), lower = 0, upper = 100, subdivisions = 1e4) var_int <- integrate(function(y) y^2*fz(y), lower = 0, upper = 100, subdivisions = 1e4) var <- var_int$value - mean_int$value^2 # variance = E[x^2] - E[X]^2 mean_int$value sqrt(var) # from Mathematica mean <- 6.25 # mean_si std <- 4.14578 # std_si
Expect discrepancy (i.e., delay) between the pre-defined Rt and the estimated Rt)
# Moving average MA <- function(input_ts, lookback) { sum <- 0 look_back1 <- lookback + 1 ma_input <- rep(0, length(input_ts)) for (i in 1:length(input_ts)) { sum = sum + input_ts[i] if (i < look_back1) { ma_input[i] <- sum / i } else { sum = sum - input_ts[i-7] ma_input[i] <- sum / 7 } } return(ma_input) } # apply EpiEstim on confirmation time series (ODE version) ma_input <- MA(dat$ode$daily_confirmed, 7) T <- length(ma_input) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(ma_input, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 6.25, std_si = 4.14578)))) df_epi_ode_conf <- data.frame(sapply(res_daily$R,c)) df_epi_ode_conf$Rt <- dat$ode$daily_Rt[3:201] df_epi_ode_conf$time <- t_start-1 col_fill <- "deepskyblue4" col_dat <- "grey70" figure6 <- ggplot(df_epi_ode_conf[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "orange", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "orange", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "darkblue", size = 1.2) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) figure6 # ggsave("plots/EpiEstim_Rt_delay_20230619.png", plot=figure5, # width=3.4*2, height=2.7, units="in")
delay_dist <- { t <- seq(0, 19) p_unnorm <- pgamma(t + 1, shape = 3, rate = 1/2.5) - pgamma(t, shape = 3, rate = 1/2.5) data.frame(delay = t, pmf = p_unnorm / sum(p_unnorm)) }
Estimate Rt by applying deconvolution on confimration series, followed by EpiEstim
# apply on the stochastic seed #19 (fig 6a) input_ts <- dat$stoch_perfect_obs$daily_confirmed[,19] # obtain moving average before deconvolution ma <- seq(0, length(input_ts)-1) lookback <- 7 sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time), n_iterations_max = 100, n_iterations = NULL ) # output to the above opearation is defined as "result$x_unobs" unobs <- result$x_unobs # simple plots for the output of deconvolution (i.e., inferred infection), and the infection from the ODE model # determine an appropriate lag value by comparing the peaks # plot(unobs) # lines(dat$ode$daily_infected) lag <- which.max(dat$ode$daily_infected) - which.max(unobs) #lag # adjust the inferred infection (i.e., unobs) # exclude first 4 elements of unobs (when, e.g., lag=4) as out of estimation period of our interest # this causes 4 less estimates (i.e., upto t=196 instead of t=200 for lag=4) unobs <- unobs[5:length(unobs)] # now apply EpiEstim T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 6.25, std_si = 4.14578)))) # used the mean and std of generation time above for mean_si and std_si df_epi_19 <- data.frame(sapply(res_daily$R,c)) df_epi_19 <- rbind(df_epi_19, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_19$time <- dat$time[3:201] df_epi_19$Rt <- dat$ode$daily_Rt[3:201] # df_deconv$sto_per_high <- df_epi_19$Median.R. plt_epi_19 <- ggplot(df_epi_19[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "#ff6961", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "red", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "darkred", size = 1.2) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.5, 2))+ scale_y_continuous(breaks=seq(0,2,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # apply on the stochastic seed #4 (fig 6b) input_ts <- dat$stoch_perfect_obs$daily_confirmed[,4] ma <- seq(0, length(input_ts)-1) lookback <- 7 sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time), n_iterations_max = 100, n_iterations = NULL ) unobs <- result$x_unobs unobs <- unobs[5:length(unobs)] T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 6.25, std_si = 4.14578)))) # graph df_epi_4 <- data.frame(sapply(res_daily$R,c)) df_epi_4 <- rbind(df_epi_4, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_4$time <- dat$time[3:201] df_epi_4$Rt <- dat$ode$daily_Rt[3:201] # df_deconv$sto_per_high <- df_epi_4$Median.R. plt_epi_4 <- ggplot(df_epi_4[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "#76ff7a", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "green", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "darkgreen", size = 1.2) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.5, 2))+ scale_y_continuous(breaks=seq(0,2,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # apply on the stochastic seed #2 (fig 6c) input_ts <- dat$stoch_perfect_obs$daily_confirmed[,2] ma <- seq(0, length(input_ts)-1) lookback <- 7 sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time), n_iterations_max = 100, n_iterations = NULL ) unobs <- result$x_unobs unobs <- unobs[5:length(unobs)] T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 6.25, std_si = 4.14578)))) df_epi_2 <- data.frame(sapply(res_daily$R,c)) df_epi_2 <- rbind(df_epi_2, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_2$time <- dat$time[3:201] df_epi_2$Rt <- dat$ode$daily_Rt[3:201] # df_deconv$sto_per_high <- df_epi_2$Median.R. plt_epi_2 <- ggplot(df_epi_2[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "orange", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "orange", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "brown", size = 1) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "darkblue", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.5, 2))+ scale_y_continuous(breaks=seq(0,2,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) figure7 <- plot_grid(plt_epi_19, plt_epi_4, plt_epi_2, nrow = 3, labels = c("A", "B", "C")) figure7 # ggsave("plots/EpiEstim_Rt_deconvolution_20230619.png", plot=figure6, # width=3.4*2, height=2.7*2, units="in")
Estimate Rt by applying deconvolution on confimration series, followed by EpiEstim
# apply on the stochastic seed #19 (fig 7a) input_ts <- dat$stoch_perfect_obs$daily_confirmed[,19] ma <- seq(0, length(input_ts)-1) lookback <- 7 sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time), n_iterations_max = 100, n_iterations = NULL ) unobs <- result$x_unobs unobs <- unobs[5:length(unobs)] T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 5, std_si = 4.14578)))) # misspecification effect: used mean_si=5, istead of 6.25 df_epi_19m <- data.frame(sapply(res_daily$R,c)) df_epi_19m <- rbind(df_epi_19m, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_19m$time <- dat$time[3:201] df_epi_19m$Rt <- dat$ode$daily_Rt[3:201] # df_deconv$mis_sto_per_low <- df_epi_2m$Median.R. plt_epi_19m <- ggplot(df_epi_19m[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "#ff6961", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "red", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "darkred", size = 1.2) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # apply on the stochastic seed #4 (fig 7b) input_ts <- dat$stoch_perfect_obs$daily_confirmed[,4] ma <- seq(0, length(input_ts)-1) lookback <- 7 sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time), n_iterations_max = 100, n_iterations = NULL ) # output to the above opearation is defined as "result$x_unobs" unobs <- result$x_unobs unobs <- unobs[5:length(unobs)] # epiestim_4m T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 5, std_si = 4.14578)))) df_epi_4m <- data.frame(sapply(res_daily$R,c)) df_epi_4m <- rbind(df_epi_4m, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_4m$time <- dat$time[3:201] df_epi_4m$Rt <- dat$ode$daily_Rt[3:201] # df_deconv$mis_sto_per_low <- df_epi_2m$Median.R. plt_epi_4m <- ggplot(df_epi_4m[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "#76ff7a", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "green", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "darkgreen", size = 1.2) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # apply on the stochastic seed #2 (fig 7c) input_ts <- dat$stoch_perfect_obs$daily_confirmed[,2] ma <- seq(0, length(input_ts)-1) sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time), n_iterations_max = 100, n_iterations = NULL ) unobs <- result$x_unobs unobs <- unobs[5:length(unobs)] T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 5, std_si = 4.14578)))) df_epi_2m <- data.frame(sapply(res_daily$R,c)) df_epi_2m <- rbind(df_epi_2m, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_2m$time <- dat$time[3:201] df_epi_2m$Rt <- dat$ode$daily_Rt[3:201] # df_deconv$mis_sto_per_low <- df_epi_2m$Median.R. plt_epi_2m <- ggplot(df_epi_2m[80:199,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = "orange", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = "orange", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "brown", size = 1) + geom_line(aes(x = time, y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "darkblue", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) figure8 <- plot_grid(plt_epi_19m, plt_epi_4m, plt_epi_2m, nrow = 3, labels = c("a", "b", "c")) figure8 # ggsave("plots/EpiEstim_stoch_Rt_deconvolution_20230619.png", plot=figure7, # width=3.4*2, height=2.7*2, units="in")
Plot for the curve of pre-defined Rt by periods of different epidemic characteristics
R_flat <- c(dat$Rt[1:101], rep(NA,32), dat$Rt[134:195], rep(NA, 6)) R_curve <- c(rep(NA, 100), dat$Rt[101:127], rep(NA, 74)) R_curve_last <- c(rep(NA, 126), dat$Rt[127:134], rep(NA, 67)) R_last <- c(rep(NA, 194), dat$Rt[195:201]) figure9 <- ggplot()+ geom_line(aes(x=dat$time, y=R_flat), color="black", linewidth=1.2)+ geom_line(aes(x=dat$time, y=R_curve), color="red", linewidth=1.2)+ geom_line(aes(x=dat$time, y=R_curve_last), linetype="dotted", color="red", linewidth=1.2)+ geom_line(aes(x=dat$time, y=R_last), linetype="dotted", linewidth=1.2)+ labs(y=expression(italic(R)[italic(t)]), x="Time (day)")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) figure9 # ggsave("plots/Rt_sections_20230619.png", plot=figure8, # width=3.4*2, height=2.7*2, units="in")
input_ts <- dat$stoch_perfect_obs$daily_confirmed[,4][1:133] # PF d_stoc_04_mid <- data.frame(date = dat$time[1:133], daily_confirmed = round(dat$stoch_perfect_obs$daily_confirmed[,4][1:133]))
set.seed(42) cl <- makeCluster(getOption("cl.cores", 2)) doParallel::registerDoParallel(cl) pf_stoc_04_mid <- foreach(i = 1:nrep, .packages = c("pfilterCOVID"), .inorder = F) %dopar% { extract_trace(params = params, y = params$Y0, data = d_stoc_04_mid, data_type = "confirmation", npart = npart, tend = nrow(d_stoc_04_mid), dt = dt, error_pdf = "pois", negbin_size = 15, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_stoc_04_mid, "outputs/pf_stoc_04_mid_20230619.rds")
pf_stoc_04_mid <- readRDS("outputs/pf_stoc_04_mid_20230619.rds") parset_chr <- paste0("confirmation", "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) pr <- c(0.025, 0.25, 0.5, 0.75, 0.975) Rt_est <- as.data.frame(sapply(pf_stoc_04_mid, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) df_stoc_04_mid <- cbind(Rt_quantile, d_stoc_04_mid) col_fill <- "deepskyblue4" col_dat <- "grey70" df_stoc_04_mid$Rt <- dat$ode$daily_Rt[1:133] fig10a <- ggplot(df_stoc_04_mid[81:133,], aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill="orange", alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill="orange", alpha = 0.8) + geom_line(aes(y = `50%`), color="brown", size = 1.2) + geom_line(aes(x = date, y = df_stoc_04_mid$Rt[80:132]), size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.75))+scale_y_continuous(breaks=seq(0,2.75,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # EpiEstim ma <- seq(0, length(input_ts)-1) lookback <- 7 sum <- 0 for (i in 1:length(input_ts)){ sum = sum + input_ts[i] if (i < lookback+1) { ma[i] = sum / i } else { sum = sum - input_ts[i-7] ma[i] = sum / 7 } } result <- deconvolve_rltype_goldsteinetal( t_obs_min = dat$time[1], y_obs = round(ma), delay_min = delay_dist$delay[1], pmf_delay = delay_dist$pmf, t_unobs_min = dat$time[1], n_unobs = length(dat$time[1:133]), n_iterations_max = 100, n_iterations = NULL ) unobs <- result$x_unobs # adjustment of unobs unobs <- unobs[5:133] T <- length(unobs) time_window <- 1 t_start <- seq(3, T-(time_window-1)) t_end <- t_start + time_window-1 # res_daily: without misspecification of SI # res_daily_m: with misspecification of SI res_daily <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 6.25, std_si = 4.14578)))) res_daily_m <- estimate_R(unobs, method = "parametric_si", config = make_config((list(t_start = t_start, t_end = t_end, mean_si = 5, std_si = 4.14578)))) df_epi_4_mid <- data.frame(sapply(res_daily$R, c)) df_epi_4_mid_m <- data.frame(sapply(res_daily_m$R, c)) df_epi_4_mid <- df_epi_4_mid[,c(5,7,8,9,11)] df_epi_4_mid_m <- df_epi_4_mid_m[,c(5,7,8,9,11)] df_epi_4_mid <- rbind(df_epi_4_mid, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_4_mid_m <- rbind(df_epi_4_mid_m, c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA), c(NA,NA,NA,NA,NA)) df_epi_4_mid$time <- dat$time[3:133] df_epi_4_mid$Rt <- dat$ode$daily_Rt[3:133] df_epi_4_mid_m$time <- dat$time[3:133] df_epi_4_mid_m$Rt <- dat$ode$daily_Rt[3:133] # fig10b fig10b <- ggplot(df_epi_4_mid[79:131,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill = col_fill, alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax = Quantile.0.75.R.), fill = col_fill, alpha = 0.8) + geom_line(aes(y = Median.R.), color = "darkblue", size = 1.2) + geom_line(aes(y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.75))+ scale_y_continuous(breaks=seq(0,2.75,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) # fig10c fig10c <- ggplot(df_epi_4_mid_m[79:131,], aes(x = time)) + geom_ribbon(aes(ymin = Quantile.0.025.R., ymax = Quantile.0.975.R.), fill="orange", alpha = 0.5) + geom_ribbon(aes(ymin = Quantile.0.25.R., ymax=Quantile.0.75.R.), fill="orange", alpha = 0.8) + geom_line(aes(y = Median.R.), color = "brown", size = 1.2) + geom_line(aes(y = Rt), colour = "black", size = 1, linetype = "dashed") + geom_hline(yintercept = 1, color = "black", size = 1, linetype = "dotted")+ labs(y = expression(italic(R)[italic(t)]), x = "Time (day)") + coord_cartesian(ylim = c(0.25, 2.75))+ scale_y_continuous(breaks=seq(0,2.75,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13)) figure10 <- plot_grid(fig10a, fig10b, fig10c, nrow=3, labels=c("A", "B", "C")) figure10 # ggsave("plots/Rt_PF_EpiEstim_20230619.png", plot=figure9, # width=3.4*2, height=2.7*2, units="in")
dg <- df_stoc_04[82:201,] dg1 <- df_epi_4[84:199,] dg2 <- df_epi_4m[84:199,] # # flat_Rt <- c(dg$Rt[1:20], dg$Rt[53:120]) flat_PF_Rt <- c(dg$`50%`[1:20], dg$`50%`[53:120]) flat_epi_Rt <- c(dg1$Median.R.[1:20], dg1$Median.R.[53:116], NA, NA, NA, NA) flat_epim_Rt <- c(dg2$Median.R.[1:20], dg2$Median.R.[53:116], NA, NA, NA, NA) # # general_period <- list("PF" = sqrt(mean((df_stoc_04[82:201,]$Rt - df_stoc_04[82:201,]$`50%`)^2, na.rm=TRUE)), "EpiEstim" = sqrt(mean((df_stoc_04[82:197,]$Rt - df_epi_4[84:199,]$Median.R.)^2, na.rm=TRUE)), "EpiEstim_m" = sqrt(mean((df_stoc_04[82:197,]$Rt - df_epi_4m[84:199,]$Median.R.)^2, na.rm=TRUE))) flat_period <- list("PF" = sqrt(mean((flat_Rt - flat_PF_Rt)^2, na.rm=TRUE)), "EpiEstim" = sqrt(mean((flat_Rt - flat_epi_Rt)^2, na.rm=TRUE)), "EpiEstim_m" = sqrt(mean((flat_Rt - flat_epim_Rt)^2, na.rm=TRUE))) last_flat <- list("PF" = sqrt(mean((flat_Rt[82:88] - flat_PF_Rt[82:88])^2, na.rm=TRUE)), "EpiEstim" = sqrt(mean((flat_Rt[82:88] - flat_epi_Rt[82:88])^2, na.rm=TRUE)), "EpiEstim_m" = sqrt(mean((flat_Rt[82:88] - flat_epim_Rt[82:88])^2, na.rm=TRUE))) fluctuation <- list("PF" = sqrt(mean((dat$ode$daily_Rt[99:133] - df_stoc_04_mid[99:133,]$`50%`)^2, na.rm=TRUE)), "EpiEstim" = sqrt(mean((dat$ode$daily_Rt[99:133] - df_epi_4_mid[99:133,]$Median.R.)^2, na.rm=TRUE)), "EpiEstim_m" = sqrt(mean((dat$ode$daily_Rt[99:133] - df_epi_4_mid_m[99:133,]$Median.R.)^2, na.rm=TRUE))) last_fluctuaion <- list("PF" = sqrt(mean((dat$ode$daily_Rt[127:133] - df_stoc_04_mid[127:133,]$`50%`)^2, na.rm=TRUE)), "EpiEstim" = sqrt(mean((dat$ode$daily_Rt[127:133] - df_epi_4_mid[127:133,]$Median.R.)^2, na.rm=TRUE)), "EpiEstim_m" = sqrt(mean((dat$ode$daily_Rt[127:133] - df_epi_4_mid_m[127:133,]$Median.R.)^2, na.rm=TRUE))) # RMSE table (in the order of PF, EpiEstim,and EpiEstim with misspecification) table2 <- list("general period" = general_period, "flat period" = flat_period, "last 1 week flat" = last_flat, "fluctuation period" = fluctuation, "last 1 week fluctuation" = last_fluctuaion)
set.seed(42) cl <- makeCluster(getOption("cl.cores", detectCores())) registerDoParallel(cl) nrep <- 1000 npart <- 10000 params[["betavol"]] <- 0.20 y0 <- params$Y0 y0["I"] <- 100 y0["E"] <- 100 data <- read_csv("data/daily_confirmed_202009_202110.csv") # data <- data[order(data$date),] # write_csv(data, "data/daily_confirmed_202009_202110.csv") # data$date <- 0:(nrow(data)-1) pf_conf <- foreach(i=1:nrep, .packages=c("pfilterCOVID"), .inorder=F) %dopar% { extract_trace(params = params, y = y0, data = data, data_type = "confirmation", npart = npart, tend = nrow(data), dt = 0.1, error_pdf = "negbin", negbin_size = 100, backward_sampling = TRUE, stoch = FALSE) } parallel::stopCluster(cl) # saveRDS(pf_conf, "outputs/pf_conf_covid_korea_20230729.rds")
Generate Figure 11 (supplmentary figure) Red and green vertical lines represent strengthening and weakening of the social distancing measures.
dtype <- "confirmation" tstamp <- format(Sys.Date(), "%Y%m%d") data <- read_csv("data/daily_confirmed_202009_202110.csv") pf_korea <- readRDS("outputs/pf_conf_covid_korea_20230729.rds") parset_chr <- paste0(dtype, "_I0=", params$I0, "_npart=", npart, "_nrep=", nrep, "_dt=", dt, "_", tstamp) pr <- c(0.025, 0.25, 0.5, 0.75, 0.975) Rt_est <- as.data.frame(sapply(pf_korea, function(x) x[, "Rt"])) Rt_quantile <- as.data.frame(t(apply(Rt_est, 1, function(x) quantile(x, pr)))) cumul_est <- as.data.frame(sapply(pf_korea, function(x) x[, "CR"])) cumul_quantile <- as.data.frame(t(apply(cumul_est, 1, function(x) quantile(x, pr)))) Rtdf <- cbind(Rt_quantile, data) Rtdf$date <- data$date cumuldf <- cbind(cumul_quantile, data) cumuldf$date <- data$date npi_data <- data.frame(date=as.Date(c("2020-10-11", "2021-03-12", "2021-06-11", "2020-11-17", "2020-11-22", "2020-12-05", "2020-12-08", "2020-12-21")), degree = c("Low","Low","Low","High","High","High","High","High")) npi_high <- npi_data %>% filter(degree=="High") npi_low <- npi_data %>% filter(degree=="Low") # Rt fig11a <- ggplot(Rtdf, aes(x = date)) + geom_ribbon(aes(ymin = `2.5%`, ymax = `97.5%`), fill = "steelblue", alpha = 0.5) + geom_ribbon(aes(ymin = `25%`, ymax = `75%`), fill = "steelblue", alpha = 0.8) + geom_line(aes(y = `50%`), color = "steelblue", size = 1.2) + geom_hline(yintercept = 1, color = "black", size = 1, linetype="dotted")+ geom_vline(xintercept=npi_high$date, color="firebrick", size=1)+ geom_vline(xintercept=npi_low$date, color="darkgreen", size=1)+ labs(y = expression(italic(R)[italic(t)]), x="") + scale_x_date(limits=as.Date(c("2020-10-01","2021-06-30")), date_breaks = "2 week")+ scale_y_continuous(limits=c(0,3),breaks=seq(0,3,by=0.5))+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13), axis.text.x=element_text(angle=90,hjust=1)) # fig11a fig11b <- ggplot(cumuldf) + geom_col(aes(x=date, y=daily_confirmed), fill="grey50", alpha=0.3) + geom_ribbon(aes(x=date, ymin=`2.5%`, ymax=`97.5%`), fill="steelblue", alpha=0.3) + geom_ribbon(aes(x = date, ymin = `25%`, ymax=`75%`), fill="steelblue", alpha=0.7) + geom_line(aes(x=date, y=`50%`), color="steelblue", size=1)+ # scale_y_continuous(limits=c(0,2000),breaks=seq(0,1000,by=200))+ labs(title = "", x = "", y = "Daily confirmed case") + scale_x_date(limits=as.Date(c("2020-10-01","2021-06-30")), date_breaks = "2 week")+ theme(text = element_text(size=16), axis.text = element_text(size=13), legend.text=element_text(size=13), axis.text.x=element_text(angle=90,hjust=1)) # fig11b figure11 <- plot_grid(fig11a, fig11b, nrow=2, labels="AUTO") figure11 # ggsave("plots/Rt_confimed_case_korea_20230730.png", plot=figure11, # width=3.4*2, height=2.7*3, units="in")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.