import pickle, json, sys, collections, numpy as np sys.path.insert(0,'code') from identity import decide_identity def load_labels(p): return {f['index']: f['label'] for f in json.load(open(p))['facings']} def feats(sc): r = sorted(sc.items(), key=lambda kv: -kv[1]) if not r: return None, 0.0, 0.0 top = r[0][1]; run = r[1][1] if len(r) > 1 else 0.0 return r[0][0], top, (top-run)/max(top,1.0) def analyze(run, labels, verbose=False): E = set(run['enrolled']); rows = [x for x in run['rows'] if labels[x['index']] != 'exclude'] T = lambda x: labels[x['index']] inc = [x for x in rows if T(x) != 'unknown']; ince = [x for x in inc if T(x) in E] unk = [x for x in rows if T(x) == 'unknown'] # identity ceiling: ungated argmax on enrolled in-catalog ranks = [] for x in ince: order = [k for k, _ in sorted(x['scores'].items(), key=lambda kv: -kv[1])] ranks.append(order.index(T(x))+1 if T(x) in order and x['scores'].get(T(x),0)>0 else 99) top1 = sum(r == 1 for r in ranks) # Van contract: argmax always arg_correct = top1; answered = sum(1 for x in rows if x['scores'] and max(x['scores'].values())>0) # current decision rule acc = collections.Counter(); c = w = wu = wi = 0 for x in rows: d = decide_identity(x['scores'], method='hybrid') b = d['best_sku'] if d['identity_level']=='accepted' else None if not b: continue acc[b]+=1 if b == T(x): c += 1 else: w += 1 if T(x)=='unknown': wu+=1 else: wi+=1 hub = max(acc.values())/sum(acc.values()) if acc else 0 out = dict(n=len(rows), in_catalog=len(inc), enrolled_in=len(ince), unknown=len(unk), identity_top1=f"{top1}/{len(ince)}={top1/max(1,len(ince)):.0%}", argmax_e2e=f"{arg_correct}/{len(inc)}={arg_correct/max(1,len(inc)):.0%}", argmax_precision=f"{arg_correct}/{answered}={arg_correct/max(1,answered):.0%}", gated=f"correct {c} wrong {w} (unk {wu}, in-cat {wi}) cov_enr {c/max(1,len(ince)):.0%} prec {c/max(1,c+w):.0%} hub {hub:.0%}", ms=round(float(np.median([x['ms'] for x in run['rows'] if x['ms']>0] or [0])),1)) return out, ranks def sweep(run, labels, feature='margin'): """Pareto of (correct accepted, precision) over a single threshold on a feature.""" E=set(run['enrolled']); rows=[x for x in run['rows'] if labels[x['index']]!='exclude'] pts=[] for x in rows: b,top,mar=feats(x['scores']); t=labels[x['index']] v={'margin':mar,'top':top,'both':min(mar/0.3, top/40)}[feature] pts.append((v, b==t and b is not None, b)) pts.sort(key=lambda p:-p[0]); res=[]; c=a=0 for v,ok,b in pts: a+=1; c+=ok; res.append((v,c,a,c/a)) return res if __name__=='__main__': labels=load_labels(sys.argv[1]) for p in sys.argv[2:]: r=pickle.load(open(p,'rb')); o,ranks=analyze(r,labels) print(p.split('/')[-1], json.dumps(o, ensure_ascii=False))