Spaces:
Sleeping
Sleeping
| import numpy as np | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| from sklearn.pipeline import Pipeline | |
| from sklearn.metrics import ( | |
| confusion_matrix, | |
| ConfusionMatrixDisplay, | |
| precision_recall_curve, | |
| average_precision_score, | |
| ) | |
| def plot_confusion_matrix_argmax( | |
| y_true, | |
| y_pred, | |
| classes=None, | |
| normalize: str | None = "true", | |
| ): | |
| """ | |
| Confusion matrix for an argmax classifier. | |
| Returns (cm_df, fig). | |
| normalize: | |
| - "true": normalize rows | |
| - "pred", "all", or None for counts | |
| """ | |
| y_true = np.asarray(y_true).astype(str) | |
| y_pred = np.asarray(y_pred).astype(str) | |
| if classes is None: | |
| classes = sorted(set(y_true) | set(y_pred)) | |
| cm = confusion_matrix(y_true, y_pred, labels=classes, normalize=normalize) | |
| cm_df = pd.DataFrame(cm, index=classes, columns=classes) | |
| fig, ax = plt.subplots() | |
| ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=classes).plot( | |
| ax=ax, | |
| values_format=".2f" if normalize else "d", | |
| colorbar=True, | |
| ) | |
| ax.set_title("Confusion matrix" + (" (normalized by True label)" if normalize else " (counts)")) | |
| fig.tight_layout() | |
| return cm_df, fig | |
| def plot_pr_auc_macro_from_proba( | |
| y_true, | |
| proba: np.ndarray, | |
| classes, | |
| ): | |
| """ | |
| Compute macro-average AP (PR-AUC) for multiclass via one-vs-rest, and plot | |
| a macro-averaged PR curve. | |
| Inputs: | |
| y_true: array-like of shape (n,) | |
| proba: ndarray of shape (n, K) with predicted probabilities | |
| classes: list/array of length K matching columns of proba | |
| Returns: (macro_ap, fig) | |
| """ | |
| y_true = np.asarray(y_true).astype(str) | |
| proba = np.asarray(proba) | |
| classes = list(classes) | |
| if proba.ndim != 2 or proba.shape[0] != len(y_true) or proba.shape[1] != len(classes): | |
| raise ValueError(f"Shape mismatch: y_true={len(y_true)}, proba={proba.shape}, classes={len(classes)}") | |
| ap_list = [] | |
| precisions = [] | |
| recalls = [] | |
| for j, cls in enumerate(classes): | |
| y_bin = (y_true == cls).astype(int) | |
| if y_bin.sum() == 0: | |
| continue # class not present in eval set | |
| y_score = proba[:, j] | |
| ap_list.append(average_precision_score(y_bin, y_score)) | |
| p, r, _ = precision_recall_curve(y_bin, y_score) | |
| precisions.append(p) | |
| recalls.append(r) | |
| if not ap_list: | |
| raise ValueError("No classes in y_true had positive examples; cannot compute PR-AUC.") | |
| macro_ap = float(np.mean(ap_list)) | |
| # Macro PR curve by interpolating precision onto a common recall grid | |
| recall_grid = np.linspace(0, 1, 200) | |
| prec_on_grid = [] | |
| for p, r in zip(precisions, recalls): | |
| order = np.argsort(r) | |
| r_sorted = r[order] | |
| p_sorted = p[order] | |
| prec_on_grid.append( | |
| np.interp(recall_grid, r_sorted, p_sorted, left=p_sorted[0], right=p_sorted[-1]) | |
| ) | |
| macro_precision = np.mean(np.vstack(prec_on_grid), axis=0) | |
| fig, ax = plt.subplots() | |
| ax.plot(recall_grid, macro_precision) | |
| ax.set_xlim(0, 1) | |
| ax.set_ylim(0, 1) | |
| ax.set_xlabel("Recall") | |
| ax.set_ylabel("Precision") | |
| ax.set_title(f"Macro PR curve (macro AP = {macro_ap:.3f})") | |
| fig.tight_layout() | |
| return macro_ap, fig | |