from __future__ import annotations import argparse import csv import json from pathlib import Path from sklearn.metrics import ( accuracy_score, classification_report, confusion_matrix, f1_score, ) from src import LABEL2ID, predict LABELS = list(LABEL2ID.keys()) def load_jsonl(path: Path) -> list[dict]: rows = [] with path.open(encoding="utf-8") as f: for line_no, line in enumerate(f, start=1): if not line.strip(): continue row = json.loads(line) missing = { "example_id", "parent_text", "current_text", "gold_label", } - set(row) if missing: raise ValueError( f"{path}:{line_no} missing fields: {sorted(missing)}" ) if row["gold_label"] not in LABEL2ID: raise ValueError( f"{path}:{line_no} invalid label: {row['gold_label']}" ) rows.append(row) return rows def evaluate( dataset_path: Path, checkpoint_dir: str, output_csv: Path, ) -> dict: rows = load_jsonl(dataset_path) y_true = [] y_pred = [] predictions = [] for row in rows: pred = predict( text=row["current_text"], parent_text=row.get("parent_text", ""), checkpoint_dir=checkpoint_dir, ) gold = row["gold_label"] y_true.append(gold) y_pred.append(pred) predictions.append({ **row, "pred_label": pred, "correct": gold == pred, }) output_csv.parent.mkdir(parents=True, exist_ok=True) fieldnames = [] for prediction in predictions: for key in prediction: if key not in fieldnames: fieldnames.append(key) with output_csv.open("w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(predictions) report = classification_report( y_true, y_pred, labels=LABELS, zero_division=0, output_dict=True, ) matrix = confusion_matrix(y_true, y_pred, labels=LABELS) return { "n_examples": len(rows), "accuracy": accuracy_score(y_true, y_pred), "macro_f1": f1_score(y_true, y_pred, labels=LABELS, average="macro"), "classification_report": report, "confusion_matrix": { "labels": LABELS, "matrix": matrix.tolist(), }, "predictions_csv": str(output_csv), } def main() -> None: parser = argparse.ArgumentParser( description="Evaluate the argument role classifier on a custom JSONL set." ) parser.add_argument( "--dataset", default="evaluation/custom_argument_eval.jsonl", type=Path, ) parser.add_argument("--checkpoint", default="models/best") parser.add_argument( "--output-csv", default="evaluation/custom_argument_eval_predictions.csv", type=Path, ) parser.add_argument( "--output-json", default="evaluation/custom_argument_eval_metrics.json", type=Path, ) args = parser.parse_args() metrics = evaluate(args.dataset, args.checkpoint, args.output_csv) args.output_json.write_text( json.dumps(metrics, indent=2), encoding="utf-8", ) print(f"Examples: {metrics['n_examples']}") print(f"Accuracy: {metrics['accuracy']:.4f}") print(f"Macro-F1: {metrics['macro_f1']:.4f}") print("\nClassification report:") print( classification_report( [r["gold_label"] for r in load_jsonl(args.dataset)], [ r["pred_label"] for r in csv.DictReader( args.output_csv.open(encoding="utf-8") ) ], labels=LABELS, zero_division=0, ) ) print(f"Saved predictions to {args.output_csv}") print(f"Saved metrics to {args.output_json}") if __name__ == "__main__": main()