|
| 1 | +""" pyplots.ai |
| 2 | +roc-curve: ROC Curve with AUC |
| 3 | +Library: seaborn 0.13.2 | Python 3.13.11 |
| 4 | +Quality: 91/100 | Created: 2025-12-26 |
| 5 | +""" |
| 6 | + |
| 7 | +import matplotlib.pyplot as plt |
| 8 | +import numpy as np |
| 9 | +import seaborn as sns |
| 10 | + |
| 11 | + |
| 12 | +# Set random seed for reproducibility |
| 13 | +np.random.seed(42) |
| 14 | + |
| 15 | +# Generate synthetic classification data for three models with different performance levels |
| 16 | +n_samples = 1000 |
| 17 | + |
| 18 | +# True labels (binary) |
| 19 | +y_true = np.concatenate([np.zeros(500), np.ones(500)]) |
| 20 | + |
| 21 | +# Model 1: Good classifier (AUC ~0.92) |
| 22 | +y_scores_model1 = np.concatenate( |
| 23 | + [ |
| 24 | + np.random.beta(2, 5, 500), # Low scores for class 0 |
| 25 | + np.random.beta(5, 2, 500), # High scores for class 1 |
| 26 | + ] |
| 27 | +) |
| 28 | + |
| 29 | +# Model 2: Moderate classifier (AUC ~0.78) |
| 30 | +y_scores_model2 = np.concatenate([np.random.beta(2, 3, 500), np.random.beta(3, 2, 500)]) |
| 31 | + |
| 32 | +# Model 3: Weak classifier (AUC ~0.65) |
| 33 | +y_scores_model3 = np.concatenate([np.random.beta(2, 2.5, 500), np.random.beta(2.5, 2, 500)]) |
| 34 | + |
| 35 | +# Compute ROC curves manually at various thresholds |
| 36 | +n_thresholds = 200 |
| 37 | +thresholds = np.linspace(0, 1, n_thresholds) |
| 38 | + |
| 39 | +# Model 1 ROC |
| 40 | +tpr1, fpr1 = [], [] |
| 41 | +for thresh in thresholds: |
| 42 | + y_pred = (y_scores_model1 >= thresh).astype(int) |
| 43 | + tp = np.sum((y_pred == 1) & (y_true == 1)) |
| 44 | + fp = np.sum((y_pred == 1) & (y_true == 0)) |
| 45 | + fn = np.sum((y_pred == 0) & (y_true == 1)) |
| 46 | + tn = np.sum((y_pred == 0) & (y_true == 0)) |
| 47 | + tpr1.append(tp / (tp + fn) if (tp + fn) > 0 else 0) |
| 48 | + fpr1.append(fp / (fp + tn) if (fp + tn) > 0 else 0) |
| 49 | +fpr1, tpr1 = np.array(fpr1), np.array(tpr1) |
| 50 | + |
| 51 | +# Model 2 ROC |
| 52 | +tpr2, fpr2 = [], [] |
| 53 | +for thresh in thresholds: |
| 54 | + y_pred = (y_scores_model2 >= thresh).astype(int) |
| 55 | + tp = np.sum((y_pred == 1) & (y_true == 1)) |
| 56 | + fp = np.sum((y_pred == 1) & (y_true == 0)) |
| 57 | + fn = np.sum((y_pred == 0) & (y_true == 1)) |
| 58 | + tn = np.sum((y_pred == 0) & (y_true == 0)) |
| 59 | + tpr2.append(tp / (tp + fn) if (tp + fn) > 0 else 0) |
| 60 | + fpr2.append(fp / (fp + tn) if (fp + tn) > 0 else 0) |
| 61 | +fpr2, tpr2 = np.array(fpr2), np.array(tpr2) |
| 62 | + |
| 63 | +# Model 3 ROC |
| 64 | +tpr3, fpr3 = [], [] |
| 65 | +for thresh in thresholds: |
| 66 | + y_pred = (y_scores_model3 >= thresh).astype(int) |
| 67 | + tp = np.sum((y_pred == 1) & (y_true == 1)) |
| 68 | + fp = np.sum((y_pred == 1) & (y_true == 0)) |
| 69 | + fn = np.sum((y_pred == 0) & (y_true == 1)) |
| 70 | + tn = np.sum((y_pred == 0) & (y_true == 0)) |
| 71 | + tpr3.append(tp / (tp + fn) if (tp + fn) > 0 else 0) |
| 72 | + fpr3.append(fp / (fp + tn) if (fp + tn) > 0 else 0) |
| 73 | +fpr3, tpr3 = np.array(fpr3), np.array(tpr3) |
| 74 | + |
| 75 | +# Calculate AUC scores using trapezoidal rule |
| 76 | +idx1 = np.argsort(fpr1) |
| 77 | +auc1 = np.trapezoid(tpr1[idx1], fpr1[idx1]) |
| 78 | +idx2 = np.argsort(fpr2) |
| 79 | +auc2 = np.trapezoid(tpr2[idx2], fpr2[idx2]) |
| 80 | +idx3 = np.argsort(fpr3) |
| 81 | +auc3 = np.trapezoid(tpr3[idx3], fpr3[idx3]) |
| 82 | + |
| 83 | +# Set seaborn style |
| 84 | +sns.set_style("whitegrid") |
| 85 | +sns.set_context("talk", font_scale=1.2) |
| 86 | + |
| 87 | +# Create figure |
| 88 | +fig, ax = plt.subplots(figsize=(16, 9)) |
| 89 | + |
| 90 | +# Plot ROC curves using seaborn lineplot |
| 91 | +sns.lineplot(x=fpr1, y=tpr1, ax=ax, linewidth=3.5, color="#306998", label=f"Random Forest (AUC = {auc1:.3f})") |
| 92 | +sns.lineplot(x=fpr2, y=tpr2, ax=ax, linewidth=3.5, color="#FFD43B", label=f"Logistic Regression (AUC = {auc2:.3f})") |
| 93 | +sns.lineplot(x=fpr3, y=tpr3, ax=ax, linewidth=3.5, color="#E74C3C", label=f"Decision Tree (AUC = {auc3:.3f})") |
| 94 | + |
| 95 | +# Diagonal reference line (random classifier) |
| 96 | +ax.plot([0, 1], [0, 1], linestyle="--", linewidth=2.5, color="#7F8C8D", label="Random Classifier (AUC = 0.500)") |
| 97 | + |
| 98 | +# Styling |
| 99 | +ax.set_xlabel("False Positive Rate (FPR)", fontsize=22) |
| 100 | +ax.set_ylabel("True Positive Rate (TPR)", fontsize=22) |
| 101 | +ax.set_title("roc-curve · seaborn · pyplots.ai", fontsize=26, fontweight="bold") |
| 102 | +ax.tick_params(axis="both", labelsize=18) |
| 103 | + |
| 104 | +# Set axis limits and aspect |
| 105 | +ax.set_xlim([-0.02, 1.02]) |
| 106 | +ax.set_ylim([-0.02, 1.02]) |
| 107 | +ax.set_aspect("equal", adjustable="box") |
| 108 | + |
| 109 | +# Legend |
| 110 | +ax.legend(loc="lower right", fontsize=18, framealpha=0.95) |
| 111 | + |
| 112 | +# Grid styling |
| 113 | +ax.grid(True, alpha=0.3, linestyle="--") |
| 114 | + |
| 115 | +plt.tight_layout() |
| 116 | +plt.savefig("plot.png", dpi=300, bbox_inches="tight") |
0 commit comments