Approach: create deterministic small and large synthetic datasets covering edge cases, compute standard metrics with robust handling (treat undefined as 0 or np.nan per policy), and assert expected values or properties (monotonicity, bounds). Use sklearn for reproducibility.Example test datasets & expected outcomes:1) No positives in ground truth- y_true = [0,0,0,0]- y_score = [0.1,0.9,0.2,0.4] or y_pred all zerosExpected:- Precision: undefined (no predicted positives) → treat as 0 or assert sklearn returns 0 with zero_division=0- Recall: 0 (no true positives)- F1: 0- AUROC: 0.5 if scores vary (model no-skill); if no positive labels sklearn raises error — assert raised or handle.- AUPRC: undefined (no positives) — often 0 or undefined; assert behavior explicitly.2) Single positive among 1,000,000 negatives- y_true length = 1_000_001, one 1 at index 0- y_score all zeros except score[0]=1.0Case A: perfect ranking (positive highest)Expected:- Precision@k (k=1): 1.0- Recall: 1.0- F1: 1.0- AUROC: ~1.0 (perfect)- AUPRC: ~1.0Case B: model gives low score to positiveExpected:- Precision ~0 (very low)- Recall 0- AUROC can still be ~0.5 if scores random — misleading because class imbalance makes AUROC insensitive.3) Perfect predictions- y_true = [1,0,1,0], y_pred = [1,0,1,0], y_score alignedExpected: precision=recall=F1=1.0, AUROC=1.0, AUPRC=1.0.Which metrics informative vs misleading:- Precision/Recall/F1: informative when you evaluate at decision threshold or top-k; F1 may hide trade-offs — report precision and recall separately.- AUROC: can be misleading under extreme imbalance; it measures ranking across negatives and will remain high even if positive is ranked slightly above many negatives. Not sensitive to performance at top of ranking.- AUPRC: more informative for rare positives because it focuses on positive class performance; prefer AUPRC and precision@k.- For "no positives" cases, AUPRC and recall are undefined — tests must encode expected behavior (raise, NaN, or defined fallback).Automation encoding (example using sklearn + pytest):python
from sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score, average_precision_score
import numpy as np
import pytest
def test_no_positives():
y_true = np.zeros(4, dtype=int)
y_pred = np.zeros(4, dtype=int)
assert precision_score(y_true, y_pred, zero_division=0) == 0
assert recall_score(y_true, y_pred) == 0
assert f1_score(y_true, y_pred, zero_division=0) == 0
with pytest.raises(ValueError):
roc_auc_score(y_true, np.array([0.1,0.2,0.3,0.4]))
assert np.isnan(average_precision_score(y_true, np.array([0.1,0.2,0.3,0.4]))) or average_precision_score(y_true, np.array([0.1,0.2,0.3,0.4]))==0
def test_single_positive_perfect():
N=1_000_001
y_true = np.zeros(N, int); y_true[0]=1
scores = np.zeros(N); scores[0]=1.0
assert roc_auc_score(y_true, scores) == 1.0
assert average_precision_score(y_true, scores) == 1.0
Best practices:- Explicitly decide how to handle undefined metrics (raise vs fallback).- Assert metric ranges and monotonic properties rather than exact floats when large datasets cause numerical noise (use approx).- Include precision@k and calibration checks for practical relevance.