deepdetection / src /training /metrics.py
akagtag's picture
Initial commit
4e75170
"""src/training/metrics.py — Shared metric computation utilities."""
from __future__ import annotations
import numpy as np
from sklearn.metrics import (
roc_auc_score, f1_score, accuracy_score,
precision_score, recall_score, average_precision_score,
roc_curve,
)
def compute_auc(y_true: list, y_scores: list) -> float:
if len(set(y_true)) < 2:
return 0.5
return float(roc_auc_score(y_true, y_scores))
def compute_eer(y_true: list, y_scores: list) -> float:
if len(set(y_true)) < 2:
return 0.5
fpr, tpr, _ = roc_curve(y_true, y_scores)
idx = int(np.argmin(np.abs(fpr - (1 - tpr))))
return float(fpr[idx])
def optimal_threshold(y_true: list, y_scores: list) -> float:
"""Threshold that maximises F1 on the provided set."""
from sklearn.metrics import precision_recall_curve
precision, recall, thresholds = precision_recall_curve(y_true, y_scores)
f1 = 2 * precision * recall / (precision + recall + 1e-8)
best = int(np.argmax(f1[:-1]))
return float(thresholds[best])
def compute_all(
y_true: list,
y_scores: list,
threshold: float = 0.5,
) -> dict:
y_pred = (np.array(y_scores) >= threshold).astype(int)
return {
"auc": compute_auc(y_true, y_scores),
"auc_pr": float(average_precision_score(y_true, y_scores)) if len(set(y_true)) > 1 else 0.5,
"eer": compute_eer(y_true, y_scores),
"f1": float(f1_score(y_true, y_pred, zero_division=0)),
"accuracy": float(accuracy_score(y_true, y_pred)),
"precision": float(precision_score(y_true, y_pred, zero_division=0)),
"recall": float(recall_score(y_true, y_pred, zero_division=0)),
"threshold": threshold,
}