Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

https://doi.org/10.5281/zenodo.15731718
24 June 2025, 17:15:41 UTC
  • Code
  • Branches (0)
  • Releases (1)
  • Visits
    • Branches
    • Releases
      • 1
      • 1
    • 7c9d12f
    • /
    • 06_t20_cricket_forecast.R
    Raw File Download

    To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
    Select below a type of object currently browsed in order to display its associated SWHID and permalink.

    • content
    • directory
    • snapshot
    • release
    origin badgecontent badge
    swh:1:cnt:f55fbb54ffc3997459bc534fef83fd625fd34349
    origin badgedirectory badge
    swh:1:dir:7c9d12f286334bcec2d56e656b51bedec0450877
    origin badgesnapshot badge
    swh:1:snp:caa5e5c1373a152e7394b87e885b1339f8fc68ec
    origin badgerelease badge
    swh:1:rel:b8949b6da5a3c1d416881fc3e15d0848afff9f2d

    This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
    Select below a type of object currently browsed in order to generate citations for them.

    • content
    • directory
    • snapshot
    • release
    (requires biblatex-software package)
    Generating citation ...
    (requires biblatex-software package)
    Generating citation ...
    (requires biblatex-software package)
    Generating citation ...
    (requires biblatex-software package)
    Generating citation ...
    06_t20_cricket_forecast.R
    # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ## FORECAST MODEL ==============================================================
    
    # Description:
    #     Produce dengue risk forecast 3 months ahead in Barbados using final model.
    #     The year index is calculated such that the forecast issue month is month 9 
    #     and the target is month 12. This forecast was issued as of March 2024 for 
    #     dengue outbreak risk in June 2024 for the ICC Men's T20 Cricket World Cup.
    
    # Paper:
    #     Compound and cascading effects of climatic extremes on dengue outbreak
    #     risk in the Caribbean: an impact-based modelling framework with long-lag
    #     and short-lag interactions
    
    # Script authors:
    #     Chloe Fletcher        ORCID: 0000-0002-6705-7605
    #     Prof. Rachel Lowe     ORCID: 0000-0003-3939-7343
    
    # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    
    ## Source packages, functions and data -----------------------------------------
    
    # load packages and functions
    source("functions/00_packages_functions.R")
    
    # read in harmonised data
    data <- read.csv("data/prediction/barbados_fc_2024-03.csv")
    data$dir <- round(data$cases / data$population * 10**5, 3)
    
    
    ## Set model parameters and update dataset -------------------------------------
    
    # forecast values
    vars <- c("tas.3mon.4", "spi6.5", "spi6.1")
    fc_issue_year <- 2024  # calendar year forecast issued
    fc_issue_month <- 3  # calendar month forecast issued
    fc_issue_month_txt <- ifelse(fc_issue_month < 10, paste0("0", fc_issue_month),
                                 as.character(fc_issue_month))  # add leading zero
    
    fc_horizon <- 3
    month <- ifelse(fc_horizon + fc_issue_month > 12,  # actual target month value
                    (fc_horizon + fc_issue_month) %% 12,
                    fc_horizon + fc_issue_month)
    
    # update dataframe
    start_id <- match(month + 1, data$cal_month)
    data <- data[start_id:nrow(data), ]
    
    nyear <- length(unique(data$cal_year)) - 1
    data$month <- rep(1:12, nyear, length.out = nrow(data))
    data$year_index <- rep(1:nyear, each=12, length.out = nrow(data))
    
    # extract last year index and population
    current_year <- max(data$year_index)
    pop <- data[nrow(data), "population"]
    
    
    ## Extract parameters of updated model -----------------------------------------
    
    # model formulation
    re1 <- paste("f(month, model = 'rw2', cyclic = TRUE, constr = TRUE,",
                 "scale.model = TRUE, hyper = precision.prior)")
    re2 <- "f(year_index, model = 'rw2', hyper = precision.prior)"
    fe <- "logdir.4"
    form <- paste(c("cases ~ 1", re1, re2, paste(vars, collapse=' * '), fe),
                  collapse=' + ')
    
    model <- runinlamod(formula(form), data, config=TRUE)
    
    # extract samples from posterior distribution
    s <- 1000
    sam <- inla.posterior.sample(s, model)
    
    sam.extract <- inla.posterior.sample.eval(
      (function(...) {
        beta.1 <- get(vars[1])
        beta.2 <- get(vars[2])
        beta.3 <- get(vars[3])
        beta.4 <- get(fe)
        beta.12 <- get(paste(vars[1:2], collapse=':'))
        beta.13 <- get(paste(vars[c(1,3)], collapse=':'))
        beta.23 <- get(paste(vars[2:3], collapse=':'))
        beta.123 <- get(paste(vars, collapse=':'))
        delta <- get("month")
        gamma <- get("year_index")
        return(c(Intercept, beta.1, beta.2, beta.3, beta.4, beta.12, beta.13, beta.23,
                 beta.123, delta, gamma, theta[1]))
      }), sam)
    
    # assign to individual parameters
    alpha <- sam.extract[1,]
    beta.1 <- sam.extract[2,]
    beta.2 <- sam.extract[3,]
    beta.3 <- sam.extract[4,]
    beta.4 <- sam.extract[5,]
    beta.12 <- sam.extract[6,]
    beta.13 <- sam.extract[7,]
    beta.23 <- sam.extract[8,]
    beta.123 <- sam.extract[9,]
    delta <- sam.extract[10:21,]
    gamma <- sam.extract[22:(21 + max(data$year_index)), ]
    theta <- sam.extract[(22 + max(data$year_index)), ]
    
    
    ## Calculate negative binomial distribution means ------------------------------
    
    # create empty array for distribution means
    fit <- array(NA,
                 dim = c(s, 1),
                 dimnames = list(paste0("s.", 1:s), paste0("t", 1)))
    
    # calculate distribution means
    fit[1:s, 1] <-
      exp(log(pop/100000) +
            alpha +
            beta.1 * data[nrow(data), vars[1]] +
            beta.2 * data[nrow(data), vars[2]] +
            beta.3 * data[nrow(data), vars[3]] +
            beta.4 * data[nrow(data), fe] +
            beta.12 * data[nrow(data), vars[1]] * data[nrow(data), vars[2]] +
            beta.13 * data[nrow(data), vars[1]] * data[nrow(data), vars[3]] +
            beta.23 * data[nrow(data), vars[2]] * data[nrow(data), vars[3]] +
            beta.123 * data[nrow(data), vars[1]] * data[nrow(data), vars[2]] * data[nrow(data), vars[3]] +
            delta[12, ] +
            gamma[(current_year), ])
    
    
    ## Generate posterior predictive distribution ----------------------------------
    
    # create empty array for generated data points
    pred <- array(NA,
                  dim = c(s, 1),
                  dimnames = list(paste0("s.", 1:s), paste0("t", 1)))
    
    # generate data points from negative binomial distribution
    for (n in 1:s){
      pred[n,1] <- rnbinom(1, mu = fit[n,1], size = theta[n])
    }
    
    # save pred output
    fname <- glue("outputs/prediction/pred_t20_{fc_issue_year}{fc_issue_month_txt}.rds")
    #saveRDS(pred, fname)
    
    
    ## Produce forecast visualisations ---------------------------------------------
    
    # read in pred
    pred <- readRDS(fname)
    max_year_index <- max(data$year_index, na.rm = TRUE)
    
    # calculate moving monthly 75th percentile threshold
    pct_75 <- data %>%
      filter(year_index < max_year_index) %>%  # excl. prediction year
      group_by(month) %>%
      summarise(q75 = round(quantile(dir, 0.75) * pop / 10**5, 2))
    
    m <- 12
    oprob <- round(sum(pred[,1] >= pct_75[m, "q75"][[1]]) * 100 / s, 3)
    
    # plot gauge
    q75 <- pct_75[12, 2]
    dens <- density(pred, from = min(pred)) %$%
      data.frame(x = x, y = y) %>%
      mutate(area = x >= q75[[1]])
    
    g1 <- gg.gauge(oprob, breaks = c(0, 29, 50, 70, 100))
    
    # plot probability density function 
    g2 <- ggplot(dens, aes(x = x, ymin = 0, ymax = y, fill = area)) + 
      geom_ribbon() + 
      scale_fill_manual(values = c("grey90", "#5BC0EB")) +
      geom_line(aes(y = y)) +
      geom_vline(xintercept = q75[[1]], color = "#AA1155") +
      labs(x="Predicted Dengue Cases", y="Density") +
      theme_bw(base_size = 14) +
      theme(panel.border = element_blank(), plot.title = element_text(hjust=0.5),
            panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
            legend.position = "none")
    
    # combined risk visualisations
    ggdraw() +
      draw_plot(g1, x = 0, y = 0.5, width = 1, height = 0.5) +
      draw_plot(g2, x = 0, y = 0, width = 1, height = 0.5) +
      draw_plot_label(label = c("A", "B"), size = 15,
                      x = c(0, 0), y = c(1, .5)) +
      theme_bw(base_size = 16) +
      theme(panel.border = element_blank(), plot.title=element_text(hjust=0.5),
            panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
            legend.position="none", axis.text=element_blank(), axis.ticks=element_blank())
    #ggsave("outputs/figs/F_05.png", width=10, height=10, dpi=300)
    
    
    ## END

    back to top

    Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
    The source code of Software Heritage itself is available on our development forge.
    The source code files archived by Software Heritage are available under their own copyright and licenses.
    Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API