Course Content
Machine Learning Foundations
14 sections · 70 lessons
What does the ROC curve represent intuitively?
What you need to know
The ROC curve has two axes, both rates between 0 and 1:
y-axis: true positive rate (TPR, recall) = TP / (TP + FN) share of positives caughtx-axis: false positive rate (FPR) = FP / (FP + TN) share of negatives wrongly flaggedHow the curve is drawn
- Start strict — at a threshold above every score, nothing is flagged: point (0, 0).
- Lower the threshold step by step — each case that crosses the line moves the point up (if it is a positive) or right (if it is a negative).
- End permissive — at a threshold below every score, everything is flagged: point (1, 1).
A good model has its positives near the top of the score list, so the curve first climbs steeply (catching positives) before it moves right (flagging negatives). A random model climbs and moves right at the same pace, tracing the diagonal: to catch 60% of positives it must flag 60% of negatives.
Reading points off the curve
roc_curve returns every point with its threshold, so you can ask practical questions:
1import numpy as np2from sklearn.linear_model import LogisticRegression3from sklearn.model_selection import train_test_split4from sklearn.metrics import roc_curve56rng = np.random.default_rng(0)7n = 30_0008y = (rng.random(n) < 0.02).astype(int)9X = rng.normal(size=(n, 5)) + 1.0 * y[:, None]10X_tr, X_te, y_tr, y_te = train_test_split(X, y, stratify=y, random_state=0)11proba = LogisticRegression().fit(X_tr, y_tr).predict_proba(X_te)[:, 1]1213fpr, tpr, thresholds = roc_curve(y_te, proba)14for max_fpr in [0.01, 0.05, 0.20]:15 i = np.searchsorted(fpr, max_fpr, side="right") - 1 # last point within budget16 print(f"FPR <= {max_fpr:.2f}: TPR = {tpr[i]:.2f} at threshold {thresholds[i]:.3f}")FPR <= 0.01: TPR = 0.44 at threshold 0.240FPR <= 0.05: TPR = 0.73 at threshold 0.066FPR <= 0.20: TPR = 0.96 at threshold 0.011Each line is a business option. "If we accept wrongly flagging 1% of genuine payments, we catch 44% of fraud. If we accept 5%, we catch 73%." The curve is simply all of these options joined together.
Three curve shapes to recognise
| Shape | Meaning |
|---|---|
| Hugs the top-left corner | Strong separation — most positives caught at a low FPR |
| Close to the diagonal | Weak model — little better than random |
| Below the diagonal | Scores are reversed; check labels or the sign of the score |
A warning about the x-axis
FPR is a rate among negatives. When negatives are huge in number, a small FPR can still be a lot of cases. In the output above, 1% FPR on 7,352 genuine payments is about 73 false alarms — against 65 frauds caught (44% of 148). In a bank with 50 lakh payments a day, 1% FPR is 50,000 wrongly flagged payments. That is why, for rare positives, teams also look at the precision–recall curve.
A real-life example
An email provider tests a new phishing detector. Product managers say at most 0.1% of genuine emails may be moved to the warning folder. The ML engineer reads the ROC curve at FPR = 0.001 and sees TPR = 0.62 for the old model and 0.81 for the new one. That single vertical slice of the curve — not the overall AUC — is the number that goes into the launch review, because it is the only part of the curve the product will ever operate in.
Follow-up questions to expect
- "What is the point (0, 1)?" — The perfect classifier: all positives caught with no false alarms.
- "Why is FPR used instead of precision on the x-axis?" — FPR and TPR are each computed within one class, so the ROC curve does not change with class balance. Precision mixes both classes, which is what the PR curve shows.
- "How do you choose a threshold from the ROC curve?" — Fix the FPR the business can tolerate and read off the threshold, or use Youden's J (TPR minus FPR) when costs are equal.