"""Aggregate runs/*/metrics.json into results/summary_*.csv (mean ± std over folds).""" import glob import json import os import pandas as pd from common import ROOT, RUNS PAIRS = ["he->if", "if->he", "he->nuclei", "nuclei->he", "he->markers", "markers->he", "if->nuclei", "nuclei->if", "if->markers", "markers->if", "nuclei->markers", "markers->nuclei"] rows = [] for f in sorted(glob.glob(os.path.join(RUNS, "*", "metrics.json"))): m = json.load(open(f)) a = m["args"] for subset in ["test", "test_tissue"]: for pr in PAIRS: r = m[subset][pr] rows.append({"anchor": a.get("anchor", "imagebind"), "split": a["split"], "fold": a["fold"], "loss": a["loss"], "subset": subset, "pair": pr, "trained_directly": pr.startswith("he") or pr.endswith("he") or a["loss"] == "allpairs", **{k: r[k] for k in ["N", "chance_R@1", "R@1", "R@5", "R@10", "MRR", "MedR", "pair_acc", "R@1_g100", "pair_acc_g100"]}}) df = pd.DataFrame(rows) out = os.path.join(ROOT, "results") df.to_csv(os.path.join(out, "all_runs_long.csv"), index=False) met = ["R@1", "R@5", "R@10", "MRR", "pair_acc", "R@1_g100", "pair_acc_g100"] g = df.groupby(["anchor", "loss", "subset", "split", "pair"], sort=False) agg = g[met + ["N"]].mean() sd = g[met].std().fillna(0) tab = agg.copy() for c in met: tab[c] = [f"{x:.3f}±{s:.3f}" if n > 1 else f"{x:.3f}" for x, s, n in zip(agg[c], sd[c], g.size())] tab["n_folds"] = g.size() tab.reset_index().to_csv(os.path.join(out, "summary_by_pair.csv"), index=False) # compact headline: mean over the 12 directed pairs, separated into anchor-trained vs emergent pairs h = df.groupby(["anchor", "loss", "subset", "split", "fold", "trained_directly"])[met].mean().reset_index() h = h.groupby(["anchor", "loss", "subset", "split", "trained_directly"])[met].agg(["mean", "std"]).round(3) h.to_csv(os.path.join(out, "summary_headline.csv")) pd.set_option("display.width", 250) print(h[[("R@1", "mean"), ("R@1", "std"), ("R@1_g100", "mean"), ("pair_acc", "mean"), ("pair_acc_g100", "mean")]]) # H&E-encoder ablation (anchor loss, full test set): fixed-gallery R@1 per pair, mean over folds ab = df[(df.loss == "anchor") & (df.subset == "test")] fm = ab.pivot_table(index=["split", "pair"], columns="anchor", values="R@1_g100", aggfunc="mean").round(3) fm.to_csv(os.path.join(out, "anchor_ablation_R1_g100.csv")) fm2 = ab.pivot_table(index=["split", "pair"], columns="anchor", values="pair_acc", aggfunc="mean").round(3) fm2.to_csv(os.path.join(out, "anchor_ablation_pair_acc.csv"))