From 07b94263619751d6670af34c98b2e9eac4c61e88 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 10:32:51 +0100 Subject: [PATCH 01/21] Create functions for default scoring rules --- R/default-scoring-rules.R | 152 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 R/default-scoring-rules.R diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R new file mode 100644 index 000000000..c6bfac1e2 --- /dev/null +++ b/R/default-scoring-rules.R @@ -0,0 +1,152 @@ +#' @title Select Scoring Rules From A List of Possibilities +#' @description Helper function to return only the scoring rules selected by +#' the user from a list of possible scoring rules. +#' @param possibilities A list of scoring rules. +#' @param select A character vector of scoring rules to select from the list. +#' If `select = all` (the default), all possible scoring rules are returned. +#' @param exclude A character vector of scoring rules to exclude from the list. +#' If `select != "all"`, this argument is ignored. +#' @return A list of scoring rules. +#' @keywords internal +#' @importFrom checkmate assert_subset +#' @examples +#' scoringutils:::select_rules( +#' possibilities = rules_binary(), +#' select = "brier_score" +#' ) +select_rules <- function(possibilities, select, exclude = NULL) { + assert_character(x = c(select, exclude), null.ok = TRUE) + allowed <- names(possibilities) + + if (select == "all" && is.null(exclude)) { + return(possibilities) + } else if (select == "all") { + assert_subset(exclude, allowed) + select <- allowed[!allowed %in% exclude] + return(possibilities[select]) + } else { + assert_subset(select, allowed) + return(possibilities[select]) + } +} + +#' @title Scoring Rules for Binary Forecasts +#' @description Helper function that returns a named list of default +#' scoring rules suitable for binary forecasts. +#' +#' The default scoring rules are: +#' - "brier_score" = [brier_score()] +#' - "log_score" = [logs_binary()] +#' @inherit select_rules params return +#' @export +#' @keywords info +#' @examples +#' rules_binary() +#' rules_binary(select = "brier_score") +#' rules_binary(exclude = "log_score") +rules_binary <- function(select = "all", exclude = NULL) { + all <- list( + "brier_score" = brier_score, + "log_score" = logs_binary + ) + selected <- select_rules(all, select, exclude) + return(selected) +} + + +#' @title Scoring Rules for Point Forecasts +#' @description Helper function that returns a named list of default +#' scoring rules suitable for point forecasts. +#' +#' The default scoring rules are: +#' - "ae_point" = [ae()][Metrics::ae()] +#' - "se_point" = [se()][Metrics::se()] +#' - "ape" = [ape()][Metrics::ape()] +#' @inherit select_rules params return +#' @export +#' @keywords info +#' @examples +#' rules_point() +#' rules_point(select = "ape") +rules_point <- function(select = "all", exclude = NULL) { + all <- list( + "ae_point" = Metrics::ae, + "se_point" = Metrics::se, + "ape" = Metrics::ape + ) + selected <- select_rules(all, select, exclude) + return(selected) +} + + +#' @title Scoring Rules for Sample-Based Forecasts +#' @description Helper function that returns a named list of default +#' scoring rules suitable for forecasts in a sample-based format +#' +#' The default scoring rules are: +#' - "mad" = [mad_sample()] +#' - "bias" = [bias_sample()] +#' - "dss" = [dss_sample()] +#' - "crps" = [crps_sample()] +#' - "log_score" = [logs_sample()] +#' - "mad" = [mad_sample()] +#' - "ae_median" = [ae_median_sample()] +#' - "se_mean" = [se_mean_sample()] +#' @inherit select_rules params return +#' @export +#' @keywords info +#' @examples +#' rules_sample() +#' rules_sample(select = "mad") +rules_sample <- function(select = "all", exclude = NULL) { + all <- list( + "bias" = bias_sample, + "dss" = dss_sample, + "crps" = crps_sample, + "log_score" = logs_sample, + "mad" = mad_sample, + "ae_median" = ae_median_sample, + "se_mean" = se_mean_sample + ) + selected <- select_rules(all, select, exclude) + return(selected) +} + + +#' @title Scoring Rules for Quantile-Based Forecasts +#' @description Helper function that returns a named list of default +#' scoring rules suitable for forecasts in a quantile-based format +#' +#' The default scoring rules are: +#' - "wis" = [wis] +#' - "overprediction" = [overprediction()] +#' - "underprediction" = [underprediction()] +#' - "dispersion" = [dispersion()] +#' - "bias" = [bias_quantile()] +#' - "coverage_50" = [interval_coverage_quantile()] +#' - "coverage_90" = \(...) \{ +#' run_safely(..., range = 90, fun = [interval_coverage_quantile]) +#' \} +#' - "coverage_deviation" = [interval_coverage_dev_quantile()], +#' - "ae_median" = [ae_median_quantile()] +#' @inherit select_rules params return +#' @export +#' @keywords info +#' @examples +#' rules_quantile() +#' rules_quantile(select = "wis") +rules_quantile <- function(select = "all", exclude = NULL) { + all <- list( + "wis" = wis, + "overprediction" = overprediction, + "underprediction" = underprediction, + "dispersion" = dispersion, + "bias" = bias_quantile, + "coverage_50" = interval_coverage_quantile, + "coverage_90" = \(...) {run_safely(..., range = 90, fun = interval_coverage_quantile)}, + "coverage_deviation" = interval_coverage_dev_quantile, + "ae_median" = ae_median_quantile + ) + selected <- select_rules(all, select, exclude) + return(selected) +} From d952fe52c46600cf2e5c1e33ed7356422e2ea157 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 10:35:20 +0100 Subject: [PATCH 02/21] Update documentation for new functions --- NAMESPACE | 5 +++++ man/rules_binary.Rd | 34 ++++++++++++++++++++++++++++++++++ man/rules_point.Rd | 34 ++++++++++++++++++++++++++++++++++ man/rules_quantile.Rd | 42 ++++++++++++++++++++++++++++++++++++++++++ man/rules_sample.Rd | 39 +++++++++++++++++++++++++++++++++++++++ man/select_rules.Rd | 31 +++++++++++++++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 man/rules_binary.Rd create mode 100644 man/rules_point.Rd create mode 100644 man/rules_quantile.Rd create mode 100644 man/rules_sample.Rd create mode 100644 man/select_rules.Rd diff --git a/NAMESPACE b/NAMESPACE index 35c1eb7c0..c0f344dac 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -59,6 +59,10 @@ export(plot_score_table) export(plot_wis) export(quantile_score) export(quantile_to_interval) +export(rules_binary) +export(rules_point) +export(rules_quantile) +export(rules_sample) export(run_safely) export(sample_to_quantile) export(score) @@ -86,6 +90,7 @@ importFrom(checkmate,assert_logical) importFrom(checkmate,assert_number) importFrom(checkmate,assert_numeric) importFrom(checkmate,assert_string) +importFrom(checkmate,assert_subset) importFrom(checkmate,assert_vector) importFrom(checkmate,check_atomic_vector) importFrom(checkmate,check_data_frame) diff --git a/man/rules_binary.Rd b/man/rules_binary.Rd new file mode 100644 index 000000000..612926e32 --- /dev/null +++ b/man/rules_binary.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default-scoring-rules.R +\name{rules_binary} +\alias{rules_binary} +\title{Scoring Rules for Binary Forecasts} +\usage{ +rules_binary(select = "all", exclude = NULL) +} +\arguments{ +\item{select}{A character vector of scoring rules to select from the list. +If \code{select = all} (the default), all possible scoring rules are returned.} + +\item{exclude}{A character vector of scoring rules to exclude from the list. +If \code{select != "all"}, this argument is ignored.} +} +\value{ +A list of scoring rules. +} +\description{ +Helper function that returns a named list of default +scoring rules suitable for binary forecasts. + +The default scoring rules are: +\itemize{ +\item "brier_score" = \code{\link[=brier_score]{brier_score()}} +\item "log_score" = \code{\link[=logs_binary]{logs_binary()}} +} +} +\examples{ +rules_binary() +rules_binary(select = "brier_score") +rules_binary(exclude = "log_score") +} +\keyword{info} diff --git a/man/rules_point.Rd b/man/rules_point.Rd new file mode 100644 index 000000000..6ca51267e --- /dev/null +++ b/man/rules_point.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default-scoring-rules.R +\name{rules_point} +\alias{rules_point} +\title{Scoring Rules for Point Forecasts} +\usage{ +rules_point(select = "all", exclude = NULL) +} +\arguments{ +\item{select}{A character vector of scoring rules to select from the list. +If \code{select = all} (the default), all possible scoring rules are returned.} + +\item{exclude}{A character vector of scoring rules to exclude from the list. +If \code{select != "all"}, this argument is ignored.} +} +\value{ +A list of scoring rules. +} +\description{ +Helper function that returns a named list of default +scoring rules suitable for point forecasts. + +The default scoring rules are: +\itemize{ +\item "ae_point" = \link[Metrics:ae]{ae()} +\item "se_point" = \link[Metrics:se]{se()} +\item "ape" = \link[Metrics:ape]{ape()} +} +} +\examples{ +rules_point() +rules_point(select = "ape") +} +\keyword{info} diff --git a/man/rules_quantile.Rd b/man/rules_quantile.Rd new file mode 100644 index 000000000..c947c8b61 --- /dev/null +++ b/man/rules_quantile.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default-scoring-rules.R +\name{rules_quantile} +\alias{rules_quantile} +\title{Scoring Rules for Quantile-Based Forecasts} +\usage{ +rules_quantile(select = "all", exclude = NULL) +} +\arguments{ +\item{select}{A character vector of scoring rules to select from the list. +If \code{select = all} (the default), all possible scoring rules are returned.} + +\item{exclude}{A character vector of scoring rules to exclude from the list. +If \code{select != "all"}, this argument is ignored.} +} +\value{ +A list of scoring rules. +} +\description{ +Helper function that returns a named list of default +scoring rules suitable for forecasts in a quantile-based format + +The default scoring rules are: +\itemize{ +\item "wis" = \link{wis} +\item "overprediction" = \code{\link[=overprediction]{overprediction()}} +\item "underprediction" = \code{\link[=underprediction]{underprediction()}} +\item "dispersion" = \code{\link[=dispersion]{dispersion()}} +\item "bias" = \code{\link[=bias_quantile]{bias_quantile()}} +\item "coverage_50" = \code{\link[=interval_coverage_quantile]{interval_coverage_quantile()}} +\item "coverage_90" = \(...) \{ +run_safely(..., range = 90, fun = \link{interval_coverage_quantile}) +\} +\item "coverage_deviation" = \code{\link[=interval_coverage_dev_quantile]{interval_coverage_dev_quantile()}}, +\item "ae_median" = \code{\link[=ae_median_quantile]{ae_median_quantile()}} +} +} +\examples{ +rules_quantile() +rules_quantile(select = "wis") +} +\keyword{info} diff --git a/man/rules_sample.Rd b/man/rules_sample.Rd new file mode 100644 index 000000000..daeb4c54b --- /dev/null +++ b/man/rules_sample.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default-scoring-rules.R +\name{rules_sample} +\alias{rules_sample} +\title{Scoring Rules for Sample-Based Forecasts} +\usage{ +rules_sample(select = "all", exclude = NULL) +} +\arguments{ +\item{select}{A character vector of scoring rules to select from the list. +If \code{select = all} (the default), all possible scoring rules are returned.} + +\item{exclude}{A character vector of scoring rules to exclude from the list. +If \code{select != "all"}, this argument is ignored.} +} +\value{ +A list of scoring rules. +} +\description{ +Helper function that returns a named list of default +scoring rules suitable for forecasts in a sample-based format + +The default scoring rules are: +\itemize{ +\item "mad" = \code{\link[=mad_sample]{mad_sample()}} +\item "bias" = \code{\link[=bias_sample]{bias_sample()}} +\item "dss" = \code{\link[=dss_sample]{dss_sample()}} +\item "crps" = \code{\link[=crps_sample]{crps_sample()}} +\item "log_score" = \code{\link[=logs_sample]{logs_sample()}} +\item "mad" = \code{\link[=mad_sample]{mad_sample()}} +\item "ae_median" = \code{\link[=ae_median_sample]{ae_median_sample()}} +\item "se_mean" = \code{\link[=se_mean_sample]{se_mean_sample()}} +} +} +\examples{ +rules_sample() +rules_sample(select = "mad") +} +\keyword{info} diff --git a/man/select_rules.Rd b/man/select_rules.Rd new file mode 100644 index 000000000..cb763de3a --- /dev/null +++ b/man/select_rules.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/default-scoring-rules.R +\name{select_rules} +\alias{select_rules} +\title{Select Scoring Rules From A List of Possibilities} +\usage{ +select_rules(possibilities, select, exclude = NULL) +} +\arguments{ +\item{possibilities}{A list of scoring rules.} + +\item{select}{A character vector of scoring rules to select from the list. +If \code{select = all} (the default), all possible scoring rules are returned.} + +\item{exclude}{A character vector of scoring rules to exclude from the list. +If \code{select != "all"}, this argument is ignored.} +} +\value{ +A list of scoring rules. +} +\description{ +Helper function to return only the scoring rules selected by +the user from a list of possible scoring rules. +} +\examples{ +scoringutils:::select_rules( + possibilities = rules_binary(), + select = "brier_score" +) +} +\keyword{internal} From 518353bde52202f7683aec2f64d161d03adda3fa Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 10:36:45 +0100 Subject: [PATCH 03/21] Switch to using functions instead of package data for default rules --- R/score.R | 12 ++++++------ R/z_globalVariables.R | 8 ++++---- man/apply_rules.Rd | 4 ++-- man/score.Rd | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/R/score.R b/R/score.R index 5ca049fa7..a26351e78 100644 --- a/R/score.R +++ b/R/score.R @@ -16,8 +16,8 @@ #' @inheritSection forecast_types Forecast unit #' @param data A data.frame or data.table with predicted and observed values. #' @param metrics A named list of scoring functions. Names will be used as -#' column names in the output. See [metrics_point()], [metrics_binary()], -#' `metrics_quantile()`, and [metrics_sample()] for more information on the +#' column names in the output. See [rules_point()], [rules_binary()], +#' [rules_quantile()], and [rules_sample()] for more information on the #' default metrics used. #' @param ... additional arguments #' @return A data.table with unsummarised scores. This will generally be @@ -76,7 +76,7 @@ score.default <- function(data, ...) { #' @rdname score #' @export -score.forecast_binary <- function(data, metrics = metrics_binary, ...) { +score.forecast_binary <- function(data, metrics = rules_binary(), ...) { data <- validate_forecast(data) data <- remove_na_observed_predicted(data) metrics <- validate_metrics(metrics) @@ -96,7 +96,7 @@ score.forecast_binary <- function(data, metrics = metrics_binary, ...) { #' @importFrom Metrics se ae ape #' @rdname score #' @export -score.forecast_point <- function(data, metrics = metrics_point, ...) { +score.forecast_point <- function(data, metrics = rules_point(), ...) { data <- validate_forecast(data) data <- remove_na_observed_predicted(data) metrics <- validate_metrics(metrics) @@ -113,7 +113,7 @@ score.forecast_point <- function(data, metrics = metrics_point, ...) { #' @rdname score #' @export -score.forecast_sample <- function(data, metrics = metrics_sample, ...) { +score.forecast_sample <- function(data, metrics = rules_sample(), ...) { data <- validate_forecast(data) data <- remove_na_observed_predicted(data) forecast_unit <- attr(data, "forecast_unit") @@ -150,7 +150,7 @@ score.forecast_sample <- function(data, metrics = metrics_sample, ...) { #' @importFrom data.table `:=` as.data.table rbindlist %like% #' @rdname score #' @export -score.forecast_quantile <- function(data, metrics = metrics_quantile, ...) { +score.forecast_quantile <- function(data, metrics = rules_quantile(), ...) { data <- validate_forecast(data) data <- remove_na_observed_predicted(data) forecast_unit <- attr(data, "forecast_unit") diff --git a/R/z_globalVariables.R b/R/z_globalVariables.R index 89cfc2eab..bcd591290 100644 --- a/R/z_globalVariables.R +++ b/R/z_globalVariables.R @@ -44,10 +44,10 @@ globalVariables(c( "metric", "metrics_select", "metrics", - "metrics_binary", - "metrics_point", - "metrics_quantile", - "metrics_sample", + "rules_binary", + "rules_point", + "rules_quantile", + "rules_sample", "model", "n_obs", "n_obs wis_component_name", diff --git a/man/apply_rules.Rd b/man/apply_rules.Rd index f64ba562f..294033e62 100644 --- a/man/apply_rules.Rd +++ b/man/apply_rules.Rd @@ -10,8 +10,8 @@ apply_rules(data, metrics, ...) \item{data}{A data.frame or data.table with predicted and observed values.} \item{metrics}{A named list of scoring functions. Names will be used as -column names in the output. See \code{\link[=metrics_point]{metrics_point()}}, \code{\link[=metrics_binary]{metrics_binary()}}, -\code{metrics_quantile()}, and \code{\link[=metrics_sample]{metrics_sample()}} for more information on the +column names in the output. See \code{\link[=rules_point]{rules_point()}}, \code{\link[=rules_binary]{rules_binary()}}, +\code{\link[=rules_quantile]{rules_quantile()}}, and \code{\link[=rules_sample]{rules_sample()}} for more information on the default metrics used.} \item{...}{additional arguments} diff --git a/man/score.Rd b/man/score.Rd index d317ed64a..b995b847f 100644 --- a/man/score.Rd +++ b/man/score.Rd @@ -13,13 +13,13 @@ score(data, ...) \method{score}{default}(data, ...) -\method{score}{forecast_binary}(data, metrics = metrics_binary, ...) +\method{score}{forecast_binary}(data, metrics = rules_binary(), ...) -\method{score}{forecast_point}(data, metrics = metrics_point, ...) +\method{score}{forecast_point}(data, metrics = rules_point(), ...) -\method{score}{forecast_sample}(data, metrics = metrics_sample, ...) +\method{score}{forecast_sample}(data, metrics = rules_sample(), ...) -\method{score}{forecast_quantile}(data, metrics = metrics_quantile, ...) +\method{score}{forecast_quantile}(data, metrics = rules_quantile(), ...) } \arguments{ \item{data}{A data.frame or data.table with predicted and observed values.} @@ -27,8 +27,8 @@ score(data, ...) \item{...}{additional arguments} \item{metrics}{A named list of scoring functions. Names will be used as -column names in the output. See \code{\link[=metrics_point]{metrics_point()}}, \code{\link[=metrics_binary]{metrics_binary()}}, -\code{metrics_quantile()}, and \code{\link[=metrics_sample]{metrics_sample()}} for more information on the +column names in the output. See \code{\link[=rules_point]{rules_point()}}, \code{\link[=rules_binary]{rules_binary()}}, +\code{\link[=rules_quantile]{rules_quantile()}}, and \code{\link[=rules_sample]{rules_sample()}} for more information on the default metrics used.} } \value{ From 83e37f914871e9c60370428373d5c1c6bdb3901c Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 10:37:13 +0100 Subject: [PATCH 04/21] Delete package data with default scoring rules --- R/data.R | 48 ------------------------- data/metrics_binary.rda | Bin 45076 -> 0 bytes data/metrics_point.rda | Bin 495 -> 0 bytes data/metrics_quantile.rda | Bin 9677 -> 0 bytes data/metrics_sample.rda | Bin 46691 -> 0 bytes inst/create-list-available-forecasts.R | 36 ------------------- man/metrics_binary.Rd | 20 ----------- man/metrics_point.Rd | 21 ----------- man/metrics_quantile.Rd | 29 --------------- man/metrics_sample.Rd | 26 -------------- 10 files changed, 180 deletions(-) delete mode 100644 data/metrics_binary.rda delete mode 100644 data/metrics_point.rda delete mode 100644 data/metrics_quantile.rda delete mode 100644 data/metrics_sample.rda delete mode 100644 inst/create-list-available-forecasts.R delete mode 100644 man/metrics_binary.Rd delete mode 100644 man/metrics_point.Rd delete mode 100644 man/metrics_quantile.Rd delete mode 100644 man/metrics_sample.Rd diff --git a/R/data.R b/R/data.R index d64b55366..c9bf77109 100644 --- a/R/data.R +++ b/R/data.R @@ -195,51 +195,3 @@ #' #' @keywords info "metrics" - -#' Default metrics for binary forecasts. -#' -#' A named list with functions: -#' - "brier_score" = [brier_score()] -#' - "log_score" = [logs_binary()] -#' @keywords info -"metrics_binary" - -#' Default metrics for point forecasts. -#' -#' A named list with functions: -#' - "ae_point" = [ae()][Metrics::ae()] -#' - "se_point" = [se()][Metrics::se()] -#' - "ape" = [ape()][Metrics::ape()] -#' @keywords info -"metrics_point" - -#' Default metrics for sample-based forecasts. -#' -#' A named list with functions: -#' - "mad" = [mad_sample()] -#' - "bias" = [bias_sample()] -#' - "dss" = [dss_sample()] -#' - "crps" = [crps_sample()] -#' - "log_score" = [logs_sample()] -#' - "mad" = [mad_sample()] -#' - "ae_median" = [ae_median_sample()] -#' - "se_mean" = [se_mean_sample()] -#' @keywords info -"metrics_sample" - -#' Default metrics for quantile-based forecasts. -#' -#' A named list with functions: -#' - "wis" = [wis] -#' - "overprediction" = [overprediction()] -#' - "underprediction" = [underprediction()] -#' - "dispersion" = [dispersion()] -#' - "bias" = [bias_quantile()] -#' - "coverage_50" = [interval_coverage_quantile()] -#' - "coverage_90" = \(...) \{ -#' run_safely(..., range = 90, fun = [interval_coverage_quantile]) -#' \} -#' - "coverage_deviation" = [interval_coverage_dev_quantile()], -#' - "ae_median" = [ae_median_quantile()] -#' @keywords info -"metrics_quantile" diff --git a/data/metrics_binary.rda b/data/metrics_binary.rda deleted file mode 100644 index 9a37a5dda6ef74ab7f54a00ae382ef5b72f92700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45076 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 v5L2@fU=X?q)Mgyyv_rXzuK0LT(pTn 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 Maz!{$kezMRMk}DR4gdfE diff --git a/data/metrics_point.rda b/data/metrics_point.rda deleted file mode 100644 index bf6b60e869c2cc3cf526e7acc31778aadb5e0426..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 495 zcmVOmlRy9ln>RXN5>JnOU8bw=2UDKJ>4_K zp|cRV%`}B|JB~7E!ZSw=RGV|aRzb>|iNhoDw@Ow?i5x9S3E0z79T>+&I!QXkL)AcH z6AfgZ@V>YOnP>AD2Px+3WA`> zh>>yX&|7}n7VrhJ5z$nNAX5VI6(A9jTN26{0SW@jRk8()2>}X(Vhb1n2qlCHISlskrIi+GsY38Y2D+^oGU{! l7|T!&Oo56VgmzwYU?@34Fp^VGL(5O`cO+AV2?F9H0e~DW#w7p% diff --git a/data/metrics_quantile.rda b/data/metrics_quantile.rda deleted file mode 100644 index b5598113dba4ec1cb98f7628899619b2b8723cda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9677 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 Date: Tue, 2 Jan 2024 10:38:15 +0100 Subject: [PATCH 05/21] Update existing tests --- tests/testthat/setup.R | 8 ++++++-- tests/testthat/test-score.R | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R index a236f299d..362f52adb 100644 --- a/tests/testthat/setup.R +++ b/tests/testthat/setup.R @@ -3,8 +3,12 @@ library(ggplot2, quietly = TRUE) library(data.table) suppressMessages(library(magrittr)) -metrics_no_cov <- metrics_quantile[!grepl("coverage", names(metrics_quantile))] -metrics_no_cov_no_ae <- metrics_no_cov[!grepl("ae", names(metrics_no_cov))] +metrics_no_cov <- rules_quantile( + exclude = c("coverage_50", "coverage_90", "coverage_deviation") +) +metrics_no_cov_no_ae <- rules_quantile( + exclude = c("coverage_50", "coverage_90", "coverage_deviation", "ae_median") +) # compute scores diff --git a/tests/testthat/test-score.R b/tests/testthat/test-score.R index ac6249528..3cb960618 100644 --- a/tests/testthat/test-score.R +++ b/tests/testthat/test-score.R @@ -140,18 +140,18 @@ test_that("function produces output for a point case", { ) expect_equal( colnames(eval), - c("model", "target_type",names(metrics_point)) + c("model", "target_type", names(rules_point())) ) }) test_that("Changing metrics names works", { - metrics_test <- metrics_point + metrics_test <- rules_point() names(metrics_test)[1] = "just_testing" eval <- suppressMessages(score(example_point, metrics = metrics_test)) eval_summarised <- summarise_scores(eval, by = "model") expect_equal( colnames(eval_summarised), - c("model", "just_testing", names(metrics_point)[-1]) + c("model", "just_testing", names(rules_point())[-1]) ) }) @@ -174,7 +174,7 @@ test_that("score_quantile correctly handles separate results = FALSE", { nrow(eval) > 1, TRUE ) - expect_true(all(names(metrics_quantile) %in% colnames(eval))) + expect_true(all(names(rules_quantile()) %in% colnames(eval))) }) From 9e810b98fc2b1af128d985343dc10cd450c13bb9 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 11:04:00 +0100 Subject: [PATCH 06/21] Make sure that input to `select_rules` is a list --- R/default-scoring-rules.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index c6bfac1e2..3efd85434 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -8,7 +8,7 @@ #' If `select != "all"`, this argument is ignored. #' @return A list of scoring rules. #' @keywords internal -#' @importFrom checkmate assert_subset +#' @importFrom checkmate assert_subset assert_list #' @examples #' scoringutils:::select_rules( #' possibilities = rules_binary(), @@ -16,6 +16,7 @@ #' ) select_rules <- function(possibilities, select, exclude = NULL) { assert_character(x = c(select, exclude), null.ok = TRUE) + assert_list(possibilities) allowed <- names(possibilities) if (select == "all" && is.null(exclude)) { From 00c1e990123993a384a14df31ef6cbb83b8643b4 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 11:04:15 +0100 Subject: [PATCH 07/21] Add tests for default scoring rules --- tests/testthat/test-default-scoring-rules.R | 71 +++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 tests/testthat/test-default-scoring-rules.R diff --git a/tests/testthat/test-default-scoring-rules.R b/tests/testthat/test-default-scoring-rules.R new file mode 100644 index 000000000..206181f5b --- /dev/null +++ b/tests/testthat/test-default-scoring-rules.R @@ -0,0 +1,71 @@ +test_that("`select_rules` works as expected", { + + expect_equal( + scoringutils:::select_rules(rules_point(), select = "all"), + rules_point() + ) + + expect_equal( + names(scoringutils:::select_rules(rules_point(), select = "ape")), + "ape" + ) + + expect_equal( + length(scoringutils:::select_rules(rules_point(), select = "all", exclude = "ape")), + length(rules_point()) - 1 + ) + + # if both select and exclude are specified, exclude is ignored + expect_equal( + names(scoringutils:::select_rules(rules_point(), select = "ape", exclude = "ape")), + "ape" + ) + + # expect error if possibilities is not a list + expect_error( + scoringutils:::select_rules(rules_point, select = "all"), + "Assertion on 'possibilities' failed: Must be of type 'list', not 'closure'." + ) +}) + + +test_that("default rules work as expected", { + + expect_true( + all(c( + is.list(rules_point()), + is.list(rules_binary()), + is.list(rules_quantile()), + is.list(rules_sample())) + ) + ) + + expect_equal( + names(rules_point(select = "ape")), + "ape" + ) + + expect_equal( + length(rules_binary(select = "all", exclude = "brier_score")), + length(rules_binary()) - 1 + ) + + # if both select and exclude are specified, exclude is ignored + expect_equal( + names(scoringutils:::select_rules(rules_quantile(), select = "wis", exclude = "wis")), + "wis" + ) + + # expect error if select is not included in the default possibilities + expect_error( + rules_sample(select = "not-included"), + "Must be a subset of" + ) + + # expect error if exclude is not included in the default possibilities + expect_error( + rules_quantile(exclude = "not-included"), + "Must be a subset of" + ) +}) + From ea2d09f3d25d64c1f3e66cb175e351c4489557c0 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 11:19:16 +0100 Subject: [PATCH 08/21] Fix linting issues --- R/default-scoring-rules.R | 44 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 3efd85434..6f0829884 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -47,8 +47,8 @@ select_rules <- function(possibilities, select, exclude = NULL) { #' rules_binary(exclude = "log_score") rules_binary <- function(select = "all", exclude = NULL) { all <- list( - "brier_score" = brier_score, - "log_score" = logs_binary + brier_score = brier_score, + log_score = logs_binary ) selected <- select_rules(all, select, exclude) return(selected) @@ -71,9 +71,9 @@ rules_binary <- function(select = "all", exclude = NULL) { #' rules_point(select = "ape") rules_point <- function(select = "all", exclude = NULL) { all <- list( - "ae_point" = Metrics::ae, - "se_point" = Metrics::se, - "ape" = Metrics::ape + ae_point = Metrics::ae, + se_point = Metrics::se, + ape = Metrics::ape ) selected <- select_rules(all, select, exclude) return(selected) @@ -101,13 +101,13 @@ rules_point <- function(select = "all", exclude = NULL) { #' rules_sample(select = "mad") rules_sample <- function(select = "all", exclude = NULL) { all <- list( - "bias" = bias_sample, - "dss" = dss_sample, - "crps" = crps_sample, - "log_score" = logs_sample, - "mad" = mad_sample, - "ae_median" = ae_median_sample, - "se_mean" = se_mean_sample + bias = bias_sample, + dss = dss_sample, + crps = crps_sample, + log_score = logs_sample, + mad = mad_sample, + ae_median = ae_median_sample, + se_mean = se_mean_sample ) selected <- select_rules(all, select, exclude) return(selected) @@ -138,15 +138,17 @@ rules_sample <- function(select = "all", exclude = NULL) { #' rules_quantile(select = "wis") rules_quantile <- function(select = "all", exclude = NULL) { all <- list( - "wis" = wis, - "overprediction" = overprediction, - "underprediction" = underprediction, - "dispersion" = dispersion, - "bias" = bias_quantile, - "coverage_50" = interval_coverage_quantile, - "coverage_90" = \(...) {run_safely(..., range = 90, fun = interval_coverage_quantile)}, - "coverage_deviation" = interval_coverage_dev_quantile, - "ae_median" = ae_median_quantile + wis = wis, + overprediction = overprediction, + underprediction = underprediction, + dispersion = dispersion, + bias = bias_quantile, + coverage_50 = interval_coverage_quantile, + coverage_90 = \(...) { + run_safely(..., range = 90, fun = interval_coverage_quantile) + }, + coverage_deviation = interval_coverage_dev_quantile, + ae_median = ae_median_quantile ) selected <- select_rules(all, select, exclude) return(selected) From d51a2fda41f0c346eec426c00fda446c87ddd105 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 11:25:08 +0100 Subject: [PATCH 09/21] Update NEWS.md file --- NEWS.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index e77c172c7..a991f3806 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# scoringutils 1.3 +# scoringutils 2.0.0 This major update and addresses a variety of comments made by reviewers from the Journal of Statistical Software (see preprint of the manuscript [here](https://arxiv.org/abs/2205.07090)). @@ -7,20 +7,21 @@ The update introduces breaking changes. If you want to keep using the older vers ## Package updates - In `score()`, required columns "true_value" and "prediction" were renamed and replaced by required columns "observed" and "predicted". Scoring functions now also use the function arguments "observed" and "predicted" everywhere consistently. - The overall scoring workflow was updated. `score()` is now a generic function that dispatches the correct method based on the forecast type. forecast types currently supported are "binary", "point", "sample" and "quantile" with corresponding classes "forecast_binary", "forecast_point", "forecast_sample" and "forecast_quantile". An object of class `forecast_*` can be created using the function `as_forecast()`, which also replaces the previous function `check_forecasts()` (see more information below). -- Scoring functions received a consistent interface and input checks: - - metrics for binary forecasts: +- Scoring rules (functions used for scoring) received a consistent interface and input checks: + - Scoring rules for binary forecasts: - `observed`: factor with exactly 2 levels - `predicted`: numeric, vector with probabilities - - metrics for point forecasts: + - Scoring rules for point forecasts: - `observed`: numeric vector - `predicted`: numeric vector - - metrics for sample-based forecasts: + - Scoring rules for sample-based forecasts: - `observed`: numeric, either a scalar or a vector - `predicted`: numeric, a vector (if `observed` is a scalar) or a matrix (if `observed` is a vector) - - metrics for quantile-based forecasts: + - Scoring rules for quantile-based forecasts: - `observed`: numeric, either a scalar or a vector - `predicted`: numeric, a vector (if `observed` is a scalar) or a matrix (if `observed` is a vector) - `quantile`: numeric, a vector with quantile-levels. Can alternatively be a matrix of the same shape as `predicted`. +- Users can now supply their own scoring rules to `score()` as a list of functions. Default scoring rules can be accessed using the functions `rules_point()`, `rules_sample()`, `rules_quantile()` and `rules_binary()`, which return a list of scoring rules suitable for the respective forecast type. - `check_forecasts()` was replaced by a different workflow. There now is a function, `as_forecast()`, that determines forecast type of the data, constructs a forecasting object and validates it using the function `validate_forecast()` (a generic that dispatches the correct method based on the forecast type). Objects of class `forecast_binary`, `forecast_point`, `forecast_sample` and `forecast_quantile` have print methods that fulfill the functionality of `check_forecasts()`. - The functionality for computing pairwise comparisons was now split from `summarise_scores()`. Instead of doing pairwise comparisons as part of summarising scores, a new function, `add_pairwise_comparison()`, was introduced that takes summarised scores as an input and adds pairwise comparisons to it. - `add_coverage()` was reworked completely. It's new purpose is now to add coverage information to the raw forecast data (essentially fulfilling some of the functionality that was previously covered by `score_quantile()`) From e78dfea15f9ef96dec855ac1ab9e32d46109aad1 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 11:48:20 +0100 Subject: [PATCH 10/21] replace `\()` by `function()` so that code works with R versions <4 --- R/default-scoring-rules.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 6f0829884..9ec9b3436 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -144,7 +144,7 @@ rules_quantile <- function(select = "all", exclude = NULL) { dispersion = dispersion, bias = bias_quantile, coverage_50 = interval_coverage_quantile, - coverage_90 = \(...) { + coverage_90 = function(...) { run_safely(..., range = 90, fun = interval_coverage_quantile) }, coverage_deviation = interval_coverage_dev_quantile, From 0d96e562cc556e210f107e953684652d29148e57 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 16:43:04 +0100 Subject: [PATCH 11/21] Change "possibilities" to "rules" as function argument, require named list --- R/default-scoring-rules.R | 18 +++++++++--------- man/select_rules.Rd | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 9ec9b3436..849949dbd 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -1,7 +1,7 @@ -#' @title Select Scoring Rules From A List of Possibilities +#' @title Select Scoring Rules From A List of Possible Scoring Rules #' @description Helper function to return only the scoring rules selected by #' the user from a list of possible scoring rules. -#' @param possibilities A list of scoring rules. +#' @param rules A list of scoring rules. #' @param select A character vector of scoring rules to select from the list. #' If `select = all` (the default), all possible scoring rules are returned. #' @param exclude A character vector of scoring rules to exclude from the list. @@ -11,23 +11,23 @@ #' @importFrom checkmate assert_subset assert_list #' @examples #' scoringutils:::select_rules( -#' possibilities = rules_binary(), +#' rules = rules_binary(), #' select = "brier_score" #' ) -select_rules <- function(possibilities, select, exclude = NULL) { +select_rules <- function(rules, select = "all", exclude = NULL) { assert_character(x = c(select, exclude), null.ok = TRUE) - assert_list(possibilities) - allowed <- names(possibilities) + assert_list(rules, names = TRUE) + allowed <- names(rules) if (select == "all" && is.null(exclude)) { - return(possibilities) + return(rules) } else if (select == "all") { assert_subset(exclude, allowed) select <- allowed[!allowed %in% exclude] - return(possibilities[select]) + return(rules[select]) } else { assert_subset(select, allowed) - return(possibilities[select]) + return(rules[select]) } } diff --git a/man/select_rules.Rd b/man/select_rules.Rd index cb763de3a..046bbc880 100644 --- a/man/select_rules.Rd +++ b/man/select_rules.Rd @@ -2,12 +2,12 @@ % Please edit documentation in R/default-scoring-rules.R \name{select_rules} \alias{select_rules} -\title{Select Scoring Rules From A List of Possibilities} +\title{Select Scoring Rules From A List of Possible Scoring Rules} \usage{ -select_rules(possibilities, select, exclude = NULL) +select_rules(rules, select = "all", exclude = NULL) } \arguments{ -\item{possibilities}{A list of scoring rules.} +\item{rules}{A list of scoring rules.} \item{select}{A character vector of scoring rules to select from the list. If \code{select = all} (the default), all possible scoring rules are returned.} @@ -24,7 +24,7 @@ the user from a list of possible scoring rules. } \examples{ scoringutils:::select_rules( - possibilities = rules_binary(), + rules = rules_binary(), select = "brier_score" ) } From 2253c6bac133abba5dc9310b7d5b1742bbd2d4c0 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 16:47:54 +0100 Subject: [PATCH 12/21] fix error checking for named input --- R/default-scoring-rules.R | 2 +- tests/testthat/test-default-scoring-rules.R | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 849949dbd..8bee15987 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -16,7 +16,7 @@ #' ) select_rules <- function(rules, select = "all", exclude = NULL) { assert_character(x = c(select, exclude), null.ok = TRUE) - assert_list(rules, names = TRUE) + assert_list(rules, names = "named") allowed <- names(rules) if (select == "all" && is.null(exclude)) { diff --git a/tests/testthat/test-default-scoring-rules.R b/tests/testthat/test-default-scoring-rules.R index 206181f5b..853508ab3 100644 --- a/tests/testthat/test-default-scoring-rules.R +++ b/tests/testthat/test-default-scoring-rules.R @@ -5,6 +5,11 @@ test_that("`select_rules` works as expected", { rules_point() ) + expect_equal( + scoringutils:::select_rules(rules_point(), select = "all"), + scoringutils:::select_rules(rules_point()) + ) + expect_equal( names(scoringutils:::select_rules(rules_point(), select = "ape")), "ape" From 28213bdf14dad937217ca9bcd4a998790ac78244 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Tue, 2 Jan 2024 16:49:25 +0100 Subject: [PATCH 13/21] fix failing test --- tests/testthat/test-default-scoring-rules.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-default-scoring-rules.R b/tests/testthat/test-default-scoring-rules.R index 853508ab3..49d59db3d 100644 --- a/tests/testthat/test-default-scoring-rules.R +++ b/tests/testthat/test-default-scoring-rules.R @@ -29,7 +29,7 @@ test_that("`select_rules` works as expected", { # expect error if possibilities is not a list expect_error( scoringutils:::select_rules(rules_point, select = "all"), - "Assertion on 'possibilities' failed: Must be of type 'list', not 'closure'." + "Assertion on 'rules' failed: Must be of type 'list', not 'closure'." ) }) From 97cca5935c8377c17020208250b6623a15851b45 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:16:51 +0100 Subject: [PATCH 14/21] Export `select_rules()` to users --- NAMESPACE | 1 + R/default-scoring-rules.R | 5 +++-- man/select_rules.Rd | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index c0f344dac..c4ba7a2dc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -67,6 +67,7 @@ export(run_safely) export(sample_to_quantile) export(score) export(se_mean_sample) +export(select_rules) export(set_forecast_unit) export(squared_error) export(summarise_scores) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 8bee15987..b81fa2079 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -7,10 +7,11 @@ #' @param exclude A character vector of scoring rules to exclude from the list. #' If `select != "all"`, this argument is ignored. #' @return A list of scoring rules. -#' @keywords internal +#' @keywords metric #' @importFrom checkmate assert_subset assert_list +#' @export #' @examples -#' scoringutils:::select_rules( +#' select_rules( #' rules = rules_binary(), #' select = "brier_score" #' ) diff --git a/man/select_rules.Rd b/man/select_rules.Rd index 046bbc880..9139c85c9 100644 --- a/man/select_rules.Rd +++ b/man/select_rules.Rd @@ -23,9 +23,9 @@ Helper function to return only the scoring rules selected by the user from a list of possible scoring rules. } \examples{ -scoringutils:::select_rules( +select_rules( rules = rules_binary(), select = "brier_score" ) } -\keyword{internal} +\keyword{metric} From 9240ba7bf907109ed3c3897cc6f81a8fb3f48774 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:23:15 +0100 Subject: [PATCH 15/21] Change function default from `select = "all"` to `select = NULL` --- R/default-scoring-rules.R | 19 ++++++++++++------- man/rules_binary.Rd | 4 ++-- man/rules_point.Rd | 6 +++--- man/rules_quantile.Rd | 6 +++--- man/rules_sample.Rd | 4 ++-- man/select_rules.Rd | 10 +++++++--- 6 files changed, 29 insertions(+), 20 deletions(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index b81fa2079..8659ac7ca 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -3,9 +3,9 @@ #' the user from a list of possible scoring rules. #' @param rules A list of scoring rules. #' @param select A character vector of scoring rules to select from the list. -#' If `select = all` (the default), all possible scoring rules are returned. +#' If `select` is `NULL` (the default), all possible scoring rules are returned. #' @param exclude A character vector of scoring rules to exclude from the list. -#' If `select != "all"`, this argument is ignored. +#' If `select` is not `NULL`, this argument is ignored. #' @return A list of scoring rules. #' @keywords metric #' @importFrom checkmate assert_subset assert_list @@ -15,14 +15,18 @@ #' rules = rules_binary(), #' select = "brier_score" #' ) -select_rules <- function(rules, select = "all", exclude = NULL) { +#' select_rules( +#' rules = rules_binary(), +#' exclude = "log_score" +#' ) +select_rules <- function(rules, select = NULL, exclude = NULL) { assert_character(x = c(select, exclude), null.ok = TRUE) assert_list(rules, names = "named") allowed <- names(rules) - if (select == "all" && is.null(exclude)) { + if (is.null(select) && is.null(exclude)) { return(rules) - } else if (select == "all") { + } else if (is.null(select)) { assert_subset(exclude, allowed) select <- allowed[!allowed %in% exclude] return(rules[select]) @@ -32,6 +36,7 @@ select_rules <- function(rules, select = "all", exclude = NULL) { } } + #' @title Scoring Rules for Binary Forecasts #' @description Helper function that returns a named list of default #' scoring rules suitable for binary forecasts. @@ -70,7 +75,7 @@ rules_binary <- function(select = "all", exclude = NULL) { #' @examples #' rules_point() #' rules_point(select = "ape") -rules_point <- function(select = "all", exclude = NULL) { +rules_point <- function(select = NULL, exclude = NULL) { all <- list( ae_point = Metrics::ae, se_point = Metrics::se, @@ -126,7 +131,7 @@ rules_sample <- function(select = "all", exclude = NULL) { #' - "dispersion" = [dispersion()] #' - "bias" = [bias_quantile()] #' - "coverage_50" = [interval_coverage_quantile()] -#' - "coverage_90" = \(...) \{ +#' - "coverage_90" = (...) \{ #' run_safely(..., range = 90, fun = [interval_coverage_quantile]) #' \} #' - "coverage_deviation" = [interval_coverage_dev_quantile()], diff --git a/man/rules_binary.Rd b/man/rules_binary.Rd index 612926e32..fbcf49528 100644 --- a/man/rules_binary.Rd +++ b/man/rules_binary.Rd @@ -8,10 +8,10 @@ rules_binary(select = "all", exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. -If \code{select = all} (the default), all possible scoring rules are returned.} +If \code{select} is \code{NULL} (the default), all possible scoring rules are returned.} \item{exclude}{A character vector of scoring rules to exclude from the list. -If \code{select != "all"}, this argument is ignored.} +If \code{select} is not \code{NULL}, this argument is ignored.} } \value{ A list of scoring rules. diff --git a/man/rules_point.Rd b/man/rules_point.Rd index 6ca51267e..1deddc616 100644 --- a/man/rules_point.Rd +++ b/man/rules_point.Rd @@ -4,14 +4,14 @@ \alias{rules_point} \title{Scoring Rules for Point Forecasts} \usage{ -rules_point(select = "all", exclude = NULL) +rules_point(select = NULL, exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. -If \code{select = all} (the default), all possible scoring rules are returned.} +If \code{select} is \code{NULL} (the default), all possible scoring rules are returned.} \item{exclude}{A character vector of scoring rules to exclude from the list. -If \code{select != "all"}, this argument is ignored.} +If \code{select} is not \code{NULL}, this argument is ignored.} } \value{ A list of scoring rules. diff --git a/man/rules_quantile.Rd b/man/rules_quantile.Rd index c947c8b61..c6dfdb857 100644 --- a/man/rules_quantile.Rd +++ b/man/rules_quantile.Rd @@ -8,10 +8,10 @@ rules_quantile(select = "all", exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. -If \code{select = all} (the default), all possible scoring rules are returned.} +If \code{select} is \code{NULL} (the default), all possible scoring rules are returned.} \item{exclude}{A character vector of scoring rules to exclude from the list. -If \code{select != "all"}, this argument is ignored.} +If \code{select} is not \code{NULL}, this argument is ignored.} } \value{ A list of scoring rules. @@ -28,7 +28,7 @@ The default scoring rules are: \item "dispersion" = \code{\link[=dispersion]{dispersion()}} \item "bias" = \code{\link[=bias_quantile]{bias_quantile()}} \item "coverage_50" = \code{\link[=interval_coverage_quantile]{interval_coverage_quantile()}} -\item "coverage_90" = \(...) \{ +\item "coverage_90" = (...) \{ run_safely(..., range = 90, fun = \link{interval_coverage_quantile}) \} \item "coverage_deviation" = \code{\link[=interval_coverage_dev_quantile]{interval_coverage_dev_quantile()}}, diff --git a/man/rules_sample.Rd b/man/rules_sample.Rd index daeb4c54b..d9cff1aa4 100644 --- a/man/rules_sample.Rd +++ b/man/rules_sample.Rd @@ -8,10 +8,10 @@ rules_sample(select = "all", exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. -If \code{select = all} (the default), all possible scoring rules are returned.} +If \code{select} is \code{NULL} (the default), all possible scoring rules are returned.} \item{exclude}{A character vector of scoring rules to exclude from the list. -If \code{select != "all"}, this argument is ignored.} +If \code{select} is not \code{NULL}, this argument is ignored.} } \value{ A list of scoring rules. diff --git a/man/select_rules.Rd b/man/select_rules.Rd index 9139c85c9..605d7176b 100644 --- a/man/select_rules.Rd +++ b/man/select_rules.Rd @@ -4,16 +4,16 @@ \alias{select_rules} \title{Select Scoring Rules From A List of Possible Scoring Rules} \usage{ -select_rules(rules, select = "all", exclude = NULL) +select_rules(rules, select = NULL, exclude = NULL) } \arguments{ \item{rules}{A list of scoring rules.} \item{select}{A character vector of scoring rules to select from the list. -If \code{select = all} (the default), all possible scoring rules are returned.} +If \code{select} is \code{NULL} (the default), all possible scoring rules are returned.} \item{exclude}{A character vector of scoring rules to exclude from the list. -If \code{select != "all"}, this argument is ignored.} +If \code{select} is not \code{NULL}, this argument is ignored.} } \value{ A list of scoring rules. @@ -27,5 +27,9 @@ select_rules( rules = rules_binary(), select = "brier_score" ) +select_rules( + rules = rules_binary(), + exclude = "log_score" +) } \keyword{metric} From 12c69b5fe883fe9c8bf3559b2e1ce5e78438eccc Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:25:01 +0100 Subject: [PATCH 16/21] Update argument to `select = NULL` --- R/default-scoring-rules.R | 6 +++--- man/rules_binary.Rd | 2 +- man/rules_quantile.Rd | 2 +- man/rules_sample.Rd | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 8659ac7ca..d02783210 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -51,7 +51,7 @@ select_rules <- function(rules, select = NULL, exclude = NULL) { #' rules_binary() #' rules_binary(select = "brier_score") #' rules_binary(exclude = "log_score") -rules_binary <- function(select = "all", exclude = NULL) { +rules_binary <- function(select = NULL, exclude = NULL) { all <- list( brier_score = brier_score, log_score = logs_binary @@ -105,7 +105,7 @@ rules_point <- function(select = NULL, exclude = NULL) { #' @examples #' rules_sample() #' rules_sample(select = "mad") -rules_sample <- function(select = "all", exclude = NULL) { +rules_sample <- function(select = NULL, exclude = NULL) { all <- list( bias = bias_sample, dss = dss_sample, @@ -142,7 +142,7 @@ rules_sample <- function(select = "all", exclude = NULL) { #' @examples #' rules_quantile() #' rules_quantile(select = "wis") -rules_quantile <- function(select = "all", exclude = NULL) { +rules_quantile <- function(select = NULL, exclude = NULL) { all <- list( wis = wis, overprediction = overprediction, diff --git a/man/rules_binary.Rd b/man/rules_binary.Rd index fbcf49528..ca408aeac 100644 --- a/man/rules_binary.Rd +++ b/man/rules_binary.Rd @@ -4,7 +4,7 @@ \alias{rules_binary} \title{Scoring Rules for Binary Forecasts} \usage{ -rules_binary(select = "all", exclude = NULL) +rules_binary(select = NULL, exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. diff --git a/man/rules_quantile.Rd b/man/rules_quantile.Rd index c6dfdb857..f7b7c052f 100644 --- a/man/rules_quantile.Rd +++ b/man/rules_quantile.Rd @@ -4,7 +4,7 @@ \alias{rules_quantile} \title{Scoring Rules for Quantile-Based Forecasts} \usage{ -rules_quantile(select = "all", exclude = NULL) +rules_quantile(select = NULL, exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. diff --git a/man/rules_sample.Rd b/man/rules_sample.Rd index d9cff1aa4..d4622637a 100644 --- a/man/rules_sample.Rd +++ b/man/rules_sample.Rd @@ -4,7 +4,7 @@ \alias{rules_sample} \title{Scoring Rules for Sample-Based Forecasts} \usage{ -rules_sample(select = "all", exclude = NULL) +rules_sample(select = NULL, exclude = NULL) } \arguments{ \item{select}{A character vector of scoring rules to select from the list. From b29223a328db24b3f16b8c429135433efba087c1 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:27:34 +0100 Subject: [PATCH 17/21] Update function documentation and pkgdown keywords --- R/default-scoring-rules.R | 10 +++++----- man/rules_binary.Rd | 2 +- man/rules_point.Rd | 2 +- man/rules_quantile.Rd | 4 ++-- man/rules_sample.Rd | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index d02783210..5f565116b 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -46,7 +46,7 @@ select_rules <- function(rules, select = NULL, exclude = NULL) { #' - "log_score" = [logs_binary()] #' @inherit select_rules params return #' @export -#' @keywords info +#' @keywords metric #' @examples #' rules_binary() #' rules_binary(select = "brier_score") @@ -71,7 +71,7 @@ rules_binary <- function(select = NULL, exclude = NULL) { #' - "ape" = [ape()][Metrics::ape()] #' @inherit select_rules params return #' @export -#' @keywords info +#' @keywords metric #' @examples #' rules_point() #' rules_point(select = "ape") @@ -101,7 +101,7 @@ rules_point <- function(select = NULL, exclude = NULL) { #' - "se_mean" = [se_mean_sample()] #' @inherit select_rules params return #' @export -#' @keywords info +#' @keywords metric #' @examples #' rules_sample() #' rules_sample(select = "mad") @@ -131,14 +131,14 @@ rules_sample <- function(select = NULL, exclude = NULL) { #' - "dispersion" = [dispersion()] #' - "bias" = [bias_quantile()] #' - "coverage_50" = [interval_coverage_quantile()] -#' - "coverage_90" = (...) \{ +#' - "coverage_90" = function(...) \{ #' run_safely(..., range = 90, fun = [interval_coverage_quantile]) #' \} #' - "coverage_deviation" = [interval_coverage_dev_quantile()], #' - "ae_median" = [ae_median_quantile()] #' @inherit select_rules params return #' @export -#' @keywords info +#' @keywords metric #' @examples #' rules_quantile() #' rules_quantile(select = "wis") diff --git a/man/rules_binary.Rd b/man/rules_binary.Rd index ca408aeac..f5c455e35 100644 --- a/man/rules_binary.Rd +++ b/man/rules_binary.Rd @@ -31,4 +31,4 @@ rules_binary() rules_binary(select = "brier_score") rules_binary(exclude = "log_score") } -\keyword{info} +\keyword{metric} diff --git a/man/rules_point.Rd b/man/rules_point.Rd index 1deddc616..55f562dc9 100644 --- a/man/rules_point.Rd +++ b/man/rules_point.Rd @@ -31,4 +31,4 @@ The default scoring rules are: rules_point() rules_point(select = "ape") } -\keyword{info} +\keyword{metric} diff --git a/man/rules_quantile.Rd b/man/rules_quantile.Rd index f7b7c052f..034403df5 100644 --- a/man/rules_quantile.Rd +++ b/man/rules_quantile.Rd @@ -28,7 +28,7 @@ The default scoring rules are: \item "dispersion" = \code{\link[=dispersion]{dispersion()}} \item "bias" = \code{\link[=bias_quantile]{bias_quantile()}} \item "coverage_50" = \code{\link[=interval_coverage_quantile]{interval_coverage_quantile()}} -\item "coverage_90" = (...) \{ +\item "coverage_90" = function(...) \{ run_safely(..., range = 90, fun = \link{interval_coverage_quantile}) \} \item "coverage_deviation" = \code{\link[=interval_coverage_dev_quantile]{interval_coverage_dev_quantile()}}, @@ -39,4 +39,4 @@ run_safely(..., range = 90, fun = \link{interval_coverage_quantile}) rules_quantile() rules_quantile(select = "wis") } -\keyword{info} +\keyword{metric} diff --git a/man/rules_sample.Rd b/man/rules_sample.Rd index d4622637a..0a6399beb 100644 --- a/man/rules_sample.Rd +++ b/man/rules_sample.Rd @@ -36,4 +36,4 @@ The default scoring rules are: rules_sample() rules_sample(select = "mad") } -\keyword{info} +\keyword{metric} From c71f1ba252a8bfc05f60e5356b0646741175867a Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:36:08 +0100 Subject: [PATCH 18/21] Update function documentation --- R/default-scoring-rules.R | 8 ++++++++ R/utils.R | 2 +- man/rules_quantile.Rd | 8 ++++++++ man/run_safely.Rd | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/R/default-scoring-rules.R b/R/default-scoring-rules.R index 5f565116b..9dd6fd24d 100644 --- a/R/default-scoring-rules.R +++ b/R/default-scoring-rules.R @@ -136,6 +136,14 @@ rules_sample <- function(select = NULL, exclude = NULL) { #' \} #' - "coverage_deviation" = [interval_coverage_dev_quantile()], #' - "ae_median" = [ae_median_quantile()] +#' +#' Note: The `coverage_90` scoring rule is created as a wrapper around +#' [interval_coverage_quantile()], making use of the function [run_safely()]. +#' This construct allows the function to deal with arbitrary arguments in `...`, +#' while making sure that only those that [interval_coverage_quantile()] can +#' accept get passed on to it. `range = 90` is set in the function definition, +#' as passing an argument `range = 90` to [score()] would mean it would also +#' get passed to `coverage_50`. #' @inherit select_rules params return #' @export #' @keywords metric diff --git a/R/utils.R b/R/utils.R index 8e5e8a9e1..680166bc5 100644 --- a/R/utils.R +++ b/R/utils.R @@ -145,7 +145,7 @@ strip_attributes <- function(object, attributes) { #' @title Run a function safely #' @description This is a wrapper function designed to run a function safely -#' when it is not completely clear what arguments coulld be passed to the +#' when it is not completely clear what arguments could be passed to the #' function. #' #' All named arguments in `...` that are not accepted by `fun` are removed. diff --git a/man/rules_quantile.Rd b/man/rules_quantile.Rd index 034403df5..78b24342b 100644 --- a/man/rules_quantile.Rd +++ b/man/rules_quantile.Rd @@ -34,6 +34,14 @@ run_safely(..., range = 90, fun = \link{interval_coverage_quantile}) \item "coverage_deviation" = \code{\link[=interval_coverage_dev_quantile]{interval_coverage_dev_quantile()}}, \item "ae_median" = \code{\link[=ae_median_quantile]{ae_median_quantile()}} } + +Note: The \code{coverage_90} scoring rule is created as a wrapper around +\code{\link[=interval_coverage_quantile]{interval_coverage_quantile()}}, making use of the function \code{\link[=run_safely]{run_safely()}}. +This construct allows the function to deal with arbitrary arguments in \code{...}, +while making sure that only those that \code{\link[=interval_coverage_quantile]{interval_coverage_quantile()}} can +accept get passed on to it. \code{range = 90} is set in the function definition, +as passing an argument \code{range = 90} to \code{\link[=score]{score()}} would mean it would also +get passed to \code{coverage_50}. } \examples{ rules_quantile() diff --git a/man/run_safely.Rd b/man/run_safely.Rd index b8c45751f..a4f809040 100644 --- a/man/run_safely.Rd +++ b/man/run_safely.Rd @@ -16,7 +16,7 @@ The result of \code{fun} or \code{NULL} if \code{fun} errors } \description{ This is a wrapper function designed to run a function safely -when it is not completely clear what arguments coulld be passed to the +when it is not completely clear what arguments could be passed to the function. All named arguments in \code{...} that are not accepted by \code{fun} are removed. From cf59af62615913d1ce104e50ad75803ee32022fe Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:40:43 +0100 Subject: [PATCH 19/21] Update tests to reflect the change to `select = NULL` in `select_rules()` --- tests/testthat/test-default-scoring-rules.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-default-scoring-rules.R b/tests/testthat/test-default-scoring-rules.R index 49d59db3d..3c6c59dad 100644 --- a/tests/testthat/test-default-scoring-rules.R +++ b/tests/testthat/test-default-scoring-rules.R @@ -1,12 +1,12 @@ test_that("`select_rules` works as expected", { expect_equal( - scoringutils:::select_rules(rules_point(), select = "all"), + scoringutils:::select_rules(rules_point(), select = NULL), rules_point() ) expect_equal( - scoringutils:::select_rules(rules_point(), select = "all"), + scoringutils:::select_rules(rules_point(), select = NULL), scoringutils:::select_rules(rules_point()) ) @@ -16,7 +16,7 @@ test_that("`select_rules` works as expected", { ) expect_equal( - length(scoringutils:::select_rules(rules_point(), select = "all", exclude = "ape")), + length(scoringutils:::select_rules(rules_point(), select = NULL, exclude = "ape")), length(rules_point()) - 1 ) @@ -28,7 +28,7 @@ test_that("`select_rules` works as expected", { # expect error if possibilities is not a list expect_error( - scoringutils:::select_rules(rules_point, select = "all"), + scoringutils:::select_rules(rules_point, select = NULL), "Assertion on 'rules' failed: Must be of type 'list', not 'closure'." ) }) From 890ab29f3a57a44ee2c4b6bf943a8646045ece89 Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 11:44:08 +0100 Subject: [PATCH 20/21] Update failing test --- tests/testthat/test-default-scoring-rules.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-default-scoring-rules.R b/tests/testthat/test-default-scoring-rules.R index 3c6c59dad..a53dcbe00 100644 --- a/tests/testthat/test-default-scoring-rules.R +++ b/tests/testthat/test-default-scoring-rules.R @@ -51,7 +51,7 @@ test_that("default rules work as expected", { ) expect_equal( - length(rules_binary(select = "all", exclude = "brier_score")), + length(rules_binary(select = NULL, exclude = "brier_score")), length(rules_binary()) - 1 ) From afb8a39c7c30954c72a91fb38770edff0a32a02d Mon Sep 17 00:00:00 2001 From: nikosbosse Date: Wed, 3 Jan 2024 16:43:10 +0100 Subject: [PATCH 21/21] Omit `NA` values when checking the number of samples / quantiles per forceast --- R/check-input-helpers.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/check-input-helpers.R b/R/check-input-helpers.R index 63bace514..0470829d8 100644 --- a/R/check-input-helpers.R +++ b/R/check-input-helpers.R @@ -211,6 +211,7 @@ assure_model_column <- function(data) { #' @inherit document_check_functions params return #' @keywords internal_input_check check_number_per_forecast <- function(data, forecast_unit) { + data <- na.omit(data) # check whether there are the same number of quantiles, samples -------------- data[, scoringutils_InternalNumCheck := length(predicted), by = forecast_unit] n <- unique(data$scoringutils_InternalNumCheck)