#' Scenario to pick the best scenario out of a list of scenarios
#'
#' `scenario_best_of` picks the best value between multiple scenarios specified
#' in `scenario_names`. `small_is_best` allows to pick if higher value or
#' smaller values are best.
#'
#' If multiple scenario are tied for the best scenario, the scenario with the best time
#' series for each `iso3` and `ind` is picked. If they are still tied scenarios for
#' the best value, the first in alphabetical order is picked.
#'
#' @param scenario_names names of the scenario to pick from.
#' @param maximize_end_year (Boolean) if TRUE, the best scenario is
#' picked on the best value at `end_year`. Default to FALSE.
#'
#' @inheritParams scenario_fixed_target
#' @inheritParams trim_values
#' @inheritParams transform_hpop_data
#'
#' @family basic_scenarios
#' @family comparing_scenario
#'
#' @export
scenario_best_of <- function(df,
scenario_names,
value_col = "value",
maximize_end_year = TRUE,
start_year = 2018,
end_year = 2025,
target_year = end_year,
scenario_name = glue::glue("best_of_{paste0(scenario_names, collapse = '_')}"),
scenario_col = "scenario",
trim = TRUE,
small_is_best = FALSE,
keep_better_values = TRUE,
upper_limit = 100,
lower_limit = 0,
trim_years = TRUE,
start_year_trim = start_year,
end_year_trim = end_year,
ind_ids = billion_ind_codes("all")) {
this_ind <- unique(df[["ind"]])
assert_columns(df, "year", "iso3", "ind", scenario_col, value_col)
assert_unique_rows(df, scenario_col, ind_ids = ind_ids)
assert_ind_start_end_year(df, value_col, target_year, target_year, scenario_col, ind_ids = this_ind)
best <- df %>%
dplyr::filter(.data[["year"]] == target_year) %>%
dplyr::mutate(scenario_value = .data[[value_col]])
if (small_is_best) {
best <- best %>%
dplyr::group_by(dplyr::across(dplyr::all_of(c("iso3", "ind")))) %>%
dplyr::filter(.data[["scenario_value"]] == min(.data[["scenario_value"]]))
} else {
best <- best %>%
dplyr::group_by(dplyr::across(dplyr::all_of(c("iso3", "ind")))) %>%
dplyr::filter(.data[["scenario_value"]] == max(.data[["scenario_value"]]))
}
if (length(unique(best[[scenario_col]])) > 1) {
those_scenarios <- unique(best[[scenario_col]])
if(maximize_end_year){
best <- df %>%
dplyr::mutate(scenario_value = .data[[value_col]]) %>%
dplyr::select(dplyr::any_of(c("iso3", "year", "ind", scenario_col, "scenario_value"))) %>%
dplyr::filter(.data[[scenario_col]] %in% those_scenarios,
.data[["year"]] == end_year) %>%
dplyr::group_by(dplyr::across(dplyr::any_of(c("iso3", "ind", scenario_col)))) %>%
dplyr::summarise(sum_values = sum(.data[["scenario_value"]], na.rm = T))
}else{
best <- df %>%
dplyr::mutate(scenario_value = .data[[value_col]]) %>%
dplyr::select(dplyr::any_of(c("iso3", "year", "ind", scenario_col, "scenario_value"))) %>%
dplyr::filter(.data[[scenario_col]] %in% those_scenarios) %>%
dplyr::group_by(dplyr::across(dplyr::any_of(c("iso3", "ind", scenario_col)))) %>%
dplyr::summarise(sum_values = sum(.data[["scenario_value"]], na.rm = T))
}
if (small_is_best) {
best <- best %>%
dplyr::ungroup() %>%
dplyr::group_by(dplyr::across(dplyr::all_of(c("iso3", "ind")))) %>%
dplyr::filter(.data[["sum_values"]] == min(.data[["sum_values"]], na.rm = T))
} else {
best <- best %>%
dplyr::ungroup() %>%
dplyr::group_by(dplyr::across(dplyr::all_of(c("iso3", "ind")))) %>%
dplyr::filter(.data[["sum_values"]] == max(.data[["sum_values"]], na.rm = T))
}
best <- best %>%
dplyr::group_by(dplyr::across(dplyr::all_of(c("iso3", "ind")))) %>%
dplyr::group_modify(
~ {
if (length(unique(.x[[scenario_col]])) > 1) {
one_scenario <- unique(.x[[scenario_col]])[[1]]
.x %>%
dplyr::filter(.data[[scenario_col]] == one_scenario)
} else {
.x
}
}
)
}
best_df <- df %>%
dplyr::mutate(scenario_value = .data[[value_col]]) %>%
dplyr::semi_join(best, by = c("iso3", "ind", scenario_col)) %>%
trim_values(
col = "scenario_value",
value_col = value_col,
trim = trim,
small_is_best = small_is_best,
keep_better_values = keep_better_values,
upper_limit = upper_limit,
lower_limit = lower_limit,
trim_years = trim_years,
start_year_trim = start_year_trim,
end_year_trim = end_year_trim
) %>%
dplyr::mutate(!!sym(scenario_col) := scenario_name)
df %>%
dplyr::bind_rows(best_df)
}
#' @noRd
#'
#' @keywords internal
get_best_equal_scenarios <- function(df,
scenario_col = "scenario",
value_col = "scenario_value") {
best <- df %>%
dplyr::group_by(dplyr::across(dplyr::all_of(c("iso3", "ind")))) %>%
tidyr::pivot_wider(values_from = value_col, names_from = scenario_col)
}
#' Scenario establish a business as usual scenario
#'
#' `scenario_bau` filters for values between start_year and end_year for `bau_scenario` and
#' returns values in `value.` If values are missing for years between `start_year` and `end_year`,
#' the last available value will be imputed.
#'
#' @param only_reported_estimated (logical) if TRUE only the last `reported` and `estimated`
#' values are imputed.
#' @param avoid_worstening If TRUE, the value at `start_year` is kept if it is
#' better (see `small_is_best`).
#' @inheritParams scenario_fixed_target
#' @inheritParams trim_values
#' @inheritParams transform_hpop_data
#' @inheritParams transform_hep_data
#' @inheritParams accelerate_alcohol
#'
#' @family basic_scenarios
#' @family comparing_scenario
#'
#' @export
scenario_bau <- function(df,
only_reported_estimated = FALSE,
value_col = "value",
start_year = 2018,
end_year = 2025,
scenario_name = glue::glue("business_as_usual"),
scenario_col = "scenario",
avoid_worstening = FALSE,
trim = TRUE,
small_is_best = FALSE,
keep_better_values = TRUE,
upper_limit = 100,
lower_limit = 0,
trim_years = TRUE,
start_year_trim = start_year,
end_year_trim = end_year,
ind_ids = billion_ind_codes("all"),
bau_scenario = "historical",
default_scenario = "default") {
indicator <- unique(df[["ind"]]) %>%
stringr::str_remove_all(paste0(c("espar[0-9]{2}_[0-9]{2}$", "espar[0-9]{2}$"), collapse = "|")) %>%
unique()
indicator <- indicator[indicator != ""]
scenario_df <- df %>%
dplyr::filter(.data[[scenario_col]] %in% c(bau_scenario, default_scenario),
!is.na(.data[[value_col]]),
.data[["ind"]] %in% indicator)
assert_columns(scenario_df, scenario_col, value_col)
full_years <- tidyr::expand_grid(
"year" := start_year:end_year,
"iso3" := unique(df[["iso3"]]),
"ind" := indicator,
"{scenario_col}" := c(bau_scenario, default_scenario)
) %>%
dplyr::distinct()
if(only_reported_estimated){
scenario_df <- scenario_df %>%
dplyr::filter(.data[["type"]] %in% c("reported", "estimated"))
}
if(nrow(scenario_df) > 0){
scenario_df <- scenario_df %>%
dplyr::full_join(full_years, by = c("year", "iso3", "ind", scenario_col)) %>%
dplyr::group_by(dplyr::across(dplyr::any_of(c("iso3", "ind")))) %>%
dplyr::mutate(start_value = get_baseline_value(.data[[value_col]],
.data[["year"]],
.data[["type"]],
.data[[scenario_col]],
default_scenario,
baseline_year = start_year,
type_filter = c("all")))%>%
dplyr::filter(.data[[scenario_col]] == bau_scenario) %>%
dplyr::mutate(
last_year = max(.data[["year"]][!is.na(.data[[value_col]])], na.rm = TRUE),
last_value = .data[[value_col]][.data[["year"]] == .data[["last_year"]]],
"{value_col}" := dplyr::case_when(
!is.na(.data[["start_value"]]) & .data[["year"]] == start_year ~ .data[["start_value"]],
is.na(.data[[value_col]]) & .data[["year"]] > .data[["last_year"]] ~ .data[["last_value"]],
TRUE ~ .data[[value_col]]
),
"{value_col}" := dplyr::case_when(
avoid_worstening & small_is_best & .data[[value_col]] > start_value ~ start_value,
avoid_worstening & !small_is_best & .data[[value_col]] < start_value ~ start_value,
TRUE ~ .data[[value_col]]
)
) %>%
dplyr::select(-c("last_value", "last_year", "start_value"))
}else{
scenario_df <- scenario_df %>%
dplyr::full_join(full_years, by = c("year", "iso3", "ind", scenario_col))
}
bau <- scenario_df %>%
dplyr::filter(
.data[["year"]] %in% start_year:end_year,
.data[[scenario_col]] == bau_scenario
) %>%
dplyr::mutate(scenario_value = .data[[value_col]]) %>%
dplyr::mutate(!!sym(scenario_col) := scenario_name) %>%
trim_values(
col = "scenario_value",
value_col = value_col,
trim = trim,
small_is_best = small_is_best,
keep_better_values = keep_better_values,
upper_limit = upper_limit,
lower_limit = lower_limit,
trim_years = trim_years,
start_year_trim = start_year_trim,
end_year_trim = end_year_trim) %>%
dplyr::mutate(type = dplyr::case_when(
!is.na(.data[["type"]]) ~ .data[["type"]],
TRUE ~ "projected"
))
df %>%
dplyr::bind_rows(bau)
}
#' @noRd
scenario_with_values <- function(df,
scenario_function,
type_filter = c("reported", "estimated"),
only_reported_estimated = FALSE,
value_col = "value",
start_year = 2018,
end_year = 2025,
scenario_name = scenario_function,
scenario_col = "scenario",
avoid_worstening = FALSE,
trim = TRUE,
small_is_best = FALSE,
keep_better_values = TRUE,
upper_limit = 100,
lower_limit = 0,
trim_years = TRUE,
ind_ids = billion_ind_codes("all"),
bau_scenario = "historical",
default_scenario = "default",
...){
indicator <- unique(df[["ind"]]) %>%
stringr::str_remove_all(paste0(c("espar[0-9]{2}_[0-9]{2}$", "espar[0-9]{2}$"), collapse = "|")) %>%
unique()
params <- get_dots_and_call_parameters(...)
df_this_ind <- df %>%
dplyr::filter(.data[["ind"]] == indicator)
df_without_data <- df_this_ind %>%
dplyr::group_by(.data[["iso3"]]) %>%
dplyr::filter(sum(.data[["type"]] %in% type_filter, na.rm = TRUE) <= 1)
df_with_data <- df_this_ind %>%
dplyr::group_by(.data[["iso3"]]) %>%
dplyr::filter(sum(.data[["type"]] %in% type_filter, na.rm = TRUE) > 1) %>%
dplyr::ungroup()
if (nrow(df_with_data) > 0) {
scenario_fn <- get(as.character(scenario_function), mode = "function")
params_fn <- get_right_parameters(params, scenario_fn)
df_with_data_fn <- exec_scenario(df_with_data,
scenario_fn,
params_fn)%>%
dplyr::filter(.data[[scenario_col]] == params[["scenario_name"]])
} else {
df_with_data_fn <- tibble::tibble()
}
if (nrow(df_without_data) > 0) {
params_bau <- get_right_parameters(params, scenario_bau)
df_without_data_fn <- exec_scenario(df_without_data,
scenario_bau,
params_bau) %>%
dplyr::filter(.data[[scenario_col]] == params[["scenario_name"]])
} else {
df_without_data_fn <- tibble::tibble()
}
df %>%
dplyr::bind_rows(df_without_data_fn, df_with_data_fn)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.