Spaces:
Paused
Paused
File size: 4,468 Bytes
f66643d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | """Gom các report JSON (layout/OCR + formula) thành CSV để phân tích / vẽ biểu đồ.
Đọc report của eval_layout.py và eval_formula.py, làm phẳng mọi metric theo từng
lát cắt (slice) và xuất:
* <out>_long.csv : (report, slice, metric, value) -- tiện nhóm/vẽ.
* <out>_wide.csv : mỗi hàng = 1 slice, mỗi cột = "<report>.<metric>".
Ví dụ
-----
# chạy từ benchmark/parser/
python evaluation/aggregate_reports.py \
--layout fine=eval_results/eval_report_fine.json \
--layout merged=eval_results/eval_report_merged.json \
--formula eval_results/eval_report_formula.json \
--report table=eval_results/eval_report_table.json \
--out eval_results/eval_summary
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import pandas as pd
def flatten(d: dict, prefix: str = "") -> dict:
"""Làm phẳng dict lồng nhau -> {'a.b.c': value} (bỏ qua list)."""
out = {}
for k, v in d.items():
key = f"{prefix}{k}"
if isinstance(v, dict):
out.update(flatten(v, key + "."))
elif isinstance(v, list):
continue
else:
out[key] = v
return out
def rows_from_report(name: str, path: Path):
rep = json.load(open(path, encoding="utf-8"))
rows = []
for slice_key, metrics in rep["slices"].items():
flat = flatten(metrics)
for metric, value in flat.items():
rows.append({"report": name, "slice": slice_key,
"metric": metric, "value": value})
return rows
def parse_kv(s: str, default_name: str) -> tuple[str, Path]:
if "=" in s:
name, path = s.split("=", 1)
return name, Path(path)
return default_name, Path(s)
def parse_args():
ap = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--layout", action="append", default=[],
help="report layout, dạng name=path (lặp nhiều lần). "
"VD: fine=../../eval_report_fine.json")
ap.add_argument("--formula", action="append", default=[],
help="report formula, dạng [name=]path (lặp nhiều lần).")
ap.add_argument("--report", action="append", default=[],
help="report BẤT KỲ (table/cdm/…), dạng name=path (lặp nhiều lần).")
ap.add_argument("--out", type=Path, required=True,
help="Tiền tố file ra: <out>_long.csv và <out>_wide.csv")
return ap.parse_args()
def main() -> int:
args = parse_args()
rows = []
for spec in args.layout:
name, path = parse_kv(spec, "layout")
rows += rows_from_report(f"layout_{name}", path)
for spec in args.formula:
name, path = parse_kv(spec, "formula")
rows += rows_from_report(name if "=" in spec else "formula", path)
for spec in args.report:
name, path = parse_kv(spec, "report")
rows += rows_from_report(name, path)
if not rows:
print("Không có report nào. Truyền --layout/--formula.")
return 1
df = pd.DataFrame(rows)
long_path = args.out.with_name(args.out.name + "_long.csv")
df.to_csv(long_path, index=False)
# wide: slice x (report.metric)
df["col"] = df["report"] + "." + df["metric"]
wide = df.pivot_table(index="slice", columns="col", values="value", aggfunc="first")
# đưa 'all' lên đầu
order = ["all"] + sorted(s for s in wide.index if s != "all")
wide = wide.reindex([s for s in order if s in wide.index])
wide_path = args.out.with_name(args.out.name + "_wide.csv")
wide.to_csv(wide_path)
print(f"[aggregate] {len(rows)} dòng metric, {df['slice'].nunique()} slice, "
f"{df['report'].nunique()} report")
print(f" long -> {long_path}")
print(f" wide -> {wide_path}")
# in nhanh vài cột chính cho 'all'
key_cols = [c for c in wide.columns if any(
k in c for k in ("f1@0.5", "CER", "WER", "reading_order.edit_distance_mean",
"coverage", "edit_matched_micro"))]
if "all" in wide.index and key_cols:
print("\n[all] các cột chính:")
for c in sorted(key_cols):
print(f" {c:45s} {wide.loc['all', c]}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
|