Spaces:
Sleeping
Sleeping
| """ | |
| Evaluation metrics module. | |
| Computes accuracy, precision, recall, F1 (macro and per-class). | |
| """ | |
| from typing import Optional | |
| import numpy as np | |
| from sklearn.metrics import ( | |
| accuracy_score, | |
| precision_score, | |
| recall_score, | |
| f1_score, | |
| classification_report, | |
| confusion_matrix, | |
| ) | |
| def compute_metrics( | |
| y_true: list[int], | |
| y_pred: list[int], | |
| class_names: Optional[list[str]] = None, | |
| average: str = 'macro', | |
| ) -> dict: | |
| """ | |
| Compute comprehensive classification metrics. | |
| Returns: | |
| dict with accuracy, macro/weighted F1, precision, recall, | |
| per-class metrics, and classification report. | |
| """ | |
| y_true = np.array(y_true) | |
| y_pred = np.array(y_pred) | |
| metrics = { | |
| 'accuracy': float(accuracy_score(y_true, y_pred)), | |
| 'macro_precision': float(precision_score(y_true, y_pred, average='macro', zero_division=0)), | |
| 'macro_recall': float(recall_score(y_true, y_pred, average='macro', zero_division=0)), | |
| 'macro_f1': float(f1_score(y_true, y_pred, average='macro', zero_division=0)), | |
| 'weighted_precision': float(precision_score(y_true, y_pred, average='weighted', zero_division=0)), | |
| 'weighted_recall': float(recall_score(y_true, y_pred, average='weighted', zero_division=0)), | |
| 'weighted_f1': float(f1_score(y_true, y_pred, average='weighted', zero_division=0)), | |
| } | |
| # Per-class metrics | |
| per_class_precision = precision_score(y_true, y_pred, average=None, zero_division=0) | |
| per_class_recall = recall_score(y_true, y_pred, average=None, zero_division=0) | |
| per_class_f1 = f1_score(y_true, y_pred, average=None, zero_division=0) | |
| per_class = {} | |
| for i, f1_val in enumerate(per_class_f1): | |
| name = class_names[i] if class_names and i < len(class_names) else str(i) | |
| per_class[name] = { | |
| 'precision': float(per_class_precision[i]), | |
| 'recall': float(per_class_recall[i]), | |
| 'f1': float(f1_val), | |
| 'support': int(np.sum(y_true == i)), | |
| } | |
| metrics['per_class'] = per_class | |
| # Confusion matrix | |
| cm = confusion_matrix(y_true, y_pred) | |
| metrics['confusion_matrix'] = cm.tolist() | |
| # Classification report string | |
| if class_names: | |
| report = classification_report( | |
| y_true, y_pred, target_names=class_names, zero_division=0, | |
| ) | |
| else: | |
| report = classification_report(y_true, y_pred, zero_division=0) | |
| metrics['classification_report'] = report | |
| return metrics | |
| def compute_top_k_accuracy( | |
| probabilities: list[list[float]], | |
| y_true: list[int], | |
| k: int = 3, | |
| ) -> float: | |
| """Compute top-k accuracy from probability distributions.""" | |
| correct = 0 | |
| for probs, true_label in zip(probabilities, y_true): | |
| top_k_preds = np.argsort(probs)[-k:] | |
| if true_label in top_k_preds: | |
| correct += 1 | |
| return correct / len(y_true) if y_true else 0.0 | |