ROC Curve and AUC in Python: How They Are Calculated Step by Step
An ROC Curve plots the True Positive Rate against the False Positive Rate across all decision thresholds, with the AUC (Area Under the Curve) summarizing the classifier's overall discriminative power.
An ROC Curve (Receiver Operating Characteristic) is a graphical plot illustrating the diagnostic ability of a binary classifier across all possible classification thresholds. The AUC (Area Under the Curve) reduces this entire curve into a single scalar value ( to ) summarizing the model's overall class discrimination ability independent of any single threshold.
Think about an airport security guard with a sensitivity dial ranging from 'Flag Literally Everything' (threshold ) down to 'Flag Almost Nothing' (threshold ). At each dial setting, the guard achieves a different True Positive Rate (Recall) while generating a different number of False Positive Rates (False Alarms). The ROC curve maps out the complete trade-off frontier as that dial is turned.
1. Why ROC and AUC Are Essential
- Threshold Independence: Evaluates the model's intrinsic ranking ability before committing to a specific production decision boundary.
- Fair Model Comparison: Compares multiple competing classifiers across the entire spectrum of operating sensitivities.
- Clear Visual Diagnostics: Curves bulging toward the top-left corner identify superior sensitivity-to-false-alarm trade-offs.
2. ROC-AUC vs. Precision-Recall AUC (PR-AUC)
| Dimension | ROC Curve & AUC | Precision-Recall Curve (PR-AUC) |
|---|---|---|
| Plotted Axes | (-axis) vs. (-axis) | (-axis) vs. (-axis) |
| Includes True Negatives ()? | Yes: | No: Focuses strictly on the positive class. |
| Class Imbalance Sensitivity | Can appear overly optimistic if is massive. | Highly sensitive: Accurately reflects performance on rare positives. |
| Random Guess Baseline | Diagonal Line () | Horizontal Line at Positive Class Prevalence () |
| Optimal Use Case | Balanced binary classification tasks. | Heavy class imbalance (fraud, medical diagnosis, ad click prediction). |
3. The Mathematical Formulations
1. The Two Axes: TPR and FPR
2. AUC via the Trapezoidal Rule
Sorting the threshold points by increasing , total AUC is computed by summing the trapezoidal slices between consecutive points:
3. The Probabilistic Interpretation (Mann-Whitney U)
Mathematically, AUC equals the exact probability that a randomly chosen positive instance is assigned a higher predicted score than a randomly chosen negative instance:
An AUC of means that of the time, the model correctly ranks a true positive above a true negative.
4. Worked Numerical Example (By Hand)
Consider samples ( actual positives: A, B, E; actual negatives: C, D) with predicted probabilities:
| Sample | Actual Class () | Predicted Probability |
|---|---|---|
| A | 1 | 0.90 |
| B | 1 | 0.60 |
| C | 0 | 0.55 |
| D | 0 | 0.30 |
| E | 1 | 0.20 |
- Threshold : Flagged: A .
- Threshold : Flagged: A, B, C .
- Threshold : Flagged: All .
- Trapezoidal Sum: Slices yield:
5. Code: Python Implementation From Scratch & Scikit-Learn
1. NumPy ROC Sweep & Trapezoidal AUC Engine
import numpy as np
y_actual = np.array([1, 1, 0, 0, 1])
y_probs = np.array([0.90, 0.60, 0.55, 0.30, 0.20])
def compute_roc_points(y_true, y_score):
thresholds = np.sort(np.unique(y_score))[::-1]
thresholds = np.concatenate(([1.1], thresholds, [0.0]))
points = []
for t in thresholds:
y_pred = (y_score >= t).astype(int)
tp = np.sum((y_pred == 1) & (y_true == 1))
fn = np.sum((y_pred == 0) & (y_true == 1))
fp = np.sum((y_pred == 1) & (y_true == 0))
tn = np.sum((y_pred == 0) & (y_true == 0))
tpr = tp / (tp + fn) if (tp + fn) > 0 else 0.0
fpr = fp / (fp + tn) if (fp + tn) > 0 else 0.0
points.append((fpr, tpr))
return sorted(points)
def compute_auc(points):
auc = 0.0
for i in range(1, len(points)):
fpr_prev, tpr_prev = points[i - 1]
fpr_curr, tpr_curr = points[i]
width = fpr_curr - fpr_prev
avg_height = (tpr_curr + tpr_prev) / 2.0
auc += width * avg_height
return auc
points = compute_roc_points(y_actual, y_probs)
auc_val = compute_auc(points)
print("ROC Points (FPR, TPR):", [(round(f, 3), round(t, 3)) for f, t in points])
print(f"Calculated AUC: {auc_val:.3f}")2. Production Scikit-Learn & Optimal Threshold (Youden's J)
from sklearn.metrics import roc_curve, roc_auc_score
fpr, tpr, thresholds = roc_curve(y_actual, y_probs)
auc_score = roc_auc_score(y_actual, y_probs)
# Youden's J statistic finds the optimal threshold: max(TPR - FPR)
j_scores = tpr - fpr
best_idx = np.argmax(j_scores)
best_threshold = thresholds[best_idx]
print(f"Scikit-Learn AUC Score: {auc_score:.3f}")
print(f"Optimal Threshold (Youden's J): {best_threshold:.2f} (TPR={tpr[best_idx]:.2f}, FPR={fpr[best_idx]:.2f})")Summary
- The ROC Curve plots True Positive Rate vs. False Positive Rate across all possible probability thresholds.
- AUC (Area Under the Curve) measures overall class separation ( is perfect, is random guessing).
- AUC corresponds to the probability that a randomly chosen positive example ranks higher than a randomly chosen negative example.
- On heavily imbalanced datasets, Precision-Recall AUC (PR-AUC) provides a more reliable metric than ROC-AUC.
- Youden's J Statistic () helps identify the single most balanced operational threshold.
Common questions
What does an AUC of 0.5 mean?
An AUC of 0.5 means the classifier has no discriminative ability and performs identically to random coin flipping. An AUC of 1.0 represents perfect separation, while an AUC below 0.5 indicates inverse predictions.
Why use ROC-AUC instead of accuracy?
Accuracy depends on an arbitrary single threshold (usually 0.5) and fails on imbalanced data. ROC-AUC evaluates the classifier's overall ability to rank positive cases higher than negative cases across all possible thresholds.
When should I use Precision-Recall AUC (PR-AUC) instead of ROC-AUC?
Use PR-AUC when working with severely imbalanced datasets (e.g. fraud detection or rare medical diagnosis). ROC-AUC incorporates True Negatives, which can make a model look deceptively optimistic when negatives heavily outnumber positives.
What is Youden's J statistic?
Youden's J statistic (J = TPR - FPR) identifies the optimal single operating threshold on an ROC curve by finding the point that maximizes the difference between the True Positive Rate and False Positive Rate.