SPB Git

spb/wp29_uqo

Public

# F3-conf-03 — Rolling-origin ridge forecasts of US industrial production growth

# Question

Does a fixed-penalty ridge regression (λ = 50) on eight standardised monthly predictors forecast next month's US industrial production growth (100 × Δln INDPRO, % per month) better than (a) the naive last-value forecast and (b) the expanding historical mean, over 60 rolling origins from 2021-09 to 2026-08 (horizon h = 1)?

# Data and exclusions

  • data/ip_predictors.csv: 417 monthly rows, 1992-01 to 2026-09, current-vintage FRED data (see data/README.md). No rows were dropped.
  • Missing values: only neworder_chg for 1992-01 and 1992-02. Neither falls in any training window (training rows start at 1992-03), so no imputation was needed.
  • Minor discrepancy: the README says the first month of every change series is empty, but ip_growth, oil_chg and permit_chg are populated for 1992-01. I kept the values as given. ip_growth 1992-01 enters only as the second lag in the 1992-03 training row, which is what the task specification implies.
  • The extreme COVID-19 months of 2020 (ip_growth from −14.14 to +6.35 %) stay in every training window, as the specification requires. They inflate the standardisation statistics and affect the coefficients.

# Method

  • Origins t = 2021-09-01 … 2026-08-01 (60). Each origin's target is ip_growth at t+1.
  • Naive forecast: ip_growth at t.
  • Expanding-mean forecast: the mean of ip_growth from 1992-04 to t.
  • Ridge: the training rows are s = 1992-03 … t−1, with target y_{s+1}. The features are ip_growth_s, ip_growth_{s−1} and ip_growth_{s−2}, plus oil_chg_s, fedfunds_s, permit_chg_s, neworder_chg_s and tcu_s.
    • At every origin I recompute the feature means and sample SDs (ddof = 1) and the target mean from that origin's training rows only. normalisation_window = "expanding".
    • b = (Z′Z + 50 I)⁻¹ Z′(y − ȳ), with no penalised intercept. Forecast = ȳ + ((z_t − μ)/σ)·b.
    • The code asserts that no training target is dated after t.
  • I scored errors against current-vintage actuals and computed RMSE and MAE over the 60 origins.
  • out/analysis.py regenerates results.json, forecasts.csv (180 rows) and uncertainty.json.

# Results

model RMSE (%/month) MAE (%/month)
naive 0.8831 0.6990
expanding mean 0.5439 0.4293
ridge (λ=50) 0.5608 0.4514
  • Relative RMSE improvement of ridge over naive: 1 − 0.5608/0.8831 = +0.365 (36.5 % lower RMSE).
  • Relative RMSE improvement of ridge over the expanding mean: −0.031. Ridge's RMSE is 3.1 % higher than the mean's, and its MAE is also higher.

So the ridge model clearly beats the naive forecast but does not beat the expanding historical mean over this evaluation window. At the one-month horizon, the eight predictors add no out-of-sample value over the unconditional mean.

# Uncertainty

These diagnostics are in out/uncertainty.json, produced by the same script.

  • Diebold–Mariano tests (squared loss, with the Harvey–Leybourne–Newbold small-sample correction and a t(59) reference):
    • ridge vs naive: statistic −3.36, p = 0.0014. Ridge is significantly better.
    • ridge vs mean: statistic +0.54, p = 0.59. There is no significant difference.
  • Moving-block bootstrap (block 6, B = 5000, seed 12345), 95 % intervals for the relative RMSE improvement:
    • vs naive: [0.248, 0.426].
    • vs mean: [−0.158, 0.056].
  • With only 60 evaluation months, a small loss to the mean cannot be told apart from a small gain.

# Limitations and open issues

  • Data vintage. I used current-vintage, revised data and ignored publication lags (INDPRO, TCU and NEWORDER are revised substantially). These results are not real-time forecast performance.
  • Model choices. λ = 50 is fixed by the task, not tuned. The level variables (fedfunds, tcu) enter untransformed. The COVID outliers are untreated. Each of these could change the ridge results.
  • Evaluation window. It is one short window (2021-09 to 2026-08) and includes the post-pandemic recovery. The relative ranking may not generalise to other periods.
  • Uncertainty method. The DM test and the bootstrap both assume approximate stationarity of loss differentials. The bootstrap seed does not affect any value in results.json.
Files · main
Menu

Theme