Machine Learning Foundations

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:

Text
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 flagged

How the curve is drawn

  1. Start strict — at a threshold above every score, nothing is flagged: point (0, 0).
  2. 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).
  3. 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:

Python
import numpy as npfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import roc_curverng = np.random.default_rng(0)n = 30_000y = (rng.random(n) < 0.02).astype(int)X = rng.normal(size=(n, 5)) + 1.0 * y[:, None]X_tr, X_te, y_tr, y_te = train_test_split(X, y, stratify=y, random_state=0)proba = LogisticRegression().fit(X_tr, y_tr).predict_proba(X_te)[:, 1]fpr, tpr, thresholds = roc_curve(y_te, proba)for max_fpr in [0.01, 0.05, 0.20]:    i = np.searchsorted(fpr, max_fpr, side="right") - 1   # last point within budget    print(f"FPR <= {max_fpr:.2f}: TPR = {tpr[i]:.2f} at threshold {thresholds[i]:.3f}")
Text
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.011

Each 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

ShapeMeaning
Hugs the top-left cornerStrong separation — most positives caught at a low FPR
Close to the diagonalWeak model — little better than random
Below the diagonalScores 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.