ForecastComparison#
- class cultivars.forecast.comparison.ForecastComparison(losses_a, losses_b)[source]
Bases:
objectTest a loss differential between two forecasters.
Takes two aligned loss series, one value per evaluation origin, and answers the unconditional question – is the average of \(d_t = L_{A,t} - L_{B,t}\) distinguishable from zero, with a variance that respects the serial correlation multi-step errors carry – twice, as Diebold-Mariano and with the Harvey-Leybourne-Newbold correction, and the conditional question once, as Giacomini-White on the default instruments. The losses can be anything negatively oriented: squared errors, CRPS, log scores, pinball losses, so long as both series were produced by the same loss on the same origins.
- Parameters:
- Variables:
_losses_a – The validated
(T,)first loss series._losses_b – The validated
(T,)second loss series.
- Raises:
DimensionError – If the series’ shapes disagree.
SpecificationError – If the window is too short, or the series are numerically identical and there is no differential to test.
NumericalError – If the losses are not finite.
Note
Producing the loss series is deliberately the caller’s job: the rolling-origin loop belongs in driver code or in
Backtest, whose record’slosses()gives exactly the aligned series this class takes, because conflating model selection with model evaluation inside a test is how look-ahead bias gets laundered. Fewer than eight origins are refused: a differential’s long-run variance on so short a window has neither power nor reliable size.See also
ForecastComparisonResult– the recordcompute()returns.giacomini_white()– the conditional test with an open instrument set.clark_west()– for nested forecasts.encompassing()– whether one forecast already contains the other’s information.
References
Diebold, F. X., & Mariano, R. S. (1995). Comparing predictive accuracy. Journal of Business & Economic Statistics, 13(3), 253-263.
Harvey, D., Leybourne, S., & Newbold, P. (1997). Testing the equality of prediction mean squared errors. International Journal of Forecasting, 13(2), 281-291.
Example
Synthetic loss series, then the squared-loss columns of two VAR backtests on one schedule:
>>> import numpy as np >>> rng = np.random.default_rng(0) >>> shared = rng.standard_normal(120) ** 2 >>> a = shared + 0.05 * rng.standard_normal(120) >>> b = shared + 0.4 + 0.05 * rng.standard_normal(120) >>> verdict = ForecastComparison(a, b).compute() >>> bool(verdict.mean_differential < 0.0) True >>> bool(verdict.hln_pvalue < 0.01) True >>> from cultivars.forecast.backtest import Backtest >>> from cultivars.multivariate.reduced_form.vector_autoregression import VAR >>> y = np.random.default_rng(1).standard_normal((160, 2)) >>> one = Backtest(y, lambda w: VAR(w, order=1).fit(), horizons=2, start=100).run() >>> two = Backtest(y, lambda w: VAR(w, order=2).fit(), horizons=2, start=100).run() >>> first, second = one.losses(horizon=2, name="y1"), two.losses(horizon=2, name="y1") >>> ForecastComparison(first, second).compute(horizon=2).nobs 59