| import json, statistics, random |
| from pathlib import Path |
| R=Path("/var/lib/octave/sn114/repo") |
| feats={f["cid"]:f for f in json.load(open(R/"routable_feature.json"))} |
| per=json.load(open(R/"per_challenge_cap_effect.json")) |
| |
| |
| xs=sorted(per, key=lambda p: feats[p['cid']]['uniq_at_risk']) |
| n=len(xs); q=n//4 |
| out={'quartiles':[]} |
| for i in range(4): |
| grp=xs[i*q:(i+1)*q] if i<3 else xs[3*q:] |
| losers=sum(1 for p in grp if p['loss']>1e-9) |
| out['quartiles'].append({'quartile':i+1,'n':len(grp),'losers':losers, |
| 'loser_rate':round(losers/len(grp),4), |
| 'mean_uniq_at_risk':round(statistics.fmean([feats[p['cid']]['uniq_at_risk'] for p in grp]),1)}) |
| rates=[x['loser_rate'] for x in out['quartiles']] |
| out['rate_spread']=round(max(rates)-min(rates),4) |
| out['flat_prediction_holds']=bool(out['rate_spread']<0.20) |
| |
| L=[p for p in per if p['loss']>1e-9] |
| def corr(a,b): |
| ma,mb=statistics.fmean(a),statistics.fmean(b) |
| num=sum((x-ma)*(y-mb) for x,y in zip(a,b)) |
| da=sum((x-ma)**2 for x in a)**0.5; db=sum((y-mb)**2 for y in b)**0.5 |
| return num/(da*db) if da and db else 0.0 |
| out['corr_loss_vs_atrisk_among_losers']=round(corr([p['loss'] for p in L],[feats[p['cid']]['uniq_at_risk'] for p in L]),4) |
| json.dump(out, open(R/"base_rate_test.json","w"), indent=2) |
| for x in out['quartiles']: print(' Q%d n=%-4d mean at-risk %-7s losers %-3d rate %.4f'%(x['quartile'],x['n'],x['mean_uniq_at_risk'],x['losers'],x['loser_rate'])) |
| print() |
| print(' loser-rate spread across quartiles: %.4f flat prediction holds: %s'%(out['rate_spread'],out['flat_prediction_holds'])) |
| print(' corr(loss magnitude, at-risk volume) among the 21 losers: %+.4f'%out['corr_loss_vs_atrisk_among_losers']) |