A variety of metrics and scoring rules can also be accessed directly
through the scoringutils
package.
The following gives an overview of (most of) the implemented metrics.
The function bias
determines bias from predictive
Monte-Carlo samples, automatically recognising whether forecasts are
continuous or integer valued.
For continuous forecasts, Bias is measured as \[B_t (P_t, x_t) = 1 - 2 \cdot (P_t (x_t))\]
where \(P_t\) is the empirical cumulative distribution function of the prediction for the true value \(x_t\). Computationally, \(P_t (x_t)\) is just calculated as the fraction of predictive samples for \(x_t\) that are smaller than \(x_t\).
For integer valued forecasts, Bias is measured as
\[B_t (P_t, x_t) = 1 - (P_t (x_t) + P_t (x_t + 1))\]
to adjust for the integer nature of the forecasts. In both cases, Bias can assume values between -1 and 1 and is 0 ideally.
## integer valued forecasts
<- rpois(30, lambda = 1:30)
true_values <- replicate(200, rpois(n = 30, lambda = 1:30))
predictions bias_sample(true_values, predictions)
#> [1] -0.90 0.78 -0.94 -0.31 0.83 -0.91 -0.46 -0.81 0.82 0.54 0.68 -0.20
#> [13] -0.49 0.32 -0.35 -0.14 -0.30 -0.49 0.05 0.34 0.56 0.89 -0.37 -0.69
#> [25] 0.45 0.66 -0.30 0.22 -0.51 -0.46
## continuous forecasts
<- rnorm(30, mean = 1:30)
true_values <- replicate(200, rnorm(30, mean = 1:30))
predictions bias_sample(true_values, predictions)
#> [1] -0.81 0.08 -0.77 -0.28 -0.58 -0.32 -0.43 -0.72 -0.45 0.23 0.95 0.87
#> [13] -0.32 0.59 -0.82 0.24 -0.81 0.92 -0.64 0.88 -0.87 -0.29 -0.83 0.11
#> [25] 0.13 -0.12 0.63 -0.17 0.40 -0.07
Calibration or reliability of forecasts is the ability of a model to correctly identify its own uncertainty in making predictions. In a model with perfect calibration, the observed data at each time point look as if they came from the predictive probability distribution at that time.
Equivalently, one can inspect the probability integral transform of the predictive distribution at time t,
\[u_t = F_t (x_t)\]
where \(x_t\) is the observed data point at time \(t \text{ in } t_1, …, t_n\), n being the number of forecasts, and \(F_t\) is the (continuous) predictive cumulative probability distribution at time t. If the true probability distribution of outcomes at time t is \(G_t\) then the forecasts \(F_t\) are said to be ideal if \(F_t = G_t\) at all times \(t\). In that case, the probabilities ut are distributed uniformly.
In the case of discrete outcomes such as incidence counts, the PIT is no longer uniform even when forecasts are ideal. In that case a randomised PIT can be used instead:
\[u_t = P_t(k_t) + v \cdot (P_t(k_t) - P_t(k_t - 1) )\]
where \(k_t\) is the observed count, \(P_t(x)\) is the predictive cumulative probability of observing incidence \(k\) at time \(t\), \(P_t (-1) = 0\) by definition and \(v\) is standard uniform and independent of \(k\). If \(P_t\) is the true cumulative probability distribution, then \(u_t\) is standard uniform.
The function checks whether integer or continuous forecasts were provided. It then applies the (randomised) probability integral and tests the values \(u_t\) for uniformity using the Anderson-Darling test.
As a rule of thumb, there is no evidence to suggest a forecasting model is miscalibrated if the p-value found was greater than a threshold of \(p >= 0.1\), some evidence that it was miscalibrated if \(0.01 < p < 0.1\), and good evidence that it was miscalibrated if \(p <= 0.01\). In this context it should be noted, though, that uniformity of the PIT is a necessary but not sufficient condition of calibration. It should also be noted that the test only works given sufficient samples, otherwise the Null hypothesis will often be rejected outright.
Wrapper around the crps_sample()
function from the
scoringRules
package. For more information look at the
manuals from the scoringRules
package. The function can be
used for continuous as well as integer valued forecasts. Smaller values
are better.
<- rpois(30, lambda = 1:30)
true_values <- replicate(200, rpois(n = 30, lambda = 1:30))
predictions crps_sample(true_values, predictions)
#> [1] 0.429775 0.281750 0.524600 0.602725 1.262075 1.080250 0.629675 0.890025
#> [9] 0.876000 0.970050 0.844025 1.263600 0.929700 1.344850 0.879525 4.101475
#> [17] 1.031975 1.804100 2.870250 2.725900 2.939950 3.869800 1.246525 1.711725
#> [25] 1.721675 1.204450 2.031775 1.643200 2.488150 3.597225
Wrapper around the dss_sample()
function from the
scoringRules
package. For more information look at the
manuals from the scoringRules
package. The function can be
used for continuous as well as integer valued forecasts. Smaller values
are better.
<- rpois(30, lambda = 1:30)
true_values <- replicate(200, rpois(n = 30, lambda = 1:30))
predictions dss_sample(true_values, predictions)
#> [1] 1.1806501 0.7724205 2.3711260 8.5101478 1.8862851 1.9397989 2.1021237
#> [8] 2.1750992 4.6629699 2.9085047 2.3466570 5.1580051 2.6675912 2.8995027
#> [15] 2.8219740 3.7333843 2.8545581 2.9373084 3.1665251 4.1997797 3.3279192
#> [22] 3.4145497 4.5998931 3.2290007 3.3030058 3.6157869 7.6454929 4.6537346
#> [29] 3.7256697 4.8384816
Wrapper around the logs_sample()
function from the
scoringRules
package. For more information look at the
manuals from the scoringRules
package. The function should
not be used for integer valued forecasts. While Log Scores are in
principle possible for integer valued forecasts they require a kernel
density estimate which is not well defined for discrete values. Smaller
values are better.
<- rnorm(30, mean = 1:30)
true_values <- replicate(200, rnorm(n = 30, mean = 1:30))
predictions logs_sample(true_values, predictions)
#> [1] 0.9148593 2.2015025 0.9810609 1.1270173 1.3074626 1.5869638 1.6786254
#> [8] 1.9799950 4.4090563 1.0118336 1.7137631 1.4145373 3.3250302 1.1966158
#> [15] 1.0588706 2.5730175 2.6622540 0.9887906 1.4609316 2.5428668 1.1401444
#> [22] 2.6268288 1.0889910 1.5231457 2.5961462 3.1843058 0.9939355 1.5940437
#> [29] 1.1808028 1.0143136
The Brier score is a proper score rule that assesses the accuracy of probabilistic binary predictions. The outcomes can be either 0 or 1, the predictions must be a probability that the true outcome will be 1.
The Brier Score is then computed as the mean squared error between the probabilistic prediction and the true outcome.
\[\text{Brier_Score} = \frac{1}{N} \sum_{t = 1}^{n} (\text{prediction}_t - \text{outcome}_t)^2\]
<- sample(c(0, 1), size = 30, replace = TRUE)
true_values <- runif(n = 30, min = 0, max = 1)
predictions
brier_score(true_values, predictions)
#> [1] 0.869822990 0.553971549 0.605277392 0.281430698 0.524834679 0.154998911
#> [7] 0.082265040 0.874273347 0.964359615 0.009161109 0.130904205 0.232579075
#> [13] 0.040088802 0.089768559 0.180337385 0.857109108 0.146643003 0.399187509
#> [19] 0.093691130 0.039430998 0.028903374 0.001824507 0.088766496 0.064580364
#> [25] 0.005353511 0.903184243 0.175981473 0.716227636 0.050954844 0.018651464
The Interval Score is a Proper Scoring Rule to score quantile predictions, following Gneiting and Raftery (2007). Smaller values are better.
The score is computed as
\[ \text{score} = (\text{upper} - \text{lower}) + \\ \frac{2}{\alpha} \cdot (\text{lower} - \text{true_value}) \cdot 1(\text{true_values} < \text{lower}) + \\ \frac{2}{\alpha} \cdot (\text{true_value} - \text{upper}) \cdot 1(\text{true_value} > \text{upper})\]
where \(1()\) is the indicator
function and \(\alpha\) is the decimal
value that indicates how much is outside the prediction interval. To
improve usability, the user is asked to provide an interval range in
percentage terms, i.e. interval_range = 90 (percent) for a 90 percent
prediction interval. Correspondingly, the user would have to provide the
5% and 95% quantiles (the corresponding alpha would then be 0.1). No
specific distribution is assumed, but the range has to be symmetric (i.e
you can’t use the 0.1 quantile as the lower bound and the 0.7 quantile
as the upper). Setting weigh = TRUE
will weigh the score by
\(\frac{\alpha}{2}\) such that the
Interval Score converges to the CRPS for increasing number of
quantiles.
<- rnorm(30, mean = 1:30)
true_values <- 90
interval_range <- (100 - interval_range) / 100
alpha <- qnorm(alpha / 2, rnorm(30, mean = 1:30))
lower <- qnorm((1 - alpha / 2), rnorm(30, mean = 1:30))
upper
interval_score(
true_values = true_values,
lower = lower,
upper = upper,
interval_range = interval_range
)#> [1] 0.1018407 0.2706393 0.5343236 1.4272554 0.1484149 0.1322816 0.5843382
#> [8] 0.1788821 0.4251177 0.1990973 0.1543250 0.2557435 0.1632156 0.2234433
#> [15] 0.1620806 0.2060813 0.2629933 0.1858109 0.2021390 0.1695048 0.1644547
#> [22] 0.2707416 0.3100129 0.1950517 0.1263768 0.2534080 0.1257435 0.6983067
#> [29] 0.2021879 0.2843696