czty's picture
Add files using upload-large-folder tool
b2c86fd verified
Raw
History Blame Contribute Delete
6.01 kB
import argparse
import csv
import json
import os
import re
from pathlib import Path
DEFAULT_FILE = (
"/225040511/project/Biomni-ReAct/LAB-bench/"
"cloningscenarios_cloning_20260524_163903/cloningscenarios_results.jsonl"
)
def normalize_choice(value):
"""Return the first A-E option from a model/gold answer string."""
if value is None:
return ""
text = str(value).strip().upper()
if text in {"A", "B", "C", "D", "E"}:
return text
match = re.search(r"\b([A-E])\b", text)
return match.group(1) if match else text
def compute_accuracy_from_jsonl(file_path, print_errors=False, dedup=True):
"""
从 JSONL 文件中读取数据,计算 agent_answer 与 answer 的准确率。
Args:
file_path (str): JSONL 文件路径。
print_errors (bool): 是否打印错误条目。
dedup (bool): 是否按 task_id/id 去重,保留最后一次结果。
Returns:
dict: accuracy/count/error metrics.
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"文件不存在: {file_path}")
records = []
seen = {}
duplicate_count = 0
with open(file_path, "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
except json.JSONDecodeError as e:
print(f"警告: 第 {line_num} 行 JSON 解析错误: {e},跳过")
continue
data["_line_num"] = line_num
key = data.get("task_id") or data.get("id")
if dedup and key:
if key in seen:
duplicate_count += 1
seen[key] = data
else:
records.append(data)
if dedup:
records = list(seen.values()) + records
correct = 0
total = 0
missing_answer = 0
error_count = 0
error_records = []
for data in records:
line_num = data.get("_line_num", "N/A")
answer = normalize_choice(data.get("answer"))
agent_answer = normalize_choice(data.get("agent_answer"))
if not answer:
print(f"警告: 第 {line_num} 行缺少 'answer' 字段,跳过")
continue
total += 1
if not agent_answer:
missing_answer += 1
if data.get("error"):
error_count += 1
if answer == agent_answer:
correct += 1
else:
error_records.append(
{
"line_num": line_num,
"task_id": data.get("task_id", data.get("id", "N/A")),
"answer": answer,
"agent_answer": agent_answer,
"error": data.get("error", ""),
"question": data.get("question", "N/A"),
}
)
accuracy = correct / total if total > 0 else 0.0
metrics = {
"file": str(file_path),
"total": total,
"correct": correct,
"wrong": total - correct,
"accuracy": accuracy,
"accuracy_percent": accuracy * 100,
"missing_agent_answer": missing_answer,
"error_count": error_count,
"duplicate_count": duplicate_count,
"error_records": error_records,
}
if print_errors and error_records:
print("\n" + "="*80)
print("错误条目列表 (answer != agent_answer):")
print("="*80)
for idx, err in enumerate(error_records, 1):
print(f"[{idx:03d}] 行号: {err['line_num']}")
print(f" Task ID: {err['task_id']}")
print(f" 问题: {err['question'][:100]}..." if len(err['question']) > 100 else f" 问题: {err['question']}")
print(f" 正确答案: {err['answer']}")
print(f" Agent答案: {err['agent_answer']}")
if err["error"]:
print(f" Error: {err['error']}")
print("-"*80)
return metrics
def print_metrics(metrics):
print(f"\n文件: {metrics['file']}")
print(f"总样本数: {metrics['total']}")
print(f"正确数: {metrics['correct']}")
print(f"错误数: {metrics['wrong']}")
print(f"准确率: {metrics['accuracy']:.4f} ({metrics['accuracy_percent']:.2f}%)")
print(f"空答案数: {metrics['missing_agent_answer']}")
print(f"带 error 字段数: {metrics['error_count']}")
print(f"重复 task_id 行数: {metrics['duplicate_count']}")
def write_error_csv(metrics, out_path):
fields = ["line_num", "task_id", "answer", "agent_answer", "error", "question"]
out_path = Path(out_path)
out_path.parent.mkdir(parents=True, exist_ok=True)
with out_path.open("w", encoding="utf-8", newline="") as handle:
writer = csv.DictWriter(handle, fieldnames=fields)
writer.writeheader()
writer.writerows(metrics["error_records"])
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Calculate LAB-Bench MCQ accuracy from JSONL results.")
parser.add_argument("file", nargs="?", default=DEFAULT_FILE, help="Path to *_results.jsonl.")
parser.add_argument("--print-errors", action="store_true", help="Print wrong records.")
parser.add_argument("--no-dedup", action="store_true", help="Do not deduplicate by task_id/id.")
parser.add_argument("--error-csv", default="", help="Optional CSV path for wrong records.")
args = parser.parse_args()
try:
metrics = compute_accuracy_from_jsonl(
args.file,
print_errors=args.print_errors,
dedup=not args.no_dedup,
)
print_metrics(metrics)
if args.error_csv:
write_error_csv(metrics, args.error_csv)
print(f"\n错误样本 CSV 已保存: {args.error_csv}")
except FileNotFoundError as e:
print(f"错误: {e}")
except Exception as e:
print(f"发生未预期的错误: {e}")