Forecast Evaluation and Combinations

Module 7 · Scoring, testing, and averaging forecasts

Gary Cornwall

Econ 6376 · The George Washington University

Module 6 recap: a forecast is a point, an interval and a density

Pointỹt+h∣t=𝔼[yt+h∣ℱt]\tilde y_{t+h\mid t}=\mathbb{E}\!\left[y_{t+h}\mid\mathcal{F}_t\right]the headline number
Intervalỹt+h∣t±ch\tilde y_{t+h\mid t}\pm c_hwith a stated coverage
Densityf(yt+h∣ℱt)f(y_{t+h}\mid\mathcal{F}_t)the whole distribution; the fan chart draws it
Uncertainty grows with the horizon.

Var(et+h∣t)=σ2∑i=0h−1ψi2\text{Var(}e_{t+h\mid t}\text{)}=\sigma^2\sum_{i=0}^{h-1}\psi_i^2

h=1h=1: σ2\sigma^2. Stationary: →γ0\to\gamma_0. Unit root: keeps growing.

Module 6 recap: the loss picks the target

Under MSE, the best point forecast is theconditional mean
Under MAEconditional median
Under asymmetric linear loss with weight α\alphathe α\alpha-quantile
Huber and MAPE are losses too; this course scores with them rather than deriving a target. MAPE is scale-free but undefined at yt=0y_t=0.
Choose the loss before you see the results; compare within a loss, never between: same loss, same yy, same test observations NN.
Today’s DM test takes a loss as an input. Which one, and who chooses?

Module 6 recap: train first, then test, in time order

Train: estimate here, onceUNRATE 1960-01 … 2017-12
Test24 months
1960origin: December 2017 → 2019
Never a random split. Shuffling leaks the future into training: Biff with the sports almanac.

Module 6: one origin, many horizons. One fit, one path, h=1,…,24h=1,\ldots,24.

Module 7: many origins, one horizon. Fixed coefficients, rolling data.

Today: many origins, one horizon. Same parameters, the information set rolls.

Why Choose Only One?

Debrief: the crowd average is a forecast combination

  • Your guess of the release date is a forecast based on a mental model.
  • Each of your models has partially overlapping information sets: you can exploit this!
  • Each of you made a forecast ỹ(m)\tilde y^{(m)} of the release year, m=1,…,Mm=1,\ldots,M. The crowd mean is

ỹ(c)=1M∑m=1Mỹ(m)\tilde y^{(c)}=\frac{1}{M}\sum_{m=1}^{M}\tilde y^{(m)}

the simple average: every weight wm=1/Mw_m=1/M, nothing estimated.

The SPF’s published forecast is the median across ~37 professional forecasters: forecast combination as standard practice.

Where we are: nothing new on the mixing board

yt=α+δt+∑j=1pϕjyt−j+∑l=1qθlϵt−l+ϵty_t=\alpha+\delta t+\sum_{j=1}^{p}\phi_j y_{t-j}+\sum_{l=1}^{q}\theta_l\epsilon_{t-l}+\epsilon_t

Every slider is on, seasonal block included. Module 6 projected one fitted equation forward; Module 7 puts several on the table and referees between them.

Term L4 L5 L6 L7
α\alpha, δt\delta t On On On On
ϕjyt−j\phi_j y_{t-j} (all pp) On On On On
θlϵt−l\theta_l\epsilon_{t-l} (all qq) On On On On
Seasonal block (P,D,Q)s(P,D,Q)_s Off On On On
What we do with it Select Diagnose Forecast Evaluate and combine MM forecasts
Today’s arc, three questions:
1. How do I score several forecasts?U2U_2, MASE
2. Is the difference real?Diebold-Mariano
3. Should I even pick one?combinations

The PS3 design: many origins, one horizon

Train: estimate every model here, oncey1,…,yTy_1,\ldots,y_T, T=Ntotal−24T=N_{\text{total}}-24
Weights windowT+1,…,T+12T{+}1,\ldots,T{+}12
HoldoutT+13,…,T+24T{+}13,\ldots,T{+}24
UNRATE 1960-01train to 2017-12 · weights 2018 · holdout 2019
Parameters are estimated once, on y1,…,yTy_1,\ldots,y_Tnever again
The information set rolls. ỹt∣t−1\tilde y_{t\mid t-1} uses actuals up to yt−1y_{t-1}h=1h=1 throughout
Weights window, Tw=12T_w=12 dateswhere combination weights are estimated
Holdout, N=12N=12 dateswhere everything is scored
One fit per model; at each date, the training coefficients meet the newest data:
T_origin <- length(unrate) - 24  # Dec 2017
train_un <- upto(unrate, T_origin)
fit1 <- Arima(train_un, order = c(1, 1, 2),
  seasonal = list(order = c(1, 0, 1),
                  period = 12))
# one-step forecasts, coefficients frozen:
fitted(Arima(upto(unrate, T_origin + 24),
             model = fit1))
Subset a ts with window() (here upto()), never unrate[1:T_origin]: square brackets drop the monthly frequency.

Six forecast tracks

Track On UNRATE In the pool as
arima_1 ARIMA(1,1,2)(1,0,1)12_{12} the Module 5/6 model
arima_2 ARIMA(1,1,0) a simpler alternative
arima_3 auto.arima() on train the automatic pick
locf k=1k=1 the naive benchmark
avg_k k=3k=3 smooths sampling noise
meanf k=t−1k=t-1 the long-run mean

ỹt∣t−1=1k∑j=1kyt−j\tilde y_{t\mid t-1}=\frac{1}{k}\sum_{j=1}^{k}y_{t-j}

kk-period average forecasts, never “moving averages”: in this course that is the MA(qq) block.
Error: em,t=yt−ỹt∣t−1(m)e_{m,t}=y_t-\tilde y^{(m)}_{t\mid t-1}. Out of sample and observable: not ϵt\epsilon_t, not a residual.

UNRATE 2018-2019, actuals in black. meanf is off the chart, near 6.0%.

Why k=3k=3 for UNRATE, and not k=24k=24?

The course simulation: one track is genuinely better

(1−0.7L)(1−0.5L12)yt=α+ϵt,ϵt∼N(0,1),α=5(1−0.7)(1−0.5)=0.75,μ=5(1-0.7L)(1-0.5L^{12})\,y_t=\alpha+\epsilon_t,\qquad \epsilon_t\sim N(0,1),\qquad \alpha=5(1-0.7)(1-0.5)=0.75,\qquad \mu=5

Track In the simulation
arima_1 ARIMA(1,0,0)(1,0,0)12_{12}, mean true specification
arima_2 ARIMA(1,0,0), mean misses the season
arima_3 ARIMA(0,1,1) a needless difference
locf, avg_k, meanf k=1k=1, 33, t−1t-1 as on UNRATE
Each ARIMA estimated once, on 240 training months; then 12 weights-window and 12 holdout dates.
Built so the optimal weights are far from 1/M1/M: a method that finds arima_1 should beat the simple average.

The course realization (seed 6376): the end of training, then the weights window and the holdout.

Three ways to run an evaluation

Scheme Parameters Estimation window at origin tt Fits per model
Fixed-parameter one-step (PS3) estimated once 1:T1{:}T; information rolls to t−1t-1 1
Expanding window re-estimated at every origin 1:(t−1)1{:}(t-1) one per origin
Fixed-width rolling window re-estimated at every origin (t−W):(t−1)(t-W){:}(t-1) one per origin
Module 7 builds only the first row. The other two re-estimate at every origin.
Re-estimation buys robustness to change at the cost of noisier parameters. Fixed-width windows forget old regimes on purpose.
Which scheme would you use if you suspected a break in 2008?

U2U_2 and MASE answer different questions

RMSE and MAE are in units of yy; MAPE is a percentage. Is 0.1 points good? Two relative scores, two different questions.
U2U_2: a race. Did model mm beat locf on these holdout dates?

U2(m)=RMSE(m)RMSE(𝚕𝚘𝚌𝚏)U_2^{(m)}=\frac{\text{RMSE}^{(m)}}{\text{RMSE}^{(\texttt{locf})}}

Both RMSEs over the same holdout dates, t=T+13,…,T+24t=T{+}13,\ldots,T{+}24.
U2<1U_2<1beat locf here
U2>1U_2>1lost to it here
MASE (mean absolute scaled error): a yardstick. Model mm’s holdout miss, relative to the naive’s typical one-step miss in training.

MASE(m)=MAEholdout(m)MAEtrain(𝚕𝚘𝚌𝚏)\text{MASE}^{(m)}=\frac{\text{MAE}^{(m)}_{\text{holdout}}}{\text{MAE}^{(\texttt{locf})}_{\text{train}}}

MAEholdout(m)=1N∑t=T+13T+24|yt−ỹt∣t−1(m)|\text{MAE}^{(m)}_{\text{holdout}}=\frac{1}{N}\sum_{t=T+13}^{T+24}\bigl\lvert y_t-\tilde y^{(m)}_{t\mid t-1}\bigr\rvert

MAEtrain(𝚕𝚘𝚌𝚏)=1T−1∑t=2T|yt−ỹt∣t−1(𝚕𝚘𝚌𝚏)|\text{MAE}^{(\texttt{locf})}_{\text{train}}=\frac{1}{T-1}\sum_{t=2}^{T}\bigl\lvert y_t-\tilde y^{(\texttt{locf})}_{t\mid t-1}\bigr\rvert

with ỹt∣t−1(𝚕𝚘𝚌𝚏)=yt−1\tilde y^{(\texttt{locf})}_{t\mid t-1}=y_{t-1}. Seasonal variant: yt−sy_{t-s} replaces yt−1y_{t-1}, over t=s+1,…,Tt=s{+}1,\ldots,T, divided by T−sT-s.
MASE = 0.6. Did your model beat the naive in the holdout?

You cannot tell: the naive’s holdout errors never enter MASE. MASE <1<1 does not mean you beat the naive; U2<1U_2<1 does.

Helpers theil_u2(actual, forecast, benchmark) and mase(actual, forecast, train, m = 1): the helper’s m is the seasonal lag ss. accuracy() differs: a seasonal MASE scale by default, and a different “Theil’s U”.

The scorecard on UNRATE: small errors, no win

metrics_table <- function(actual, Fmat, train) {
  bench <- Fmat[, "locf"]
  t(apply(Fmat, 2, function(f) c(
    RMSE = rmse(actual, f),
    MAE  = mae(actual, f),
    MAPE = mape(actual, f),
    MASE = mase(actual, f, train),
    U2   = theil_u2(actual, f, bench))))
}
metrics_table(y_h, F_h, train_un)   # 2019
Every credible track has MASE below 1. Did any of them beat locf?
Track RMSE MAE MAPE MASE U2U_2
arima_1 0.097 0.083 2.258 0.642 1.011
arima_2 0.097 0.079 2.127 0.607 1.016
arima_3 0.096 0.080 2.168 0.618 0.999
locf 0.096 0.075 2.030 0.580 1.000
avg_k 0.108 0.092 2.478 0.709 1.124
meanf 2.315 2.312 63.103 17.875 24.182
No meaningful win: arima_3’s 0.999 is a tie with locf. MASE 0.58 to 0.71, but U2U_2 0.999 to 1.124 (locf is 1 by construction). 2019 was easy, for everyone, the naive included.
meanf: an I(1) series has no μ\mu to converge to (Module 2).

Scoring is not testing: the taste test

A metrics table is a ranking, not a verdict. Is the gap bigger than what the noise in twelve forecast errors would produce by chance?
Two coffee shops, one sip eachno verdict
Twelve mornings, one sip from eacha tally of the difference
Is the average difference zero?a paired tt-test
Shop A won one sip. How many paired sips before you would bet on A?

The Diebold-Mariano test is a tt-test on the loss differentials.

Diebold-Mariano: a tt-test on loss differentials

dt=g(e1,t)−g(e2,t),H0:𝔼[dt]=0d_t=g(e_{1,t})-g(e_{2,t}),\qquad H_0\!:\ \mathbb{E}[d_t]=0

d‾=1N∑tdt,DM=d‾σ̂d‾∼aN(0,1)\bar d=\frac{1}{N}\sum_t d_t,\qquad \text{DM}=\frac{\bar d}{\hat\sigma_{\bar d}}\ \stackrel{a}{\sim}\ N(0,1)

σ̂d‾\hat\sigma_{\bar d}: a standard error that allows for serial correlation in dtd_t. At h=1h=1, dm.test() uses lag 0 only, σ̂d/N\hat\sigma_d/\sqrt N (after the small-sample correction): it assumes dtd_t is serially uncorrelated, a condition on dtd_t, not merely on the errors.
Out-of-sample errors onlynever residuals(fit)
Same dates, same lossboth on the same NN
The sign: DM<0\text{DM}<0forecast 1 had the smaller loss
On the course simulation, the correctly specified model against the naive:
es_h <- ys_h - Fs_h        # N x M holdout errors
dm.test(es_h[, "arima_1"], es_h[, "locf"],
        h = 1, power = 2)  # power 2: squared
d_sim <- es_h[, "arima_1"]^2 - es_h[, "locf"]^2
t.test(d_sim)$statistic
dm.test()DM = −0.90, p = 0.390
t.test(d_sim)t = −0.90
The same statistic: dm.test() applies the Harvey-Leybourne-Newbold correction and a tN−1t_{N-1} reference. Named, not derived.

Shrink the sample: DM power from N=12N=12 to 120120

arima_1, correctly specified and estimated, has an expected-loss advantage over locf and arima_2 on average. How often does DM detect it?
R=200R=200 replications: a fresh series, the ARIMAs estimated once on 240 months, one-step tracks over the next 120, DM on the first NN dates.
At N=12N=12, what share of replications reject in favour of arima_1: about 90%, 50%, or 20%?
Rejecting for arima_1 N=12 N=24 N=60 N=120
arima_1 vs locf 12.5% 40.5% 76.0% 95.5%
arima_1 vs arima_2 10.0% 29.0% 60.5% 86.0%

Mainly power: DM rejects when the gap is large relative to the variability of dtd_t. “Failed to reject” never means “equally good”.
Caveat: these are rates of the h=1h=1 test, calibrated only if dtd_t is serially uncorrelated. Under a calibrated null, 2.5% would reject in this direction (dashed line).

Module 6’s question, answered

Module 6: on 2018-2019 the naive random walk beat the Module 5 SARIMA by a few hundredths. Does that margin mean anything?
Asked in the PS3 one-step design, on the 2019 holdout:
e_h <- y_h - F_h          # N x M holdout errors
dm.test(e_h[, "arima_1"], e_h[, "locf"],
        h = 1, power = 2)
arima_1 vs locfDM = 0.13, p = 0.90
Bartlett variance, h = 2:4p = 0.88 to 0.89
No: the test does not reject on these twelve months.
What it does not claim.
It does not test Module 6’s 24-step path. Errors from one origin share the early shocks and their spread grows with hh: not the sequence DM assumes.
It does not say the two are equally good. Twelve dates rarely separate even a correctly specified estimated model from a misspecified one.
It is not assumption-free: h=1h=1 assumes dtd_t is serially uncorrelated. A variance that allows for serial correlation gives the same verdict (a low-power check).

If you can’t pick a winner, why pick?

On UNRATE the five credible tracks are descriptively close, holdout RMSE 0.096 to 0.108, and the one tested comparison, arima_1 vs locf, does not reject. Picking the winner of a twelve-month race is mostly picking noise.
Each forecast carries some information, and the loser may carry information the winner lacks.
The portfolio analogy. Forecasts are assets; forecast errors are their risks. Imperfectly correlated errors diversify, as imperfectly correlated returns do.
Bates and Granger (1969)weight by accuracy
Granger and Ramanathan (1984)weights as a regression
Stock and Watson (2004)name the puzzle
Did the crowd mean beat most of you? Why might it?

A combined forecast is a weighted sum of forecasts

ỹt∣t−1(c)=w0+∑m=1Mwmỹt∣t−1(m)=w0+𝐰′𝐲̃t\tilde y^{(c)}_{t\mid t-1}=w_0+\sum_{m=1}^{M}w_m\,\tilde y^{(m)}_{t\mid t-1}=w_0+\mathbf{w}'\tilde{\mathbf{y}}_t

𝐲̃t\tilde{\mathbf{y}}_tthe M×1M\times1 vector of the MM forecasts of yty_t
wmw_m, 𝐰\mathbf{w}the weight on forecaster mm; the M×1M\times1 weight vector
w0w_0an intercept: zero for every method but one
ec,t=yt−ỹt∣t−1(c)e_{c,t}=y_t-\tilde y^{(c)}_{t\mid t-1}the combined error; cc is a label, not an index
Hats, stars and nothing, the DGP-versus-estimation rule applied to weights:
wwgeneric, or a fixed rule (1/M1/M)
ŵ\hat westimated on the weights window
w*w^*the population optimum
Weights are always ww, never α\alpha or β\beta (taken). Enders writes α0,…,αn\alpha_0,\ldots,\alpha_n.

Two forecasts: the combined error variance

Weights ww and 1−w1-w sum to one, so the combined error is the same mix of the two errors:

ec,t=we1,t+(1−w)e2,te_{c,t}=w\,e_{1,t}+(1-w)\,e_{2,t}

Var(ec,t)=w2Var(e1,t)+(1−w)2Var(e2,t)+2w(1−w)Cov(e1,t,e2,t)\begin{aligned}\text{Var(}e_{c,t}\text{)}&=w^2\,\text{Var(}e_{1,t}\text{)}+(1-w)^2\,\text{Var(}e_{2,t}\text{)}\\&\quad+2w(1-w)\,\text{Cov(}e_{1,t},e_{2,t}\text{)}\end{aligned}

Minimise over ww (Enders 2.73):

w*=Var(e2,t)−Cov(e1,t,e2,t)Var(e1,t)+Var(e2,t)−2Cov(e1,t,e2,t)w^*=\frac{\text{Var(}e_{2,t}\text{)}-\text{Cov(}e_{1,t},e_{2,t}\text{)}}{\text{Var(}e_{1,t}\text{)}+\text{Var(}e_{2,t}\text{)}-2\,\text{Cov(}e_{1,t},e_{2,t}\text{)}}

With zero covariance, the inverse-variance weight:

w*=1/Var(e1,t)1/Var(e1,t)+1/Var(e2,t)w^*=\frac{1/\text{Var(}e_{1,t}\text{)}}{1/\text{Var(}e_{1,t}\text{)}+1/\text{Var(}e_{2,t}\text{)}}

Error correlation (two indices: not the lag-kk ρk\rho_k):

ρ1,2=Cov(e1,t,e2,t)Var(e1,t)Var(e2,t)\rho_{1,2}=\frac{\text{Cov(}e_{1,t},e_{2,t}\text{)}}{\sqrt{\text{Var(}e_{1,t}\text{)}\,\text{Var(}e_{2,t}\text{)}}}

Variance ratio Var(e2,t)/Var(e1,t)≥1\text{Var(}e_{2,t}\text{)}/\text{Var(}e_{1,t}\text{)}\ge1: forecast 1 is the better one.
Diversification: equal variances VV, zero covariance: w*=0.5w^*=0.5 and Var(ec,t)=0.5V\text{Var(}e_{c,t}\text{)}=0.5V. Averaging halves the error variance.
Correlation eats the gain. Among weights in [0,1][0,1], the best mix beats forecast 1 alone until Cov(e1,t,e2,t)=Var(e1,t)\text{Cov(}e_{1,t},e_{2,t}\text{)}=\text{Var(}e_{1,t}\text{)}, that is, ρ1,2=Var(e1,t)/Var(e2,t)\rho_{1,2}=\sqrt{\text{Var(}e_{1,t}\text{)}/\text{Var(}e_{2,t}\text{)}}.
Past that threshold, w*>1w^*>1: the formula shorts the worse forecast. Unconstrained regression weights do exactly this (Method 3).

Drag the weight, the correlation, the variance ratio

Method 1: the simple average

w0=0,wm=1Mw_0=0,\qquad w_m=\frac{1}{M}

Nothing is estimated, so the weights carry no hat. That is the whole point: the zero-estimation-error benchmark that every other method has to beat.
It is the radar’s crowd mean: every forecaster gets one vote, 1/M1/M of the result.
Every method fits on the weights window (Tw=12T_w=12 actuals and the Tw×MT_w\times M forecasts of them) and is then applied, unchanged, to the holdout forecasts.
comb_simple <- function(y, F) {
  M <- ncol(F)   # y unused: common interface
  list(intercept = 0,
       weights = setNames(rep(1 / M, M),
                          colnames(F)))
}

Method 2: inverse-MSE weights

ŵm=1/MSEm∑j=1M1/MSEj,MSEm=1Tw∑t∈weightsem,t2,ŵ0=0\hat w_m=\frac{1/\text{MSE}_m}{\sum_{j=1}^{M}1/\text{MSE}_j},\qquad \text{MSE}_m=\frac{1}{T_w}\sum_{t\in\text{weights}}e_{m,t}^2,\qquad \hat w_0=0

The MM-forecast version of the zero-covariance w*w^* (Bates and Granger 1969; Enders 2.74).
MM numbers estimated, each from its own column. Non-negative and summing to one by construction.
MSE, not the error variance, so a biased forecaster pays for its bias too.
comb_inv_mse <- function(y, F) {
  mse <- colMeans((y - F)^2)
  list(intercept = 0,
       weights = (1 / mse) / sum(1 / mse))
}

Method 3: Granger-Ramanathan

yt=w0+∑m=1Mwmỹt∣t−1(m)+vt,t∈weights windowy_t=w_0+\sum_{m=1}^{M}w_m\,\tilde y^{(m)}_{t\mid t-1}+v_t,\qquad t\in\text{weights window}

Unconstrained least squares with an intercept. OLS on the weights window delivers ŵ0,ŵ1,…,ŵM\hat w_0,\hat w_1,\ldots,\hat w_M.
The intercept absorbs any bias; weights can be negative and need not sum to one.
With M=6M=6 and Tw=12T_w=12: seven numbers from twelve observations.
vtv_t is the regression’s disturbance: not an innovation ϵt\epsilon_t, not a forecast error em,te_{m,t}.
comb_gr <- function(y, F) {
  b <- coef(lm(y ~ F))
  w <- setNames(b[-1], colnames(F))
  w[is.na(w)] <- 0   # exactly collinear track
  list(intercept = unname(b[1]), weights = w)
}
Module 4 asked the same question of extra AR lags. Do parameters that fit the sample forecast?

Method 4: constrained least squares

𝐰̂=argmin𝐰∑t∈weights(yt−𝐰′𝐲̃t)2subject towm≥0,∑m=1Mwm=1,ŵ0=0\hat{\mathbf{w}}=\arg\min_{\mathbf{w}}\sum_{t\in\text{weights}}\big(y_t-\mathbf{w}'\tilde{\mathbf{y}}_t\big)^2\quad\text{subject to}\quad w_m\ge0,\;\;\sum_{m=1}^{M}w_m=1,\qquad \hat w_0=0

A quadratic program. No intercept, weights in a box: non-negative and summing to one.
The constraints do model selection: several weights land exactly on zero, and the rest read as shares.
Stable, interpretable, cannot short a forecaster.
No separate intercept for bias adjustment; reweighting can reduce bias, but cannot eliminate a common same-direction bias shared by every forecast.
comb_cls <- function(y, F) {
  M    <- ncol(F)
  Amat <- cbind(rep(1, M), diag(M))
  bvec <- c(1, rep(0, M))   # sum = 1; w >= 0
  w <- quadprog::solve.QP(crossprod(F),
         crossprod(F, y), Amat, bvec,
         meq = 1)$solution
  w <- pmax(w, 0); w <- w / sum(w)
  list(intercept = 0,
       weights = setNames(w, colnames(F)))
}

Four methods, one dial

Method w0w_0 ∑wm=1\sum w_m=1 wm≥0w_m\ge0 Numbers estimated from the window Estimation risk
Simple average (SA) 0 yes yes 0 none
Inverse-MSE 0 yes yes MM, one column at a time low
Constrained LS (CLS) 0 yes yes MM, jointly, boxed in moderate
Granger-Ramanathan (GR) free no no M+1M+1, jointly, unrestricted high
The four, fit on the course simulation’s weights window:
simple avg inverse-MSE constrained LS Granger-
Ramanathan
ŵ0\hat w_0 0.00 0.00 0.00 261.70
arima_1 0.17 0.27 0.66 0.78
arima_2 0.17 0.14 0.00 1.88
arima_3 0.17 0.11 0.00 −2.04
locf 0.17 0.09 0.00 0.00
avg_k 0.17 0.16 0.00 −0.83
meanf 0.17 0.23 0.34 −50.83
Read it as a dial. The simple average estimates nothing; inverse-MSE a little; CLS more, inside a box; Granger-Ramanathan everything.
CLS finds arima_1. Granger-Ramanathan’s intercept is 262 on a series whose mean is 5.
Which end of the dial wins on data the weights have not seen?

A combination method is an estimator

Theory says Granger-Ramanathan should win. It minimises the weights-window sum of squared errors over all intercepts and weights: no other weights can fit that window better.
But the fit is in-sample, and its weights are estimates from twelve observations. Estimates carry error.
The assumption we break: that you know the weights.
The experiment is fair. The course DGP has a dominant track, arima_1, so the optimal weights are far from 1/M1/M.
A method that finds arima_1 should beat the simple average. Can it, with Tw=12T_w=12?

Stage 1: weights that win the window they were fit on

RMSE Weights window Holdout
arima_1 0.706 1.120
arima_2 0.979 1.208
arima_3 1.115 1.372
locf 1.208 1.301
avg_k 0.922 1.793
meanf 0.769 1.701
simple avg 0.877 1.284
inverse-MSE 0.804 1.281
constrained LS 0.681 1.237
Granger-Ramanathan 0.282 3.009
One realization (seed 6376), Tw=12T_w=12: the §7.6 weights, scored on the window they were fit on and on the holdout.
Granger-Ramanathan, weights window0.282
simple average; arima_10.877; 0.706
Granger-Ramanathan, holdout3.009
Best in the window, worst on the holdout: almost as many weights as observations, fitting the noise.
The other three sit close together; CLS, which found arima_1, is the best of them.

Scoring a method: holdout RMSE relative to the simple average

relative RMSEmethod=RMSE of the method’s combination on the holdoutRMSE of the simple average on the same holdout\text{relative RMSE}_{\text{method}}=\frac{\text{RMSE of the method's combination on the holdout}}{\text{RMSE of the simple average on the same holdout}}

Below 1beat the simple average
Equal to 1a tie
Above 1lost to it
Weights fit on the weights window; scored on the 12 holdout dates the weights never saw.
Not U2U_2. U2U_2 divides by locf’s RMSE; this ratio divides by the simple average’s. Same dates, a different benchmark.
Over R=200R=200 simulated series, one ratio per replication. Three summaries:
Medianthe typical replication
90th percentilethe bad case: the right tail
Share beating the simple averagefraction of replications below 1

Stage 2: 200 replications at a 12-date weights window

Each replication (seed 6378): a fresh series, the ARIMAs estimated once, six tracks, four methods fit on Tw=12T_w=12, scored on the 12-date holdout relative to the simple average.
Granger-Ramanathan beats the simple average in about 80%, 50%, or 15% of replications?

Every ratio above 5× is drawn (orange) in the shaded band: 12 of Granger-Ramanathan’s 200, the largest 11.7×; in the widget they fill the hatched lane. The summaries use every replication.
Median 90th pct Share < 1
inverse-MSE 0.99 1.01 74.5%
constrained LS 0.95 1.12 64.0%
Granger-Ramanathan 1.68 4.07 16.0%
The long right tail is the puzzle in one picture. Inverse-MSE is the simple average with a tilt (median 0.99); CLS beats the simple average at the median (0.95).

Stage 3: how long a window do estimated weights need?

The forecast combination puzzle

Theory says optimally weighted combinations should dominate. In practice, the simple average is very hard to beat. Stock and Watson (2004)
Three lessons from the simulation.
1. A combination method is an estimator. Holdout performance = the population gain from its weights minus the estimation error in them.
2. The puzzle is a comparison: attainable gain against estimation cost. It bites when the gain over equal weights is small relative to the cost of estimating the weights: near-equal optimal weights, or redundant forecasts. Twelve weights-window dates make the cost high, as in most applied work, and PS3.
3. Restrictions are a dial. Moving down from 1/M1/M pays only when the window is long or the gain is large.
The index fund. Active managers (estimated weights) should beat the index (equal weights): they pick the winners. In practice fees eat the edge. Here the fee is estimation error.

But an index fund that holds a bankrupt stock at full weight is not a good index. Equal weights are robust to estimation error, not to a broken member of the pool.

UNRATE: weights fit on 2018

ws_un <- list(SA   = comb_simple(y_w, F_w),
              IMSE = comb_inv_mse(y_w, F_w),
              CLS  = comb_cls(y_w, F_w),
              GR   = comb_gr(y_w, F_w))
sapply(ws_un, function(w)
  c(w0 = w$intercept, w$weights))
kappa(cbind(1, F_w), exact = TRUE)
Condition number, GR design matrix41,620
Before the holdout: which of the four will the simple average beat on 2019?
simple avg inverse-MSE constrained LS Granger-
Ramanathan
ŵ0\hat w_0 0.000 0.000 0.000 −141.450
arima_1 0.167 0.235 0.690 1.224
arima_2 0.167 0.158 0.000 −5.825
arima_3 0.167 0.229 0.000 1.088
locf 0.167 0.179 0.000 5.098
avg_k 0.167 0.198 0.310 −2.605
meanf 0.167 0.001 0.000 24.803
Over twelve months the expanding mean of 696+ observations barely moves: the meanf column is almost a constant, almost collinear with the intercept.

UNRATE: scored on 2019

2019 Holdout RMSE
arima_1 0.097
arima_2 0.097
arima_3 0.096
locf 0.096
avg_k 0.108
meanf 2.315
simple avg 0.416
inverse-MSE 0.093
constrained LS 0.094
Granger-Ramanathan 0.463
Simple average0.416
credible single tracks0.096 to 0.108
Inverse-MSE; CLS0.093; 0.094
Granger-Ramanathan0.463
Of the four combinations, the simple average beat only Granger-Ramanathan.
Inverse-MSE and CLS match or edge out the best single tracks; the simple average is roughly four times their RMSE.

UNRATE: each estimated-weight combination against the simple average

Three tests, declared in advance, all reported.
comb_h <- sapply(ws_un, function(w)   # N x 4
  w$intercept + F_h %*% w$weights)
ec_h <- y_h - comb_h      # combined errors
for (m in c("IMSE", "CLS", "GR"))
  print(dm.test(ec_h[, m], ec_h[, "SA"],
                h = 1, power = 2))
Never pick the holdout winner and then test it on the same twelve dates: that chooses the hypothesis after seeing the data.
Against the simple average DM pp
Inverse-MSE −9.1 1.9×10−61.9\times10^{-6}
CLS −9.1 1.8×10−61.8\times10^{-6}
Granger-Ramanathan 0.87 0.40
Inverse-MSE and CLS: a clear rejection at N=12N=12, the power lesson from the other side. Granger-Ramanathan: no detectable difference.
The h=1h=1 check, all four UNRATE tests: Ljung-Box pp = 0.58 to 0.97 on dtd_t (little power at N=12N=12); Bartlett variance, h = 2:4: no verdict changes.

The honest reading: a broken member, not a lucky estimate

Here the attainable gain is large. meanf has no business on an I(1) series, and 1/M1/M gives it a sixth of the vote: enough to drag the average about 0.39 points off the actuals every month.
Inverse-MSE and CLS won by down-weighting it, which is exactly what estimated weights are for: that gain pays for estimating the restricted weights.
Granger-Ramanathan lost for the Stage 1 reason, amplified by near-collinearity: the intercept and the nearly constant meanf column are almost the same regressor.
Caveats: one window, a calm glide with no turning point; the h=1h=1 verdicts survive a low-power dependence check, so robust, not definitive. One realization is one draw; the Monte Carlo is the distribution.
For Problem Set 3: look at your six tracks before you combine them. If one is broken on your series, say so, explain why from the series’ properties, and expect it to drag the simple average.
Equal weights are robust to estimation error. What are they not robust to?

A broken member of the pool.

Key takeaways + next time

1. Many origins, one horizon. Estimate once; roll the information set.
2. U2U_2: did you beat the naive here? MASE: how big was the miss against the naive’s training miss?
3. A metrics table is a ranking, not a verdict. DM is a tt-test on dtd_t (h=1h=1: assumes serially uncorrelated dtd_t); twelve dates buy little power. UNRATE: five tracks descriptively close; arima_1 vs locf does not reject.
4. Combine because errors diversify. Zero covariance: weights ∝\propto inverse error variance.
5. A combination method is an estimator. With Tw=12T_w=12, estimate as little as you can.
6. Equal weights are the benchmark to beat, when the pool is sound. The puzzle: estimation cost outweighs the attainable gain.
7. Every forecast here used only the series’ own past.
Next time, Module 8: ADL models.
What if an exogenous regressor could improve the forecast?

yt=α+βxt+∑j=1pϕjyt−j+ϵty_t=\alpha+\beta x_t+\sum_{j=1}^{p}\phi_j y_{t-j}+\epsilon_t

A new slider on the mixing board: βxt\beta x_t and its lags. Combinations only reshuffle the information already in the pool.

Interactive lab machinery

This uncounted support slide keeps both widget factories in the document. Use the RevealJS menu to return to a widget if a browser reload interrupts an interaction.