1# F3-conf-03 — Ridge vs naive / expanding-mean forecasts of US IP growth (h = 1)23## Question4Does 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.56## Data and exclusions7- 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 in `out/state/data_audit.md`.8- The only missing values are `neworder_chg` for 1992-01 and 1992-02. Both months fall before the training start specified in the task (1992-03), so no imputation was needed.9- The README says the 1992-01 value of every change series is empty, but `ip_growth`, `oil_chg` and `permit_chg` do have 1992-01 values. I used them as given, and only `ip_growth` 1992-01 enters the model (as the second lag of the first training row). This and the vintage caveat are recorded in `data_issues`.10- 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`).1112## Method13- **Naive forecast:** `ip_growth` at origin t.14- **Expanding-mean forecast:** the mean of `ip_growth` over 1992-04 to t.15- **Ridge regression:**16 - At each origin, the training rows are s ∈ [1992-03, t−1], with target `ip_growth` at 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.17 - 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 ȳ.18 - 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.19- **Errors:** RMSE and MAE over the 60 one-step errors, computed on the current-vintage data.20- **Determinism:** the procedure is deterministic and uses no randomness (`random_seed` = null). `out/analysis.py` regenerates `results.json`, `forecasts.csv` and `exclusions.csv`.2122## Results23| model | RMSE (pp/month) | MAE (pp/month) |24|---|---|---|25| naive | 0.8831 (`rmse_naive`) | 0.6990 (`mae_naive`) |26| expanding mean | 0.5439 (`rmse_mean`) | 0.4293 (`mae_mean`) |27| ridge λ=50 | 0.5608 (`rmse_ridge`) | 0.4514 (`mae_ridge`) |2829- Compared with the naive forecast, ridge cuts RMSE by 36.5% (`rel_improvement_vs_naive` = 0.3649).30- 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`).31- **Answer:** the ridge model beats the naive baseline but not the expanding-mean baseline over this evaluation window.3233## Uncertainty34- 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).35 - 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`).36 - 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.37- No confidence intervals for the RMSEs were requested or computed.3839## Limitations and open issues40- **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.41- **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_growth` minimum −14.14 in 2020-04), which were not treated in any special way.42- **Single evaluation window:** results cover 2021-10 to 2026-09 only and may not generalise to other periods.43- **Small discrepancy:** forecasts in `forecasts.csv` are rounded to 8 decimals, so metrics recomputed from that file differ from `results.json` by less than 1e-9.44