"""Check the PDF and figure_changes against the saved test results (every key number re-derived from the source files).""" import subprocess, pickle, json import pandas as pd PDF = '/mnt/user-data/outputs/Binzagr_Data/06_Model_Review/Binzagr_Model_Review_Before_After.pdf' W = '/home/claude/binzagr/boost/work'; D = '/mnt/user-data/outputs/Binzagr_Data/06_Model_Review/data' txt = subprocess.run(['pdftotext', '-layout', PDF, '-'], capture_output=True, text=True).stdout flat = ' '.join(txt.split()) fc = pd.read_csv(f'{W}/fc_summary.csv').set_index('level') CT = pickle.load(open(f'{W}/churn_race.pkl', 'rb'))['table'].set_index('model'); ch = pickle.load(open(f'{W}/churn_race.pkl', 'rb')) AT = pickle.load(open(f'{W}/adoption_race.pkl', 'rb'))['table'].set_index('model'); ad = pickle.load(open(f'{W}/adoption_race.pkl', 'rb')) rf = pickle.load(open(f'{W}/reco_final_v2.pkl', 'rb')); RES = rf['res']; N = pickle.load(open(f'{W}/report_numbers.pkl', 'rb')) fails = [] def need(s, why): ok = s in flat print(('PASS' if ok else 'FAIL'), f'{s!r:28s}', why) if not ok: fails.append(s) p = lambda x: f'{100 * x:.1f}%' need(p(fc.loc['sku', 'picked_at_site_bias']), 'SKU after, same bias') need(p(fc.loc['sku', 'picked_wape']), 'SKU as fitted') need(p(fc.loc['van', 'picked_at_site_bias']), 'van after, same bias') need(p(fc.loc['principal', 'picked_at_site_bias']), 'principal after') need(p(fc.loc['cluster', 'picked_at_site_bias']), 'cluster after') need(p(fc.loc['sku', 'replica_site_style']), 'our copy of the per-SKU race') need(p(fc.loc['sku', 'naive7']), 'our SKU repeat-last-week') need(p(fc.loc['sku', 'wd4']), 'our SKU 4-week average') need('74.1%', 'SKU blend at zero bias (fc_eval check)') need(f'{CT.loc["Extra trees", "test_auc"]:.3f}', 'churn after AUC') need(f'{CT.loc["LightGBM", "test_auc"]:.3f}', 'churn LightGBM AUC') need(f'+{ch["ci"]["Extra trees"][0]:.3f} to +{ch["ci"]["Extra trees"][2]:.3f}', 'churn 90% interval') need(f'{100 * CT.loc["Extra trees", "test_top20_capture"]:.0f}%', 'churn top-20 after') need(p(RES['site_style']['test_p10']), 'NBS our copy of site scorer') need(p(RES[rf['pick']]['test_p10']), 'NBS after (picked model)') need(f'+{100 * RES[rf["pick"]]["gain_90pct_interval"][0]:.1f} to +{100 * RES[rf["pick"]]["gain_90pct_interval"][1]:.1f}', 'NBS 90% interval') need(f'{AT.loc["LightGBM", "test_auc_within_mean"]:.2f} to {AT.loc[ad["pick"], "test_auc_within_mean"]:.2f}', 'adoption within-cluster before to after') need('SAR 5,060,755', 'hold-out sales match') need('4,097', 'NBS outlets judged') need(f'SAR {(3454548 + N["lever"]["total_change"]) / 1e6:.3f}M', 'value total after') need('Confidential - contains Binzagr data', 'footer') for t_ in ['3.0× · Model picks 12%', '0.77 · Churn model 0.77', '38.6% vs 47.2% weekly error', 'SAR 927,163 past due (24%)', '−8% error', '4.0× the average rate']: need(t_, 'replacement table text') F = pd.read_csv(f'{D}/before_after_figures.csv') print('before_after rows', len(F), '| numbers unique', F.no.is_unique, '| types', F.type.value_counts().to_dict()) J = json.load(open(f'{D}/before_after_figures.json')); print('json rows', len(J['rows'])) for f_ in ['next_best_sku_picks_v2.csv', 'churn_scores_v2.csv']: d = pd.read_csv(f'{D}/{f_}'); print(f_, len(d), 'rows', d.columns.tolist()) pk = pd.read_csv(f'{D}/next_best_sku_picks_v2.csv', dtype={'outlet_id': str, 'sku': str}) print('picks: ranks 1..10 per outlet', bool(pk.groupby('outlet_id')['rank'].apply(lambda r: sorted(r) == list(range(1, len(r) + 1))).all())) print('\nFAILED:', fails if fails else 'none')