encompassing#
- cultivars.forecast.comparison.encompassing(realized, forecast_a, forecast_b, *, horizon=1)[source]#
Test whether forecast A encompasses forecast B (Harvey, Leybourne & Newbold, 1998).
A encompasses B when the optimal combination of the two, \((1 - \lambda) f_A + \lambda f_B\), puts no weight on B, so combining them would not help. The test asks whether
\[d_t = e_{A,t}\,(e_{A,t} - e_{B,t})\]has a positive mean, one-sided, with the Diebold-Mariano long-run variance and the Harvey-Leybourne-Newbold correction; a rejection says B carries information A lacks, and the reported weight is the share \(\lambda\) B would get in a least-squares combination. Run it both ways to learn whether either forecast is redundant.
- Parameters:
- Return type:
- Returns:
The
EncompassingTest.- Raises:
DimensionError – If the series do not align.
SpecificationError – If there are too few origins, the horizon is unusable, or the two forecasts are identical.
NumericalError – If a series is not finite.
Note
Encompassing is not the same question as accuracy. A worse forecast can still carry information the better one lacks, in which case neither encompasses the other and a combination beats both; and the better forecast can encompass the worse one, in which case the comparison is settled and combining is pointless. The two directions together, with a
ForecastComparison, are the full reading.See also
EncompassingTest– the record, with the weight.ForecastComparison– whether the losses differ at all.stacking()– combination weights for a pool of density forecasters.
References
Harvey, D. I., Leybourne, S. J., & Newbold, P. (1998). Tests for forecast encompassing. Journal of Business & Economic Statistics, 16(2), 254-259.
Example
Two predictors that each explain part of the outcome: the one missing
zdoes not encompass the one that has it, and the one that has both encompasses the one that lacksz:>>> import numpy as np >>> rng = np.random.default_rng(0) >>> x, z = rng.standard_normal(200), rng.standard_normal(200) >>> y = x + z + 0.5 * rng.standard_normal(200) >>> forward = encompassing(y, x, x + z) >>> bool(forward.pvalue < 0.01), bool(abs(forward.weight - 1.0) < 0.1) # x lacks z (True, True) >>> reverse = encompassing(y, x + z, x) >>> bool(reverse.pvalue > 0.05), bool(abs(reverse.weight) < 0.1) # x + z has it (True, True) >>> encompassing(y, x, x) Traceback (most recent call last): ... cultivars.exceptions.SpecificationError: the two forecasts are numerically identical; ...