""" Validation-set threshold search to maximize F1 (default: toxic class). """ from __future__ import annotations import numpy as np from sklearn.metrics import f1_score def search_best_threshold( y_true: np.ndarray, probs: np.ndarray, *, metric: str = "f1_toxic", min_threshold: float = 0.05, max_threshold: float = 0.95, step: float = 0.01, ) -> tuple[float, float]: """ Grid-search classification threshold on validation probabilities. Returns (best_threshold, best_score). """ y = np.asarray(y_true).astype(int) p = np.asarray(probs, dtype=float) thresholds = np.arange(min_threshold, max_threshold + step / 2, step) best_t = 0.5 best_score = -1.0 average = "weighted" if metric == "f1_weighted" else "binary" pos_label = 1 for t in thresholds: preds = (p >= t).astype(int) if metric in ("f1_toxic", "f1_binary"): score = float(f1_score(y, preds, pos_label=pos_label, zero_division=0)) else: score = float( f1_score(y, preds, average=average, zero_division=0) ) if score > best_score: best_score = score best_t = float(t) return best_t, best_score def predict_with_threshold(probs: np.ndarray, threshold: float) -> np.ndarray: return (np.asarray(probs, dtype=float) >= threshold).astype(int)