import json, numpy as np, pandas as pd r=json.load(open('out/results.json')); fc=pd.read_csv('out/forecasts.csv') d=pd.read_csv('data/ip_predictors.csv') out=[] def chk(name,cond): out.append((name,bool(cond))); print(('PASS' if cond else 'FAIL'),name) chk('180 rows', len(fc)==180) chk('60 per model', (fc.model.value_counts()==60).all()) chk('horizon all 1', (fc.horizon==1).all()) chk('target = origin + 1 month', (pd.to_datetime(fc.target_date)==pd.to_datetime(fc.origin_date)+pd.DateOffset(months=1)).all()) chk('first/last origin', fc.origin_date.min()=='2021-09-01' and fc.origin_date.max()=='2026-08-01') # independent re-implementation, slicing raw data <= t positionally (leakage-proof by construction) ip=d.ip_growth.values; months=list(d.month) X_all=np.column_stack([ip, np.r_[np.nan,ip[:-1]], np.r_[np.nan,np.nan,ip[:-2]], d.oil_chg, d.fedfunds, d.permit_chg, d.neworder_chg, d.tcu]) i0=months.index('1992-03-01'); im=months.index('1992-04-01') maxdiff=0; maxleak=0 for t in pd.date_range('2021-09-01','2026-08-01',freq='MS').strftime('%Y-%m-%d'): it=months.index(t) if True: Xa=X_all[:it+1].copy(); y=ip[:it+1].copy() # only data dated <= t X=Xa[i0:it]; Y=y[i0+1:it+1] mu=X.mean(0); sd=X.std(0,ddof=1); Z=(X-mu)/sd; yb=Y.mean() b=np.linalg.inv(Z.T@Z+50*np.eye(8))@Z.T@(Y-yb) f=yb+((Xa[it]-mu)/sd)@b g=fc[(fc.origin_date==t)&(fc.model=='ridge')].forecast.iloc[0] maxdiff=max(maxdiff,abs(f-g)) m=ip[im:it+1].mean(); maxdiff=max(maxdiff,abs(m-fc[(fc.origin_date==t)&(fc.model=='mean')].forecast.iloc[0])) maxdiff=max(maxdiff,abs(ip[it]-fc[(fc.origin_date==t)&(fc.model=='naive')].forecast.iloc[0])) maxdiff=max(maxdiff,abs(ip[it+1]-fc[(fc.origin_date==t)&(fc.model=='naive')].actual.iloc[0])) chk(f'independent re-implementation matches forecasts (max abs diff {maxdiff:.2e})', maxdiff<1e-8) for m in ['naive','mean','ridge']: e=fc[fc.model==m].forecast-fc[fc.model==m].actual chk(f'rmse_{m} recomputed', abs(np.sqrt((e**2).mean())-r[f'rmse_{m}'])<1e-9) # CSV stores 10 decimals chk(f'mae_{m} recomputed', abs(e.abs().mean()-r[f'mae_{m}'])<1e-9) # CSV stores 10 decimals chk(f'rmse_{m}>0 and rmse>=mae', r[f'rmse_{m}']>0 and r[f'rmse_{m}']>=r[f'mae_{m}']) chk('rel_impr naive identity', abs(r['rel_improvement_vs_naive']-(1-r['rmse_ridge']/r['rmse_naive']))<1e-15) chk('rel_impr mean identity', abs(r['rel_improvement_vs_mean']-(1-r['rmse_ridge']/r['rmse_mean']))<1e-15) ex=pd.read_csv('out/exclusions.csv') chk('exclusion ledger sums', r['n_input_rows']['ip_predictors.csv']-ex.n_removed.sum()==r['n_analysed']==413) chk('n_train first origin = 354 (1992-03..2021-08)', r['n_train_first_origin']==354)