fix:批量修复了一些问题
This commit is contained in:
+43
-9
@@ -25,6 +25,10 @@ async def settle_prediction(prediction_id: int, home_goals: int, away_goals: int
|
||||
pred.actual_home_goals = home_goals
|
||||
pred.actual_away_goals = away_goals
|
||||
pred.settled = True
|
||||
logger.info(
|
||||
"结算完成 prediction_id=%s match=%s actual=%s:%s mode=%s",
|
||||
prediction_id, pred.match_id, home_goals, away_goals, pred.mode or "single",
|
||||
)
|
||||
return pred
|
||||
|
||||
|
||||
@@ -109,8 +113,14 @@ async def get_eval_summary(
|
||||
rows = list((await session.execute(stmt)).scalars().all())
|
||||
|
||||
from collections import defaultdict
|
||||
buckets: dict[tuple[str, str], dict] = defaultdict(lambda: {
|
||||
buckets: dict[tuple[str, str, str], dict] = defaultdict(lambda: {
|
||||
"total": 0, "correct_1x2": 0, "score_errors": [], "conf_sum": 0.0, "conf_count": 0,
|
||||
# 置信度校准分桶(仅 settled 且 pred 完整者计入)
|
||||
"conf_buckets": {
|
||||
"low(0-0.5)": {"total": 0, "correct": 0},
|
||||
"medium(0.5-0.7)": {"total": 0, "correct": 0},
|
||||
"high(0.7-1)": {"total": 0, "correct": 0},
|
||||
},
|
||||
})
|
||||
evaluated = 0
|
||||
skipped_incomplete = 0
|
||||
@@ -118,35 +128,59 @@ async def get_eval_summary(
|
||||
if (p.pred_home_goals is None or p.pred_away_goals is None or p.pred_1x2 is None):
|
||||
skipped_incomplete += 1
|
||||
continue
|
||||
key = (p.provider, p.model)
|
||||
key = (p.provider, p.model, p.prompt_version or "")
|
||||
b = buckets[key]
|
||||
b["total"] += 1
|
||||
evaluated += 1
|
||||
if p.actual_home_goals is None or p.actual_away_goals is None:
|
||||
continue
|
||||
actual = _actual_1x2(p.actual_home_goals, p.actual_away_goals)
|
||||
if p.pred_1x2 == actual:
|
||||
b["correct_1x2"] += 1
|
||||
if p.pred_home_goals is not None and p.pred_away_goals is not None:
|
||||
|
||||
correct = False
|
||||
if p.actual_home_goals is not None and p.actual_away_goals is not None:
|
||||
actual = _actual_1x2(p.actual_home_goals, p.actual_away_goals)
|
||||
if p.pred_1x2 == actual:
|
||||
b["correct_1x2"] += 1
|
||||
correct = True
|
||||
if (
|
||||
p.pred_home_goals is not None and p.pred_away_goals is not None
|
||||
and p.actual_home_goals is not None and p.actual_away_goals is not None
|
||||
):
|
||||
err = ((p.pred_home_goals - p.actual_home_goals) ** 2 +
|
||||
(p.pred_away_goals - p.actual_away_goals) ** 2) ** 0.5
|
||||
b["score_errors"].append(err)
|
||||
if p.subjective_confidence is not None:
|
||||
b["conf_sum"] += p.subjective_confidence
|
||||
b["conf_count"] += 1
|
||||
# 仅当有实际结果可用于校准时,才落入置信度分桶
|
||||
if p.actual_home_goals is not None and p.actual_away_goals is not None:
|
||||
conf = p.subjective_confidence
|
||||
if conf < 0.5:
|
||||
bucket = "low(0-0.5)"
|
||||
elif conf < 0.7:
|
||||
bucket = "medium(0.5-0.7)"
|
||||
else:
|
||||
bucket = "high(0.7-1)"
|
||||
b["conf_buckets"][bucket]["total"] += 1
|
||||
if correct:
|
||||
b["conf_buckets"][bucket]["correct"] += 1
|
||||
|
||||
summary = []
|
||||
for (prov, model), b in sorted(buckets.items()):
|
||||
for (prov, model, ver), b in sorted(buckets.items()):
|
||||
acc = (b["correct_1x2"] / b["total"] * 100) if b["total"] else 0
|
||||
avg_err = (sum(b["score_errors"]) / len(b["score_errors"])) if b["score_errors"] else None
|
||||
avg_conf = (b["conf_sum"] / b["conf_count"]) if b["conf_count"] else None
|
||||
# 校准分桶 → 命中率
|
||||
calibration = {}
|
||||
for name, cb in b["conf_buckets"].items():
|
||||
hit_rate = round(cb["correct"] / cb["total"] * 100, 1) if cb["total"] else None
|
||||
calibration[name] = {"total": cb["total"], "hit_rate": hit_rate}
|
||||
summary.append({
|
||||
"provider": prov,
|
||||
"model": model,
|
||||
"prompt_version": ver or None,
|
||||
"total": b["total"],
|
||||
"accuracy_1x2": round(acc, 1),
|
||||
"avg_score_rmse": round(avg_err, 2) if avg_err is not None else None,
|
||||
"avg_subjective_confidence": round(avg_conf, 2) if avg_conf is not None else None,
|
||||
"calibration": calibration,
|
||||
})
|
||||
return {
|
||||
"summary": summary,
|
||||
|
||||
Reference in New Issue
Block a user