F3-conf-03 — Ridge vs naive / expanding-mean forecasts of US IP growth (h = 1)
Question
Does a ridge regression with a fixed penalty (λ = 50, lambda) on 8 standardised monthly predictors (n_features) forecast next month's US industrial production growth (100·Δln INDPRO, percent per month) better than the naive last-value forecast and the expanding historical mean? There are 60 rolling origins (n_origins), from first_origin = 2021-09-01 to last_origin = 2026-08-01, so the targets run from 2021-10 to 2026-09.
Data and exclusions
- The input is
data/ip_predictors.csv(n_input_rows= 417 rows, 1992-01 to 2026-09). Its SHA-256 matches the README. The months are contiguous and there are no duplicates. Details are inout/state/data_audit.md. - The only missing values are
neworder_chgfor 1992-01 and 1992-02. Both months fall before the training start specified in the task (1992-03), so no imputation was needed. - The README says the 1992-01 value of every change series is empty, but
ip_growth,oil_chgandpermit_chgdo have 1992-01 values. I used them as given, and onlyip_growth1992-01 enters the model (as the second lag of the first training row). This and the vintage caveat are recorded indata_issues. - Exclusion ledger (
out/exclusions.csv): 417 raw rows, minus 2 months before 1992-03, minus 2 months whose target falls after the last origin, gives 413 training rows at the last origin (n_analysed).
Method
- Naive forecast:
ip_growthat origin t. - Expanding-mean forecast: the mean of
ip_growthover 1992-04 to t. - Ridge regression:
- At each origin, the training rows are s ∈ [1992-03, t−1], with target
ip_growthat s+1. The features are ip_growth at s, s−1 and s−2, plus oil_chg, fedfunds, permit_chg, neworder_chg and tcu at s. - Each feature is standardised with the mean and the sample SD (ddof = 1) of that origin's training rows (
normalisation_window= "expanding"). The target is centred on its training mean ȳ. - Coefficients: b = (Z′Z + 50·I)⁻¹Z′(y−ȳ). Forecast: ȳ + z̃_t·b, where z̃_t is the origin's feature vector standardised with the same mean and SD.
- At each origin, the training rows are s ∈ [1992-03, t−1], with target
- Errors: RMSE and MAE over the 60 one-step errors, computed on the current-vintage data.
- Determinism: the procedure is deterministic and uses no randomness (
random_seed= null).out/analysis.pyregeneratesresults.json,forecasts.csvandexclusions.csv.
Results
| model | RMSE (pp/month) | MAE (pp/month) |
|---|---|---|
| naive | 0.8831 (rmse_naive) |
0.6990 (mae_naive) |
| expanding mean | 0.5439 (rmse_mean) |
0.4293 (mae_mean) |
| ridge λ=50 | 0.5608 (rmse_ridge) |
0.4514 (mae_ridge) |
- Compared with the naive forecast, ridge cuts RMSE by 36.5% (
rel_improvement_vs_naive= 0.3649). - Compared with the expanding mean, ridge is worse: RMSE is 3.1% higher (
rel_improvement_vs_mean= −0.0310), and its MAE is also higher (mae_ridge>mae_mean). - Answer: the ridge model beats the naive baseline but not the expanding-mean baseline over this evaluation window.
Uncertainty
- The evaluation uses only 60 monthly errors. As a supplementary check that the task did not require, I ran Diebold–Mariano-type tests on squared-error loss differentials (h = 1, simple variance, t-reference).
- Ridge vs naive: the gain is clearly distinguishable from zero (
supplementary.dm_stat_ridge_vs_naive= 3.36, p = 0.0014,supplementary.dm_pvalue_ridge_vs_naive). - Ridge vs expanding mean: the difference is not distinguishable from zero (
supplementary.dm_stat_ridge_vs_mean= −0.54, p = 0.59,supplementary.dm_pvalue_ridge_vs_mean). The small loss relative to the mean should therefore be read as "no evidence of improvement", not as evidence that ridge is genuinely worse.
- Ridge vs naive: the gain is clearly distinguishable from zero (
- No confidence intervals for the RMSEs were requested or computed.
Limitations and open issues
- Not real-time: the data are the current vintage, and publication lags are ignored by design. INDPRO, TCU and NEWORDER are heavily revised, so these results do not measure real-time forecast performance.
- Fixed specification: λ = 50 is fixed by the task and not tuned. Performance against the mean baseline may depend on this choice and on the 2020 COVID observations in the training windows (
ip_growthminimum −14.14 in 2020-04), which were not treated in any special way. - Single evaluation window: results cover 2021-10 to 2026-09 only and may not generalise to other periods.
- Small discrepancy: forecasts in
forecasts.csvare rounded to 8 decimals, so metrics recomputed from that file differ fromresults.jsonby less than 1e-9.