## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4, warning = FALSE, message = FALSE ) oldpar <- par(no.readonly = TRUE) oldopts <- options() library(dplyr) library(tidyr) library(ggplot2) library(kableExtra) library(modelimportance) ## ----results='asis'----------------------------------------------------------- forecast_data_example |> dplyr::filter( .data$reference_date == "2022-12-17", .data$horizon != 0 ) |> head(10) |> knitr::kable( format = "html", caption = "Table 1: Example of the model output for incident influenza hospitalizations (top 10 rows) extracted from `forecast_data_example` bundled in the `modelimportance` package, which is originally from `hubExamples` package.") |> kableExtra::kable_styling( font_size = 12, bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = TRUE ) ## ----fig.pos="t"-------------------------------------------------------------- forecast_data_example |> filter( reference_date == "2022-12-17", horizon != 0, output_type_id %in% c(0.05, 0.5, 0.95) ) |> pivot_wider(names_from = output_type_id, values_from = value) |> rename(lower = "0.05", upper = "0.95", value = "0.5") |> ggplot(aes(x = target_end_date)) + facet_grid(~model_id) + geom_point(aes(y = value, color = "medians"), size = 2) + geom_line(aes(y = value, color = "medians"), linewidth = 1) + geom_ribbon( aes( ymin = lower, ymax = upper, fill = "#3388FF" ), alpha = 0.5 ) + geom_point( data = target_data_example |> filter(target_end_date <= "2022-12-17"), aes(y = observation, group = 1, color = "obs") ) + geom_line( data = target_data_example |> filter(target_end_date <= "2022-12-17"), aes(y = observation, group = 1, color = "obs") ) + geom_point( data = target_data_example |> filter(target_end_date > "2022-12-17"), aes(y = observation, group = 1, color = "truth"), shape = 1, alpha = 1 ) + geom_line( data = target_data_example |> filter(target_end_date > "2022-12-17"), aes(y = observation, group = 1, color = "truth"), alpha = 0.75 ) + # coord_cartesian(ylim = c(0, 500)) + scale_x_date(breaks = target_data_example$target_end_date, date_labels = "%Y-%m-%d") + labs( y = "Weekly Hospitalization", x = "Date" ) + scale_color_manual( name = "", values = c( "medians" = "DodgerBlue", "obs" = "Black", "truth" = "Black" ), labels = c( "Forecast (Predictive median)", "Observed data before forecasting", "Eventually observed value" ) ) + scale_fill_manual("", values = "#3388FF", labels = "90% Prediction interval" ) + theme( axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8), axis.text.x = element_text(size = 6, angle = 90), axis.text.y = element_text(size = 8), strip.text = element_text(size = 8), legend.title = element_blank(), legend.text = element_text(size = 8), legend.position = "bottom", legend.direction = "vertical", legend.box = "horizontal" ) ## ----------------------------------------------------------------------------- data.frame( "Output Type" = c("mean", "median", "quantile", "pmf"), "Scoring Rule" = c("SE", "AE", "WIS", "Log Score"), Description = c( "Squared error (SE): the squared difference between the predicted value and the observed value", "Absolute error (AE): the absolute difference between the predicted value and the observed value", paste0( "Weighted interval score (WIS): a quantile-based approximation of the continuous ranked", " probability score (CRPS) for evaluating quantile forecasts" ), "Logarithm of the probability assigned to the true outcome (LogScore)" ), check.names = FALSE ) |> knitr::kable( format = "html", caption = paste0( "Table 2: Pairs of output types and their associated scoring rules ", "for evaluating prediction performance." ) ) |> kableExtra::kable_styling( font_size = 13, bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = TRUE ) ## ----------------------------------------------------------------------------- knitr::include_graphics("figure-concept.png") ## ----------------------------------------------------------------------------- knitr::include_graphics("algorithm-lomo.jpg") ## ----------------------------------------------------------------------------- knitr::include_graphics("algorithm-lasomo.jpg") ## ----fig.pos="t"-------------------------------------------------------------- data.frame(n = 2:10) |> mutate( w_eq = 1 / (2^(n - 1) - 1), w_perm_min = 1 / ((n - 1) * choose(n - 1, floor((n - 1) / 2))), w_perm_max = 1 / (n - 1) ) |> ggplot(aes(x = n)) + geom_line(aes(y = w_eq, color = "eq"), size = 0.75, linetype = "longdash") + geom_point(aes(y = w_eq, color = "eq"), size = 2, shape = 15) + geom_line(aes(y = w_perm_min, color = "perm_min"), size = 0.75) + geom_point(aes(y = w_perm_min, color = "perm_min"), size = 2, shape = 16) + geom_line(aes(y = w_perm_max, color = "perm_max"), size = 0.75) + geom_point(aes(y = w_perm_max, color = "perm_max"), size = 2, shape = 17) + scale_color_manual( name = "Weights", values = c( "eq" = "#F8766D", "perm_min" = "#619CFF", "perm_max" = "#00BA38" ), labels = c( eq = expression(w^{ eq }), perm_min = expression(w^{ perm - min }), perm_max = expression(w^{ perm - max }) ) ) + scale_x_continuous(breaks = 2:10) + labs( x = "Number of models (n)", y = "Weight assigned to a subset", color = "Weighting Scheme" ) + theme( axis.title.x = element_text(size = 9), axis.title.y = element_text(size = 9), axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 8), legend.title = element_text(size = 9), legend.position = "bottom", legend.text = element_text(size = 9), legend.spacing.x = unit(0.5, "mm"), legend.key.width = unit(1, "cm") ) ## ----code-model_importance---------------------------------------------------- # model_importance( # forecast_data, oracle_output_data, ensemble_fun, # importance_algorithm, subset_wt, min_log_score, # ... # ) ## ----------------------------------------------------------------------------- tbl_argument1 <- data.frame( "Argument" = c( "`forecast_data`", "`oracle_output_data`", "`ensemble_fun`", "`importance_algorithm`", "`subset_wt`", "`min_log_score`", "`...`" ), "Description" = c( "Forecasts", "Ground truth data", "Ensemble method", "Algorithm to calculate importance", "Method for assigning weight to subsets when using LASOMO algorithm", "Minimum value to replace for log score", "Optional arguments for `'simple_ensemble'`" ), "Possible Values" = c( "Table of model output", "Table of oracle output", "`'simple_ensemble'`, `'linear_pool'`", "`'lomo', 'lasomo'`", "`'equal', 'perm_based'`", "Non-positive numeric", "Varies" ), Default = c( "N/A", "N/A", "`'simple_ensemble'`", "`'lomo'`", "`'equal'`", -10, "`agg_fun='mean'`" ), check.names = FALSE ) tbl_argument1 |> knitr::kable(format = "html", escape = FALSE, caption = "Table 3: Description of the arguments for the `model_importance()` function, including their purpose, possible values, and default settings.") |> kableExtra::kable_styling( font_size = 13, bootstrap_options = c("striped", "condensed", "responsive"), full_width = FALSE ) ## ----------------------------------------------------------------------------- tbl_argument2 <- data.frame( "Argument" = c( "`importance_scores`", "`by`", "`na_action`", "`fun`", "`...`" ), "Description" = c( "Model importance scores produced by `model_importance()`", "Grouping variable(s) for summarization", "Method to handle `NA` values", "Function to summarize importance scores", "Optional arguments for `\"fun\"`" ), "Possible Values" = c( "data frame", "grouping variable(s)", "`\"drop\", \"worst\", \"average\"`", "summary function", "depends on `fun`" ), Default = c( "N/A", "`\"model_id\"`", "`\"drop\"`", "`mean`", "N/A" ), check.names = FALSE ) tbl_argument2 |> knitr::kable( format = "html", escape = FALSE, caption = paste0( "Table 4: Description of the arguments for the `aggregate()` function for ", "`model_imp_tbl` objects, including their purpose, possible values, and default settings." ) ) |> kableExtra::kable_styling( font_size = 13, bootstrap_options = c("striped", "condensed", "responsive"), full_width = FALSE ) ## ----code-forecast_data------------------------------------------------------- # forecast_data ## ----forecast_data, tidy = FALSE---------------------------------------------- forecast_data <- readRDS("vignette-example-forecast_data.rds") forecast_data |> knitr::kable( format = "html" ) |> kableExtra::kable_styling( font_size = 12, bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = TRUE ) ## ----code-target_data--------------------------------------------------------- # target_data ## ----target_data-------------------------------------------------------------- target_data <- readRDS("vignette-example-oracle_data.rds") target_data |> knitr::kable( format = "html" ) |> kableExtra::kable_styling( font_size = 12, bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = TRUE ) ## ----fig.pos="t"-------------------------------------------------------------- target_data |> mutate(model_id = "Observed") |> rename(value = oracle_value) |> rbind( forecast_data |> select("target_end_date", "target", "location", "value", "model_id") ) |> ggplot(aes(x = target_end_date)) + geom_point(aes(y = value, color = model_id, shape = model_id), size = 2) + geom_point( data = target_data, aes(y = oracle_value, color = "Observed", shape = "Observed"), size = 3 ) + facet_wrap(~location, scales = "free_y", labeller = labeller(location = function(x) paste0("Location: ", x)) ) + scale_x_date( breaks = target_data$target_end_date, date_labels = "%Y-%m-%d", expand = expansion(add = c(5, 5)) ) + scale_color_manual( name = "model_id", values = c( "Flusight-baseline" = "#F8766D", "MOBS-GLEAM_FLUH" = "#00BA38", "PSI-DICE" = "#619CFF", "Observed" = "black" ), limits = c( "Flusight-baseline", "MOBS-GLEAM_FLUH", "PSI-DICE", "Observed" ) ) + scale_shape_manual( name = "model_id", values = c( "Flusight-baseline" = 16, "MOBS-GLEAM_FLUH" = 17, "PSI-DICE" = 15, "Observed" = 18 ), limits = c( "Flusight-baseline", "MOBS-GLEAM_FLUH", "PSI-DICE", "Observed" ) ) + labs( y = "Weekly Hospitalization", x = "Date" ) + theme( axis.title.x = element_text(size = 9), axis.title.y = element_text(size = 9), axis.text.x = element_text(size = 9), axis.text.y = element_text(size = 9), strip.text = element_text(size = 9), legend.title = element_blank(), legend.text = element_text(size = 8), legend.position = "bottom", legend.box = "horizontal", legend.spacing.x = unit(0.25, "mm"), legend.key.width = unit(0.4, "cm") ) ## ----code-model_importance-lomo----------------------------------------------- # model_importance( # forecast_data = forecast_data, # oracle_output_data = target_data, # ensemble_fun = "simple_ensemble", # importance_algorithm = "lomo" # ) ## ----------------------------------------------------------------------------- scores_lomo <- model_importance( forecast_data = forecast_data, oracle_output_data = target_data, ensemble_fun = "simple_ensemble", importance_algorithm = "lomo" ) ## ----------------------------------------------------------------------------- # print( # scores_lomo |> # mutate(importance = round(importance, 2)) |> # rename( # ref_date = reference_date, h = horizon, # loc = location, t_end_date = target_end_date, # o_type = output_type, imp = importance # ) # ) ## ----------------------------------------------------------------------------- print(scores_lomo |> mutate(importance = round(importance, 2)) |> rename( ref_date = reference_date, h = horizon, loc = location, t_end_date = target_end_date, o_type = output_type, imp = importance )) ## ----------------------------------------------------------------------------- # summary(scores_lomo) ## ----------------------------------------------------------------------------- summary(scores_lomo) ## ----------------------------------------------------------------------------- # s <- summary(scores_lomo) # s$all_tasks ## ----------------------------------------------------------------------------- s <- summary(scores_lomo) s$all_tasks ## ----------------------------------------------------------------------------- # s$model_summary ## ----------------------------------------------------------------------------- s$model_summary ## ----------------------------------------------------------------------------- # s$task_winners ## ----------------------------------------------------------------------------- s$task_winners ## ----------------------------------------------------------------------------- # ggplot(scores_lomo, aes(x = model_id, y = importance, fill = model_id)) + # geom_col() + # coord_flip() + # geom_hline(yintercept = 0, color = "black", linewidth = 0.25) + # facet_grid( # cols = vars(target, horizon, location, target_end_date), # scales = "free_x" # ) + # labs( # x = "Model ID", y = "Importance Score", # title = "Model Importance by Task" # ) + # scale_x_discrete(labels = function(x) gsub("[-_]", "-\n", x)) + # theme( # axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5), # panel.spacing.x = unit(0.5, "lines"), legend.position = "none" # ) ## ----------------------------------------------------------------------------- ggplot(scores_lomo, aes(x = model_id, y = importance, fill = model_id)) + geom_col() + coord_flip() + geom_hline(yintercept = 0, color = "black", linewidth = 0.25) + facet_grid( cols = vars(target, horizon, location, target_end_date), scales = "free_x" ) + labs( x = "Model ID", y = "Importance Score", title = "Model Importance by Task" ) + scale_x_discrete(labels = function(x) gsub("[-_]", "-\n", x)) + theme( axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5), panel.spacing.x = unit(0.5, "lines"), legend.position = "none" ) ## ----------------------------------------------------------------------------- # aggregate(scores_lomo, by = "model_id", na_action = "drop", fun = mean) ## ----------------------------------------------------------------------------- aggregate(scores_lomo, by = "model_id", na_action = "drop", fun = mean) ## ----------------------------------------------------------------------------- # aggregate(scores_lomo, by = "model_id", na_action = "worst", fun = mean) ## ----------------------------------------------------------------------------- aggregate(scores_lomo, by = "model_id", na_action = "worst", fun = mean) ## ----------------------------------------------------------------------------- # aggregate(scores_lomo, by = "model_id", na_action = "average", fun = mean) ## ----------------------------------------------------------------------------- aggregate(scores_lomo, by = "model_id", na_action = "average", fun = mean) ## ----code-model_importance-summary-lasomo-equal------------------------------- # scores_lasomo_eq <- model_importance( # forecast_data = forecast_data, # oracle_output_data = target_data, # ensemble_fun = "simple_ensemble", # importance_algorithm = "lasomo", # subset_wt = "equal" # ) # aggregate(scores_lasomo_eq, by = "model_id", na_action = "drop", fun = mean) ## ----------------------------------------------------------------------------- scores_lasomo_eq <- suppressMessages(model_importance( forecast_data = forecast_data, oracle_output_data = target_data, ensemble_fun = "simple_ensemble", importance_algorithm = "lasomo", subset_wt = "equal" )) aggregate(scores_lasomo_eq, by = "model_id", na_action = "drop", fun = mean) ## ----code-model_importance-summary-lasomo-perm-------------------------------- # scores_lasomo_perm <- model_importance( # forecast_data = forecast_data, # oracle_output_data = target_data, # ensemble_fun = "simple_ensemble", # importance_algorithm = "lasomo", # subset_wt = "perm_based" # ) # aggregate(scores_lasomo_perm, by = "model_id", na_action = "drop", fun = mean) ## ----------------------------------------------------------------------------- scores_lasomo_perm <- suppressMessages(model_importance( forecast_data = forecast_data, oracle_output_data = target_data, ensemble_fun = "simple_ensemble", importance_algorithm = "lasomo", subset_wt = "perm_based" )) aggregate(scores_lasomo_perm, by = "model_id", na_action = "drop", fun = mean) ## ----------------------------------------------------------------------------- knitr::include_graphics("runtime_comparison-fitted.png") ## ----------------------------------------------------------------------------- knitr::include_graphics("runtime_parallel-fitted.png") ## ----include = FALSE---------------------------------------------------------- options(oldopts) par(oldpar)