--- title: "Predictive-uncertainty evaluation" author: "Alexandre M.J.-C. Wadoux" output: rmarkdown::html_vignette bibliography: references.bib link-citations: true vignette: > %\VignetteIndexEntry{Predictive-uncertainty evaluation} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5 ) ``` ## 1. Why validate predictive uncertainty? Point-prediction metrics assess how close predictions are to observations, but many models also quantify how uncertain each prediction is. This information may be supplied as prediction intervals, predicted quantiles, a predictive mean and standard deviation, or a complete predictive distribution. These probabilistic predictions should be validated just like point predictions. A poorly calibrated uncertainty estimate can give users unwarranted confidence in a prediction even when the point prediction itself appears reasonable. Two properties are particularly important: - **Calibration**, also called **reliability**, describes whether stated probabilities agree with observed frequencies. For example, approximately 90% of independent observations should fall inside intervals presented as 90% prediction intervals. - **Sharpness** describes how concentrated the predictive distributions are. Narrower prediction intervals correspond to sharper predictions. Sharpness should always be interpreted conditional on adequate calibration. Very narrow intervals are not useful when observations frequently fall outside them. The general objective is therefore to obtain predictive distributions that are as sharp as possible while remaining well calibrated [@schmidinger2023; @gneitingraftery2007]. As with point-prediction validation, these diagnostics should be calculated using independent validation data or an appropriate resampling strategy. ## 2. Which form of predictive uncertainty do you have? Probabilistic predictions can be supplied in several forms, including prediction intervals, predicted quantiles, predictive means and standard deviations, and full predictive distributions. This tutorial develops two broad worked cases: - **Case A — predictive mean and standard deviation**: the predictive distribution is summarized by its mean and standard deviation. Prediction intervals, quantiles, CDF values, and densities can be derived when an appropriate distributional assumption is available. - **Case B — predictive samples**: the predictive distribution is represented directly by predictive samples or draws. This can preserve features such as skewness, heavy tails, and multimodality that may not be represented by a mean and standard deviation alone. Prediction intervals and quantiles may also be supplied directly by a model. The same validation principles apply regardless of how they were generated. A model may also provide several representations of the same predictive distribution. ## 3. Functions used in this tutorial The main `modelskill` functions used below are: | Function | Description | Reference | | :-- | :-- | :-- | | [`picp()`](../reference/picp.html) | Calculates the prediction interval coverage probability, that is, the proportion of observations falling within a prediction interval. | [@goovaerts2001; @schmidinger2023] | | [`coverage_error()`](../reference/coverage_error.html) | Calculates the difference between empirical and nominal prediction interval coverage. | [@schmidinger2023] | | [`interval_width()`](../reference/interval_width.html) | Calculates the average width of prediction intervals and therefore summarizes their sharpness. | [@schmidinger2023] | | [`interval_score()`](../reference/interval_score.html) | Calculates a proper scoring rule that combines prediction interval width with penalties for observations outside the interval. | [@gneitingraftery2007] | | [`uncertainty_metrics()`](../reference/uncertainty_metrics.html) | Calculates PICP, coverage error, interval width, and interval score together. | [@gneitingraftery2007; @schmidinger2023] | | [`gg_coverage()`](../reference/gg_coverage.html) | Produces a reliability plot comparing nominal prediction interval coverage with empirical coverage across several interval levels. | [@goovaerts2001; @schmidinger2023] | | [`accuracy_plot_metrics()`](../reference/accuracy_plot_metrics.html) | Summarizes deviations between the empirical coverage curve and the ideal 1:1 reliability line. | [@goovaerts2001; @schmidinger2023] | | [`qcp()`](../reference/qcp.html) | Calculates quantile coverage probability, the proportion of observations below each predicted quantile. | [@schmidinger2023] | | [`gg_qcp()`](../reference/gg_qcp.html) | Produces a quantile calibration plot comparing nominal quantile probabilities with empirical quantile coverage. | [@schmidinger2023] | | [`pit()`](../reference/pit.html) | Calculates probability integral transform values from predictive CDF values, predictive means and standard deviations under a normal assumption, or equally weighted predictive samples using their empirical CDF. | [@gneiting2007; @schmidinger2023] | | [`gg_pit()`](../reference/gg_pit.html) | Produces a PIT histogram for assessing the calibration of complete predictive distributions. | [@gneitingraftery2007; @schmidinger2023] | | [`crps()`](../reference/crps.html) | Calculates the continuous ranked probability score, a proper score that evaluates the full predictive distribution. | [@hersbach2000; @gneitingraftery2007] | | [`median_crps()`](../reference/median_crps.html) | Calculates the median case-wise CRPS, providing a robust summary of typical probabilistic prediction performance. | [@gneitingraftery2007] | | [`crps_decomposition()`](../reference/crps_decomposition.html) | Decomposes CRPS into reliability and potential CRPS components when predictive samples are available. | [@hersbach2000; @schmidinger2023] | | [`log_score()`](../reference/log_score.html) | Calculates the logarithmic score from predictive density values evaluated at the observations. | [@gneitingraftery2007] | The appropriate functions depend on the available model output. For example, `picp()`, `coverage_error()`, `interval_width()`, `interval_score()`, and `uncertainty_metrics()` accept explicit bounds, predictive mean and standard deviation under a normal assumption, or equally weighted predictive samples. `qcp()`, `gg_qcp()`, `gg_coverage()`, and `accuracy_plot_metrics()` can also derive their quantiles or intervals directly from either predictive representation. `crps()` and `median_crps()` support both representations. `crps_decomposition()` remains sample-only. `pit()` accepts predictive CDF values, normal predictive means and standard deviations, or predictive samples. `log_score()` requires predictive density values evaluated at the observations. ## 4. Example data We first create a simple situation in which the predictive distributions are correctly calibrated by construction. ```{r} library(modelskill) set.seed(123) n <- 500 # Predictive means pred <- seq(0, 10, length.out = n) # True predictive standard deviation predictive_sd <- rep(1, n) # Independent observations generated from the predictive distributions obs <- stats::rnorm( n, mean = pred, sd = predictive_sd ) ``` Here, observation \(i\) is generated from \[ Y_i \sim N(\mathrm{pred}_i, \sigma_i^2), \] with \(\sigma_i = 1\). Because the predictive model and data-generating process are the same, the uncertainty estimates should be approximately calibrated. Departures from perfect calibration still occur because validation is based on a finite sample. ## 5. Case A: predictive mean and standard deviation A common output from geostatistical models, Bayesian approximations, Gaussian processes, and other statistical models is a predictive mean together with a predictive standard deviation. If a normal predictive distribution is appropriate, prediction intervals, quantiles, CDF values, and predictive densities can all be obtained from these two quantities. ### 5.1 Prediction intervals For a central 95% prediction interval: ```{r} lower95 <- pred + stats::qnorm(0.025) * predictive_sd upper95 <- pred + stats::qnorm(0.975) * predictive_sd ``` A 95% prediction interval means that, under calibration, approximately 95% of independent observations should fall between the corresponding lower and upper bounds. #### 5.1.1 Prediction interval coverage probability The **prediction interval coverage probability (PICP)** is the empirical proportion of observations contained in the interval: \[ \mathrm{PICP}(\tau) = \frac{1}{n} \sum_{i=1}^{n} I(l_i \leq y_i \leq u_i). \] where \(\tau\) is the nominal interval level. ```{r} picp(obs, lower95, upper95) ``` For a 95% prediction interval, a well-calibrated model should return a value close to 0.95. `modelskill` reports PICP on the probability scale from 0 to 1 rather than as a percentage. #### 5.1.2 Coverage error [`coverage_error()`](../reference/coverage_error.html) directly compares empirical and nominal coverage: \[ \mathrm{coverage\ error} = \mathrm{PICP}(\tau) - \tau. \] ```{r} coverage_error( obs, lower95, upper95, level = 0.95 ) ``` Interpretation is straightforward: - **0**: empirical and nominal coverage agree; - **negative**: under-coverage, meaning that observations fall outside the intervals too frequently; - **positive**: over-coverage, meaning that observations fall inside the intervals more frequently than required. Under-coverage often indicates that predictive uncertainty has been underestimated, whereas substantial over-coverage can indicate unnecessarily wide uncertainty estimates. #### 5.1.3 Prediction interval width Calibration alone is not sufficient. A model could achieve high coverage simply by producing extremely wide intervals. [`interval_width()`](../reference/interval_width.html) measures average prediction interval width: \[ \mathrm{PIW}(\tau) = \frac{1}{n} \sum_{i=1}^{n} (u_i-l_i). \] ```{r} interval_width( obs, lower95, upper95 ) ``` PIW has the same units as the response variable. Smaller values mean sharper prediction intervals. Importantly, PIW does not measure calibration and does not depend on where the observations fall. It should therefore always be interpreted together with a coverage diagnostic such as PICP. #### 5.1.4 Interval score The [`interval_score()`](../reference/interval_score.html) combines sharpness and calibration in a single proper score. ```{r} interval_score( obs, lower95, upper95, level = 0.95 ) ``` The score contains the interval width plus penalties when an observation falls below or above the interval. The farther an observation lies outside the interval, the larger the penalty. Lower interval scores are better. Scores should only be compared for the same validation data, response scale, and interval level. #### 5.1.5 Calculate all interval diagnostics together [`uncertainty_metrics()`](../reference/uncertainty_metrics.html) is a convenience wrapper that returns the principal interval diagnostics together: ```{r} uncertainty_metrics( obs, lower = lower95, upper = upper95, level = 0.95 ) # Equivalent direct interface under the normal assumption: uncertainty_metrics(obs, pred = pred, predictive_sd = predictive_sd, level = 0.95) ``` It returns: - `picp`: empirical prediction interval coverage; - `picp_error`: empirical minus nominal coverage; - `interval_width`: average interval width; - `interval_score`: proper interval score. The individual functions remain useful when only one diagnostic is required. ### 5.2 Why calibration and sharpness must be considered together Consider a second uncertainty estimate that uses the same predictive means but standard deviations that are only half as large: ```{r} sd_too_small <- rep(0.5, n) lower95_narrow <- pred + stats::qnorm(0.025) * sd_too_small upper95_narrow <- pred + stats::qnorm(0.975) * sd_too_small uncertainty_metrics( obs, lower = lower95_narrow, upper = upper95_narrow, level = 0.95 ) ``` These intervals are much narrower and therefore appear sharper. However, their coverage should be substantially below 0.95 because the predictive uncertainty has been underestimated. Compare this with the calibrated intervals: ```{r} uncertainty_metrics( obs, lower = lower95, upper = upper95, level = 0.95 ) ``` This illustrates why a smaller interval width is desirable only when calibration remains adequate. ### 5.3 Reliability across multiple interval levels A single PICP assesses one interval level only. It is often more informative to evaluate calibration across many central prediction intervals. [`gg_coverage()`](../reference/gg_coverage.html) constructs this reliability curve directly from predictive means and standard deviations: ```{r} gg_coverage( obs, pred = pred, predictive_sd = predictive_sd ) ``` Nominal interval coverage is shown on the horizontal axis and empirical PICP on the vertical axis. A well-calibrated model should follow the 1:1 line. - Points **below** the line indicate under-coverage and generally underestimated uncertainty. - Points **above** the line indicate over-coverage and generally overly conservative uncertainty. The same plot for the deliberately underestimated predictive standard deviations shows the difference: ```{r} gg_coverage( obs, pred = pred, predictive_sd = sd_too_small ) ``` In geostatistical uncertainty validation this display has traditionally also been called an **accuracy plot** [@goovaerts2001], although **reliability** **plot** is the more general terminology used for probabilistic predictions. #### 5.3.1 Numerical summaries of the reliability plot The reliability or accuracy plot can be interpreted visually, but departures from the ideal 1:1 line can also be summarized numerically. Accuracy plots were introduced for the assessment of local uncertainty by @deutsch1997 and were subsequently used for geostatistical uncertainty evaluation in soil science by @goovaerts2001. The same framework, including numerical summaries of departure from the 1:1 line, was used by @wadoux2018. For a nominal central prediction-interval level \(p\), let \(\mathrm{PICP}(p)\) denote the empirical proportion of validation observations contained in the corresponding prediction intervals. If predictive uncertainty is well calibrated, \[ \mathrm{PICP}(p) \approx p \] over the range of evaluated probabilities. The empirical coverage curve should therefore follow the 1:1 line. [`accuracy_plot_metrics()`](../reference/accuracy_plot_metrics.html) summarizes the magnitude and direction of departures from this line: ```{r} accuracy_plot_metrics( obs, pred = pred, predictive_sd = predictive_sd ) ``` For the deliberately underestimated predictive uncertainty: ```{r} accuracy_plot_metrics( obs, pred = pred, predictive_sd = sd_too_small ) ``` The principal summary is `absolute_deviation`, which corresponds to the total area between the empirical coverage curve and the ideal 1:1 line: \[ A = \int_0^1 \left| \mathrm{PICP}(p)-p \right| \,dp. \] A value of \(A=0\) indicates perfect calibration. Increasing values indicate greater overall disagreement between nominal and empirical coverage across the evaluated interval levels. This measure summarizes the magnitude of miscalibration but does not, by itself, indicate whether predictive uncertainty is predominantly overestimated or underestimated. The calculation integrates the piecewise-linear coverage curve exactly, splitting segments where they cross the 1:1 line. The endpoints `(0, 0)` and `(1, 1)` are assumed rather than measured, so the area depends on the supplied levels and interpolation. With interval lists, `gg_coverage()` and `accuracy_plot_metrics()` use only cases complete across all supplied levels. The total deviation can therefore be separated into the area above the 1:1 line, \[ A_{\mathrm{over}} = \int_0^1 \max\left\{ \mathrm{PICP}(p)-p,0 \right\} \,dp, \] and the area below the line, \[ A_{\mathrm{under}} = \int_0^1 \max\left\{ p-\mathrm{PICP}(p),0 \right\} \,dp. \] These quantities are returned as: - `absolute_deviation`: the total area \(A\) between the empirical coverage curve and the 1:1 line. Smaller values indicate better overall calibration, with zero being ideal; - `over_uncertainty`: the area \(A_{\mathrm{over}}\) above the 1:1 line. In this region empirical coverage is greater than nominal coverage, indicating over-coverage and, in general, predictive uncertainty that is too large; - `under_uncertainty`: the area \(A_{\mathrm{under}}\) below the 1:1 line. In this region empirical coverage is smaller than nominal coverage, indicating under-coverage and, in general, predictive uncertainty that is too small; - `over_percent`: the percentage of the total absolute deviation occurring above the 1:1 line; - `under_percent`: the percentage of the total absolute deviation occurring below the 1:1 line. The last two quantities correspond to the relative contributions of overestimation and underestimation to the total calibration error: \[ P_{\mathrm{over}} = \frac{A_{\mathrm{over}}}{A}, \qquad P_{\mathrm{under}} = \frac{A_{\mathrm{under}}}{A}. \] `accuracy_plot_metrics()` reports these quantities as percentages. When `absolute_deviation` is greater than zero, \[ \mathrm{over\_percent} + \mathrm{under\_percent} = 100. \] These percentages should not be interpreted as percentages of observations. They describe how the total *area of miscalibration* is partitioned above and below the 1:1 line. For example, a large `under_percent` indicates that most of the departure from ideal calibration results from empirical coverage being lower than nominal coverage. The prediction intervals are therefore generally too narrow, and predictive uncertainty is underestimated. Conversely, a large `over_percent` indicates that most of the departure results from empirical coverage exceeding nominal coverage, which is generally associated with prediction intervals that are too wide and predictive uncertainty that is overestimated. These summaries quantify **calibration**, not **sharpness**. A predictive model may achieve good coverage while producing unnecessarily wide prediction intervals. Calibration summaries should therefore be interpreted together with measures of interval width or proper scoring rules when comparing probabilistic predictions. The area summaries are most informative when the reliability curve is evaluated over a sufficiently dense range of nominal interval levels. With only one or a few interval levels, a single coverage error is usually easier to interpret than an integrated area. The interpretation above follows the accuracy-plot framework of [@deutsch1997; @goovaerts2001], with the absolute-deviation and directional summaries described and applied in @wadoux2018. ### 5.4 Why PICP alone is not enough PICP measures whether observations fall inside an interval, but it does not describe **where** the observations that fall outside the interval occur. This means that PICP can hide a **one-sided bias**. For example, for a central 90% prediction interval we expect approximately 5% of observations below the lower boundary and 5% above the upper boundary. A model could instead have approximately 10% below the lower boundary and almost none above the upper boundary while still obtaining approximately 90% total coverage. @schmidinger2023 showed that this limitation can occur in practice and recommended complementing PICP with quantile-based calibration or PIT diagnostics. We can reproduce the idea with a deliberately shifted predictive distribution. The predictive mean is shifted upward by 0.5 response units. Its predictive standard deviation is also increased so that central 90% coverage can remain close to its nominal value. ```{r} biased_pred <- pred + 0.5 biased_sd <- rep(1.118, n) lower90_biased <- biased_pred + stats::qnorm(0.05) * biased_sd upper90_biased <- biased_pred + stats::qnorm(0.95) * biased_sd uncertainty_metrics( obs, lower = lower90_biased, upper = upper90_biased, level = 0.90 ) ``` The total PICP may look acceptable even though the predictive distribution is systematically displaced. Individual quantiles reveal this problem more clearly. ### 5.5 Quantile coverage probability Prediction interval coverage probability evaluates whether observations fall inside prediction intervals, but it does not distinguish between the lower and upper tails. Quantile coverage probability (QCP) provides a complementary calibration diagnostic by evaluating individual predictive quantiles. For a correctly calibrated predictive quantile at probability \(p\), approximately a fraction \(p\) of observations should fall below that predicted quantile. The **quantile coverage probability (QCP)** is \[ \mathrm{QCP}(p) = \frac{1}{n} \sum_{i=1}^{n} I(y_i \leq q_{i,p}), \] where \(q_{i,p}\) is the predicted \(p\)-quantile for observation \(i\). For a calibrated predictive distribution, - a predicted 0.05 quantile should have QCP close to 0.05; - a predicted 0.50 quantile should have QCP close to 0.50; - a predicted 0.95 quantile should have QCP close to 0.95. It is generally more informative to evaluate QCP across several quantile levels rather than at only a few selected probabilities. We therefore evaluate quantiles from 0.05 to 0.95 at increments of 0.05. ```{r} q_levels <- seq(0.05, 0.95, by = 0.05) qhat <- vapply( q_levels, function(p) { pred + stats::qnorm(p) * predictive_sd }, numeric(n) ) qcp( obs, quantiles = qhat, levels = q_levels ) ``` For a well-calibrated predictive distribution, the empirical QCP values should be close to their corresponding nominal quantile probabilities. [`gg_qcp()`](../reference/gg_qcp.html) displays this relationship graphically: ```{r} gg_qcp( obs, quantiles = qhat, levels = q_levels ) ``` The horizontal axis gives the nominal predictive quantile probability and the vertical axis gives its empirical QCP. Points close to the 1:1 line indicate well-calibrated predictive quantiles. When the predictive distribution is represented by a predictive mean and standard deviation and a normal distribution is appropriate, `qcp()` and `gg_qcp()` can also generate these quantiles directly: ```{r} gg_qcp( obs, pred = pred, predictive_sd = predictive_sd ) ``` This differs from [`gg_coverage()`](../reference/gg_coverage.html). The reliability or accuracy plot produced by `gg_coverage()` evaluates the **joint coverage of central prediction intervals**, whereas `gg_qcp()` evaluates **individual predictive quantiles**. For example, a central 90% prediction interval jointly evaluates its 0.05 and 0.95 quantile bounds. QCP instead evaluates those two quantiles separately. This distinction is important because satisfactory central interval coverage does not necessarily imply that both tails are calibrated. A prediction interval may contain approximately the expected proportion of observations even when too many observations fall below its lower bound and too few fall above its upper bound. Now examine the deliberately biased predictive distribution: ```{r} qhat_biased <- vapply( q_levels, function(p) { biased_pred + stats::qnorm(p) * biased_sd }, numeric(n) ) qcp( obs, quantiles = qhat_biased, levels = q_levels ) gg_qcp( obs, quantiles = qhat_biased, levels = q_levels ) ``` The same plot can be generated directly from its predictive mean and standard deviation: ```{r} gg_qcp( obs, pred = biased_pred, predictive_sd = biased_sd ) ``` Departures from the 1:1 line indicate quantile miscalibration. QCP above its nominal probability means that observations fall below the predicted quantile more frequently than expected, so the predicted quantile tends to be too high. QCP below its nominal probability means that observations fall below the predicted quantile less frequently than expected, so the predicted quantile tends to be too low. QCP is therefore particularly useful for identifying asymmetric or one-sided miscalibration that may remain hidden when central prediction-interval coverage is considered alone. ### 5.6 Probability integral transform The **probability integral transform (PIT)** evaluates calibration of the complete predictive distribution. For observation \(y_i\) and its predictive cumulative distribution function \(F_i\), the PIT value is \[ u_i = F_i(y_i). \] For calibrated continuous predictive distributions, PIT values evaluated across independent validation observations should be approximately uniformly distributed between 0 and 1 [@gneiting2007; @schmidinger2023]. There is therefore no single ideal PIT value for an individual observation. Calibration is assessed from the distribution of PIT values over the validation set. When the predictive distribution is represented by a predictive mean and standard deviation and a normal distribution is appropriate, [`pit()`](../reference/pit.html) can calculate the PIT values directly: ```{r} pit_normal <- pit( obs = obs, pred = pred, predictive_sd = predictive_sd ) gg_pit(pit_normal) ``` [`gg_pit()`](../reference/gg_pit.html) displays the resulting PIT values as a histogram. The histogram is shown on a density scale, and the dashed horizontal line at density 1 represents the expected density under a uniform distribution. For a well-calibrated predictive distribution, the histogram should therefore be approximately flat around this reference line. Departures from uniformity can provide information about the form of miscalibration: - a **U-shaped** histogram, with excess PIT values near 0 and 1, is commonly associated with predictive distributions that are too narrow (underdispersed); - a **hump-shaped** histogram, with excess PIT values near 0.5, is commonly associated with predictive distributions that are too wide (overdispersed); - an excess of PIT values near **0** can occur when predictions are systematically too high relative to the observations; - an excess of PIT values near **1** can occur when predictions are systematically too low relative to the observations. These patterns are diagnostic rather than unique: different forms of misspecification can produce similar PIT histograms. Sampling variability can also create apparent departures from uniformity, particularly for small validation datasets. For example, consider the predictive standard deviations that were deliberately made too small: ```{r} pit_narrow <- pit( obs = obs, pred = pred, predictive_sd = sd_too_small ) gg_pit(pit_narrow) ``` Because these predictive distributions are too narrow, the observations occur in their tails more frequently than expected, producing relatively more PIT values near 0 and 1. The deliberately biased predictive distribution can be assessed in the same way: ```{r} pit_biased <- pit( obs = obs, pred = biased_pred, predictive_sd = biased_sd ) gg_pit(pit_biased) ``` A directional bias tends to shift PIT values towards one side of the unit interval rather than producing a symmetric departure from uniformity. `pit()` can also be used when the predictive CDF has been calculated externally. This allows PIT values to be obtained for continuous predictive distributions other than the normal distribution: ```{r} cdf_at_obs <- stats::pnorm( obs, mean = pred, sd = predictive_sd ) pit_from_cdf <- pit( cdf_at_obs = cdf_at_obs ) gg_pit(pit_from_cdf) ``` PIT and QCP are closely related because both evaluate calibration across the predictive distribution, but they summarize it differently. QCP evaluates empirical coverage at specified predictive quantiles, whereas PIT evaluates the position of each observation within its complete predictive distribution. Together with prediction-interval coverage, these diagnostics can reveal distributional or asymmetric calibration problems that may not be apparent from central prediction intervals alone [@schmidinger2023]. The usual uniformity interpretation of PIT applies to **continuous** predictive distributions. For discrete distributions or finite predictive ensembles, ordinary PIT values are themselves discrete and randomized PIT or rank-based diagnostics are more appropriate. ### 5.7 Proper scoring rules Calibration diagnostics such as PICP, QCP, and PIT ask whether a predictive distribution is statistically reliable. When several probabilistic models must be compared, it is also useful to have a single numerical criterion that evaluates the predictive distribution as a whole, accounting for both calibration and sharpness. **Proper scoring rules** are designed for this purpose. A proper scoring rule encourages honest probabilistic predictions: its expected value is optimized when the reported predictive distribution is the true predictive distribution [@gneitingraftery2007]. #### 5.7.1 Continuous ranked probability score The **continuous ranked probability score (CRPS)** compares the complete predictive CDF with the realised observation. For a normal predictive distribution, [`crps()`](../reference/crps.html) can be supplied with the predictive mean and standard deviation: ```{r} crps( obs, pred = pred, predictive_sd = predictive_sd ) ``` CRPS has the same units as the response variable. Zero is ideal and lower values are better. Compare the calibrated and underestimated uncertainty models: ```{r} crps( obs, pred = pred, predictive_sd = predictive_sd ) crps( obs, pred = pred, predictive_sd = sd_too_small ) ``` CRPS penalizes predictive distributions that are poorly centred on the observation or unnecessarily dispersed. #### 5.7.2 Median CRPS Mean CRPS can be influenced by a small number of very poor predictive distributions. [`median_crps()`](../reference/median_crps.html) summarizes the typical case more robustly: ```{r} median_crps( obs, pred = pred, predictive_sd = predictive_sd ) ``` Mean and median CRPS answer slightly different questions. Mean CRPS is usually preferred for overall probabilistic model comparison, whereas median CRPS can help determine whether the mean score is dominated by a few extreme cases. Median aggregation is a descriptive summary, not itself a proper scoring rule. #### 5.7.3 Logarithmic score The [`log_score()`](../reference/log_score.html) is another proper score. It uses the predictive density assigned to the observed value. The mean logarithmic score is \[ \mathrm{Log\ score} = -\frac{1}{n} \sum_{i=1}^{n} \log f_i(y_i). \] For the normal predictive distributions: ```{r} density_at_obs <- stats::dnorm( obs, mean = pred, sd = predictive_sd ) log_score( obs, density_at_obs ) ``` Lower values are better. The logarithmic score strongly penalizes observations that were assigned very low predictive density. It can therefore be particularly sensitive to failures in the tails of the predictive distribution. ## 6. Case B: predictive distributions represented by samples Some probabilistic models represent the predictive distribution for each validation case by a set of sampled possible values, rather than by parameters such as a predictive mean and standard deviation. For each observation, these samples provide an empirical representation of the predictive distribution and can be used directly to evaluate predictive uncertainty. Typical examples are: - posterior predictive draws from Bayesian models; - simulation-based models; - ensemble predictions; - bootstrap predictive distributions; - some machine-learning methods like quantile regression forests; - Monte Carlo uncertainty propagation. `modelskill` represents this type of prediction as a matrix with: - one **row** per validation observation; - one **column** per predictive draw. We generate 200 predictive draws for each observation: ```{r} set.seed(456) n_draws <- 200 predictive_samples <- sapply( seq_len(n_draws), function(j) { stats::rnorm( n, mean = pred, sd = predictive_sd ) } ) dim(predictive_samples) ``` Each row of `predictive_samples` now represents an empirical approximation to the predictive distribution for one observation. #### 6.1 Prediction intervals from predictive samples Prediction intervals are generated internally from empirical equal-tailed quantiles using `stats::quantile(type = 7)`. For a 95% central interval: ```{r} uncertainty_metrics( obs, distribution = predictive_samples, level = 0.95 ) # Individual interval statistics accept the same input. picp(obs, distribution = predictive_samples, level = 0.95) interval_width(obs, distribution = predictive_samples, level = 0.95) interval_score(obs, distribution = predictive_samples, level = 0.95) ``` A missing observation or any missing predictive draw removes that entire row when `na.rm = TRUE`; individual missing draws are not silently dropped. Standalone `interval_width()` remains independent of missing observations. The interpretation of PICP, interval width, coverage error, and interval score is exactly the same as when the intervals were derived from a predictive mean and standard deviation. The validation tools depend on the resulting predictive uncertainty, not on the algorithm used to generate it. ### 6.2 Reliability across interval levels from predictive samples Pass the predictive samples directly and choose the nominal interval levels. There is no need to construct lower and upper interval lists: ```{r} interval_levels <- seq(0.10, 0.90, by = 0.10) gg_coverage( obs, distribution = predictive_samples, levels = interval_levels ) ``` and to `accuracy_plot_metrics()`: ```{r} accuracy_plot_metrics( obs, distribution = predictive_samples, levels = interval_levels ) ``` If `levels` is omitted, both functions evaluate levels from 1% to 99%. The existing explicit interval-list interface remains available when a model only provides selected intervals. ### 6.3 Quantile calibration from predictive samples Empirical quantiles are extracted internally from each row of predictive samples. ```{r} qcp( obs, distribution = predictive_samples, levels = q_levels ) ``` Plot the calibration: ```{r} gg_qcp( obs, distribution = predictive_samples, levels = q_levels ) ``` This approach does not require any parametric assumption about the shape of the predictive distribution. ### 6.4 PIT from predictive samples For an analytic distribution, PIT is calculated by evaluating the predictive CDF at the observation. With predictive samples, the predictive CDF can instead be approximated by the fraction of predictive draws less than or equal to the observation: ```{r} pit_samples <- pit(obs = obs, distribution = predictive_samples) gg_pit(pit_samples) ``` For calibrated continuous predictive distributions, PIT values are uniform. Here the CDF is estimated from a finite ensemble: empirical PIT values lie on a discrete grid and are not exactly continuous-uniform, even for calibrated draws. Interpret the histogram with this finite-ensemble limitation in mind. The difference is only how \(F_i(y_i)\) was obtained: - with an analytic distribution, evaluate its CDF directly; - with predictive samples, approximate the CDF empirically. ### 6.5 CRPS from predictive samples `crps()` accepts the predictive sample matrix directly: ```{r} crps( obs, distribution = predictive_samples ) ``` No normality assumption is required. This is useful when predictive distributions are asymmetric, multimodal, or otherwise poorly summarized by a mean and standard deviation. The median case-wise CRPS is similarly available: ```{r} median_crps( obs, distribution = predictive_samples ) ``` ### 6.6 CRPS reliability decomposition When equally weighted predictive samples are available, [`crps_decomposition()`](../reference/crps_decomposition.html) decomposes CRPS into a reliability component and potential CRPS: ```{r} crps_decomposition( obs, distribution = predictive_samples ) ``` The output contains: - `crps`: the total CRPS; - `reliability`: the RELI component; - `potential_crps`: the remaining component after removing reliability error. The reliability component is non-negative and has an ideal value of zero. It provides a numerical summary of distributional calibration. @schmidinger2023 showed that RELI summarizes patterns also visible in PICP, QCP, and PIT diagnostics, whereas the total CRPS additionally reflects sharpness and predictive performance. `crps_decomposition()` in `modelskill` is intended for equally weighted predictive samples. It is therefore not called directly with a predictive mean and standard deviation. ### 6.7 What about the logarithmic score with predictive samples? `log_score()` requires the predictive density evaluated at each observation. If a model provides an analytic density, calculate these density values and supply them directly. For example, in the normal case: ```{r} density_at_obs <- stats::dnorm( obs, mean = pred, sd = predictive_sd ) log_score(obs, density_at_obs) ``` Predictive samples alone do not uniquely define a smooth probability density. A density-estimation method would first be required. `modelskill` therefore does not automatically estimate a density from predictive samples before calculating the logarithmic score. ## 7. Comparing the two input formats The two examples above represent the same conceptual predictive uncertainty in different ways. | Task | Mean + SD | Predictive samples | | ---- | --------- | ------------------ | | `picp()`, `coverage_error()`, `interval_width()`, `interval_score()` | Directly (`pred`, `predictive_sd`, `level`) | Directly (`distribution`, `level`) | | `uncertainty_metrics()` | Directly (`pred`, `predictive_sd`, `level`) | Directly (`distribution`, `level`) | | `gg_coverage()` / `accuracy_plot_metrics()` | Directly (`pred`, `predictive_sd`, `levels`) | Directly (`distribution`, `levels`) | | `qcp()` / `gg_qcp()` | Directly (`pred`, `predictive_sd`, `levels`) | Directly (`distribution`, `levels`) | | `pit()` | Directly (`pred`, `predictive_sd`) | Directly (`distribution`), using the empirical CDF | | `gg_pit()` | Supply the values returned by `pit()` | Supply the values returned by `pit()` | | `crps()` / `median_crps()` | Directly (`pred`, `predictive_sd`) | Directly (`distribution`) | | `crps_decomposition()` | No: requires ensemble members | Directly (`distribution`) | | `log_score()` | Supply `density_at_obs`, e.g. from `dnorm()` | No automatic density estimation; supply `density_at_obs` from an explicitly chosen density model | The appropriate representation depends on what the prediction model provides. There is generally no reason to reduce a rich predictive distribution to a mean and standard deviation solely for validation if predictive samples or quantiles are already available. ## 8. A practical workflow There is no single statistic that completely evaluates predictive uncertainty. Different diagnostics answer different questions. ### 8.1 If you only have prediction intervals Start with: ```r uncertainty_metrics(...) ``` and interpret PICP and interval width together. If intervals are available at several nominal levels, also use: ```r gg_coverage(...) accuracy_plot_metrics(...) ``` ### 8.2 If you have predicted quantiles Use: ```r qcp(...) gg_qcp(...) ``` QCP is particularly useful because it can expose directional quantile bias that may be hidden by central interval coverage. ### 8.3 If you have a predictive mean and standard deviation When a normal predictive distribution is scientifically appropriate, you can evaluate nearly the complete distribution using: ```r gg_coverage(...) pit(...) gg_pit(...) crps(...) median_crps(...) log_score(...) ``` Prediction intervals and quantiles can also be generated from the normal distribution as shown above. ### 8.4 If you have predictive samples Retain them rather than reducing them unnecessarily to a mean and standard deviation. Pass them directly to the calculation functions: ```r # Intervals uncertainty_metrics(...) # Quantiles qcp(...) gg_qcp(...) # Empirical CDF values pit(...) gg_pit(...) # Proper scores crps(...) median_crps(...) crps_decomposition(...) ``` This preserves asymmetry and other features of the predictive distribution. ## 9. Recommended interpretation A practical uncertainty-validation analysis should generally combine several complementary diagnostics. 1. **Check calibration.** Use PICP, QCP, PIT, or preferably more than one of these diagnostics. 2. **Check sharpness.** Examine prediction interval width, but only after verifying calibration. 3. **Inspect the whole distribution when possible.** QCP and PIT can reveal problems that a single central PICP cannot. 4. **Use proper scores when comparing models.** CRPS and interval score combine calibration and sharpness into numerical criteria suitable for relative model comparison. 5. **Do not select a model from one diagnostic alone.** Different metrics emphasize different aspects of probabilistic prediction quality and can therefore lead to different model rankings. @schmidinger2023 demonstrated this explicitly for probabilistic digital soil mapping: PICP could hide one-sided bias, whereas QCP and PIT revealed it, and scoring rules provided additional information when comparing competing probabilistic models.