
Joint (Multivariate) Calibration Diagnostic for a Predictive Ensemble
Source:R/joint-coverage.R
joint_coverage_test.RdTests whether a predictive ensemble is calibrated jointly, including its
dependence structure, against held-out observations. Where coverage_test()
assesses each output dimension separately (marginal calibration), this
function builds a multivariate rank histogram: each observation is reduced,
together with the ensemble, to one multivariate rank through a pre-rank
function, and the histogram of those ranks is tested for uniformity. An
ensemble with correct margins but a mis-specified correlation – which
coverage_test() passes – is caught here.
Usage
joint_coverage_test(x, ...)
# Default S3 method
joint_coverage_test(
x,
observed,
prerank = c("band_depth", "average"),
levels = c(0.5, 0.8, 0.9),
n_bins = 10L,
alpha = 0.05,
seed = NULL,
...
)
# S3 method for class 'pesto_ensemble'
joint_coverage_test(x, observed = NULL, ...)
# S3 method for class 'pesto_ensemble_manifest'
joint_coverage_test(x, observed, outputs = NULL, ...)Arguments
- x
Numeric matrix
n_draws x dof predictive draws, apesto_ensemble(seepesto_ensemble()), or apesto_ensemble_manifest.- ...
Additional arguments passed between methods (currently unused).
- observed
Numeric matrix
n_obs x dof held-out observations. Whenxis apesto_ensemblecarrying anobservedslot, may beNULL.- prerank
Character. Pre-rank function:
"band_depth"(default, dependence-sensitive) or"average"(familiar dispersion reading).- levels
Numeric vector in
(0, 1). Central predictive-interval levels at which to report empirical coverage. Defaultc(0.5, 0.8, 0.9).- n_bins
Integer. Number of equal-width bins for the rank-histogram uniformity test. Default
10.- alpha
Numeric in
(0, 1). Significance level for the calibration verdict. Default0.05.- seed
Integer or
NULL. Random seed: multivariate ranks break pre-rank ties at random, so a non-NULLseed makes the result reproducible.- outputs
Optional character vector of manifest output columns to test (the
real_namecolumn is always excluded). Defaults to all numeric output columns. Used only for thepesto_ensemble_manifestmethod.
Value
An object of class "joint_coverage_test" with components:
- prerank
The pre-rank function used.
- coverage
Data frame of
nominalvsempiricalcentral-rank-band coverage at each requested level.- dispersion_ratio
Var(u) / (1/12)of the normalised multivariate ranksu; above one under-dispersed, below one over-dispersed (the primary signal forprerank = "average").- mean_rank
Mean normalised rank (
0.5under calibration; the primary direction signal forprerank = "band_depth").- calibration
List with the rank-histogram chi-squared
statistic,p_value, andn_bins.- verdict
Character: the joint-calibration classification.
- reject
Logical:
calibration$p_value <= alpha.- ranks
Integer multivariate ranks, one per observation.
- n_draws, n_obs, dimension, levels, alpha
Inputs / sizes.
- pesto_metadata
Provenance carried from a
pesto_ensemble_manifest(includingfidelity), orNULL.
Details
The pre-rank function determines what miscalibration is visible:
"band_depth"(default)Ranks points by multivariate centrality (band depth; Thorarinsdottir et al. 2016). Sensitive to dependence / correlation miscalibration that marginal and average-rank methods miss. The reading is a slope: a mean rank below
0.5means observations fall outside the ensemble cloud (jointly under-dispersed); above0.5means they sit too centrally (over-dispersed); a non-uniform histogram with a central mean signals a dependence error that is not a pure dispersion shift."average"Ranks points by the sum of their per-dimension ranks (Gneiting et al. 2008). Gives the familiar rank-histogram reading – a U-shape and a dispersion ratio above one mean under-dispersion, an inverted-U and a ratio below one mean over-dispersion – but is weaker against correlation-only errors.
Under calibration the multivariate rank is uniform on {1, ..., n_draws + 1}
for either pre-rank, so the chi-squared uniformity test, the dispersion
ratio, and the coverage table are all referenced against the uniform. With
few held-out observations the uniformity test has low power; read the
dispersion and mean-rank summaries alongside it. A joint test needs at least
two output dimensions; for a single output use coverage_test().
References
Gneiting, T., Stanberry, L. I., Grimit, E. P., Held, L., & Johnson, N. A. (2008). Assessing probabilistic forecasts of multivariate quantities, with an application to ensemble predictions of surface winds. TEST, 17(2), 211-235.
Thorarinsdottir, T. L., Scheuerer, M., & Heinz, C. (2016). Assessing the calibration of high-dimensional ensemble forecasts using rank histograms. Journal of Computational and Graphical Statistics, 25(1), 105-122.
See also
coverage_test(), mmd_ppc(), concordance_test()
Other goodness-of-fit tests:
calibration_suite(),
concordance_test(),
concordance_test_nystrom(),
coverage_test(),
gaussian_score(),
ksd_test(),
ksd_test_nystrom(),
numeric_score()
Author
Max Moldovan, max.moldovan@adelaide.edu.au
Examples
set.seed(1)
chol2 <- chol(matrix(c(1, 0.9, 0.9, 1), 2L))
# Correctly correlated ensemble: calibrated jointly
obs <- matrix(stats::rnorm(120L), ncol = 2L) %*% chol2
ens_ok <- matrix(stats::rnorm(4000L), ncol = 2L) %*% chol2
joint_coverage_test(ens_ok, obs, seed = 1L)
#>
#> Joint (multivariate) calibration diagnostic
#>
#> Ensemble: 2000 draws x 2 dims; 60 held-out obs
#> Pre-rank: band_depth (dependence-sensitive)
#> Coverage: 50%->53% 80%->80% 90%->88% (nominal -> empirical rank band)
#> Mean rank: 0.581 (0.5 = calibrated; <0.5 obs outlying, >0.5 obs central)
#> Dispersion: ratio = 0.883 (Var(rank)/(1/12))
#> Calibration: chi2 = 8, p = 0.5341 (rank histogram, 10 bins)
#> Verdict: calibrated (multivariate ranks consistent with uniform)
#>
# Right margins, wrong dependence: ensemble independent, obs correlated.
# coverage_test() passes; joint_coverage_test() catches it.
ens_indep <- matrix(stats::rnorm(4000L), ncol = 2L)
joint_coverage_test(ens_indep, obs, seed = 1L)
#>
#> Joint (multivariate) calibration diagnostic
#>
#> Ensemble: 2000 draws x 2 dims; 60 held-out obs
#> Pre-rank: band_depth (dependence-sensitive)
#> Coverage: 50%->37% 80%->62% 90%->77% (nominal -> empirical rank band)
#> Mean rank: 0.622 (0.5 = calibrated; <0.5 obs outlying, >0.5 obs central)
#> Dispersion: ratio = 1.225 (Var(rank)/(1/12))
#> Calibration: chi2 = 25, p = 0.0030 (rank histogram, 10 bins)
#> Verdict: REJECT -- jointly over-dispersed (observations too central)
#>