"""Collect per-(method, target, seed) JSON results into a unified table.
Walks results/ for *.json files written by the training scripts and produces:
- results/summary.csv : per-method × target mean ± std table
- results/summary.tex : LaTeX-formatted version (paper table-ready)
Run after all jobs have finished:
python eval_collect.py --root results/
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from collections import defaultdict
import numpy as np
import pandas as pd
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--root", default="results/")
ap.add_argument("--out_csv", default="results/summary.csv")
ap.add_argument("--out_tex", default="results/summary.tex")
args = ap.parse_args()
rows = []
for path in Path(args.root).rglob("seed*.json"):
try:
with open(path) as fp:
data = json.load(fp)
rows.append(data)
except Exception as e:
print(f"[skip] {path}: {e}")
if not rows:
print("[warn] no results found.")
return
df = pd.DataFrame(rows)
grp = df.groupby(["method", "target"])
summary = grp.agg(
r2_mean=("r2", "mean"),
r2_std=("r2", "std"),
rmse_mean=("rmse", "mean"),
rmse_std=("rmse", "std"),
mae_mean=("mae", "mean"),
mae_std=("mae", "std"),
n_params=("n_params", "first"),
n_seeds=("seed", "count"),
).reset_index()
summary.to_csv(args.out_csv, index=False)
print(f"[ok] wrote {args.out_csv} with {len(summary)} rows")
with open(args.out_tex, "w") as fp:
fp.write("\\begin{tabular}{llrrrr}\n\\toprule\n")
fp.write("Method & Target & $R^2$ & RMSE & MAE & Params \\\\\n\\midrule\n")
for _, r in summary.iterrows():
fp.write(
f"{r['method']} & {r['target']} & "
f"{r['r2_mean']:.3f} $\\pm$ {r['r2_std']:.3f} & "
f"{r['rmse_mean']:.4g} & {r['mae_mean']:.4g} & "
f"{int(r['n_params'])} \\\\\n"
)
fp.write("\\bottomrule\n\\end{tabular}\n")
print(f"[ok] wrote {args.out_tex}")
if __name__ == "__main__":
main()