Precision-Recall Curves
A precision-recall curve plots precision against recall for every possible threshold, and each point is one threshold's trade-off.
Why One Threshold Hides the Trade-Off
Many classifiers do not answer yes or no directly. They output a score for each sample, and a threshold turns that score into a decision: scores above the threshold are called positive, and scores below it are called negative. Change the threshold and the decisions change, so a single set of predictions tells you only one story about the model.
The right threshold is often unknown when a model is first built. The threshold can also be set to meet a target. If a business needs to miss fewer than 10% of positive samples, it needs a recall of 90%. The difficulty is that a threshold which reaches that target may leave the model with poor precision. The source makes the extreme case concrete: if everything is classified as positive, recall is 100%, but the model is useless.
A precision-recall curve plots precision against recall for every possible threshold, so each point on it is one threshold's trade-off. In this article you will first see how precision and recall move as the threshold changes, then learn how the curve is computed, and finally how to choose an operating point and compare two classifiers.
Stepping Through a Threshold Sweep
What do you think happens?
Imagine lowering the threshold step by step from 0.9 down to 0.2. Each lower threshold makes the model label more samples as positive. Can recall go down under that change? Should precision keep rising, keep falling, or do something else?
Reveal answer
Recall never decreases; precision moves in both directions
Lowering the threshold labels more samples as positive, which can only catch more of the actual positives, so recall cannot go down. Precision, the share of predicted positives that are correct, does not follow a single direction in the printed sweep.
The verified printed output lists one threshold per line together with the precision and recall obtained at that threshold. The table below restates those values so you can read them side by side. Read them one row at a time, starting from the highest threshold.
| Threshold | Recall | Precision |
|---|---|---|
| 0.9 | 0.333 | 1.000 |
| 0.8 | 0.333 | 0.500 |
| 0.7 | 0.667 | 0.667 |
| 0.6 | 1.000 | 0.750 |
| 0.4 | 1.000 | 0.600 |
| 0.2 | 1.000 | 0.500 |
Printed threshold sweep. Each row is one threshold and the precision and recall obtained at it.
Read the sweep as a walk from the highest threshold toward the lowest. Recall starts at 0.333 at thresholds 0.9 and 0.8, rises to 0.667 at 0.7, reaches 1.000 at 0.6, and stays at 1.000 at 0.4 and 0.2. It never decreases. Precision starts at 1.000 at threshold 0.9, falls to 0.500 at 0.8, rises to 0.667 at 0.7 and to 0.750 at 0.6, and then falls to 0.600 at 0.4 and 0.500 at 0.2. Precision therefore moves in both directions while recall only climbs or holds steady.
What Each Threshold Produces on the Curve
The function that computes the curve is precision_recall_curve, found in sklearn.metrics. It needs two inputs: the ground-truth labels and the predicted uncertainties, which come from either the decision_function method or the predict_proba method. It returns three arrays: precision values, recall values, and thresholds. The thresholds cover all possible values that appear in the decision function, in sorted order, and those sorted values are what allow the curve to be drawn.
precision_recall_curvetakes the true labels and the continuous scores, not the yes or no predictions- The three returned arrays are aligned: index i describes one operating point of the classifier
Each row of the sweep is one point on the curve. The points are ordered by threshold, so moving the threshold from high to low walks along the curve from the low-recall end toward the high-recall end. Reading the curve correctly depends on its direction: the closer a curve stays to the upper-right corner, the better the classifier, because a point in the upper right means high precision and high recall for the same threshold. The source describes the curve as starting at the top-left for a very low threshold, where everything is classified as positive, and raising the threshold moves the curve toward higher precision and lower recall. The more a model keeps recall high as precision goes up, the better it is.
Locating Where the Output Departs from Expectation
A common expectation is that precision always falls as the threshold drops, because more samples get labeled positive and some of them are wrong. The printed sweep does not behave that way everywhere. Between threshold 0.8 and threshold 0.6, precision rises from 0.500 to 0.750 while the threshold is being lowered. The place to look is the transition from the threshold=0.8 line to the threshold=0.7 line and on to the threshold=0.6 line.
Checking the expected trend against the printed rows
Does precision fall steadily as the threshold drops from 0.9 to 0.2? Use only the printed sweep to decide.
- 1Write the precision sequence
Reading top to bottom the printed precision values are 1.000, 0.500, 0.667, 0.750, 0.600, 0.500.
- 2Compare each step with the next
The step from 0.500 to 0.667 and the step from 0.667 to 0.750 are increases, so the sequence is not monotonically decreasing.
- 3Locate the first contradiction
The contradiction appears in the lines from threshold 0.8 through threshold 0.6, where precision rises while the threshold is being lowered.
- 4Note what is consistent
The recall column never decreases, which matches the curve idea that lowering the threshold can only catch more positives.
Precision does not fall steadily. The expected monotone decline is contradicted by the rise from 0.500 at threshold 0.8 to 0.750 at threshold 0.6, while recall stays consistent with expectation.
Counting the Cells Behind TPR and FPR
The receiver operating characteristics curve, usually called the ROC curve, looks at all possible thresholds for a classifier at once. Where the precision-recall curve reports precision and recall, the ROC curve reports the false positive rate on the horizontal axis and the true positive rate on the vertical axis. The true positive rate is just another name for recall, so the vertical axis is a measure you already know.
Both axes are built from the four counts of a binary confusion table: true positives (TP), false negatives (FN), false positives (FP), and true negatives (TN). Each axis divides by the size of one true class, which keeps the two rates comparable even when the classes are very unequal in size. The true positive rate divides by the actual positives, and the false positive rate divides by the actual negatives.
The false positive rate measures how much cost the false positives impose relative to the size of the negative class. A model can have a high TPR while still producing many false alarms, and the FPR is what exposes that. Each threshold gives one ROC point, and moving the threshold from one extreme to the other traces the curve from the bottom left to the top right. The ideal curve sits near the top left corner, where the TPR is high and the FPR is low.
Computing an ROC Curve and Its AUC
Start with a case small enough to check by hand. Four samples have true labels 1, 0, 1, 0, and a classifier gives them the scores 0.9, 0.8, 0.7, and 0.1. The two samples labeled 1 are the positives, and the two labeled 0 are the negatives.
0.75roc_auc_scoreonly needs a continuous score that ranks samples- The printed value 0.75 is the hand-checked result explained below
To check the 0.75 by hand, pair every positive with every negative and ask whether the positive received the higher score. The positives are 0.9 and 0.7; the negatives are 0.8 and 0.1. The pair 0.9 against 0.8 is correct, 0.9 against 0.1 is correct, 0.7 against 0.8 is wrong, and 0.7 against 0.1 is correct. Three of the four pairs are ranked correctly, giving 0.75.
AUC summarizes the ROC curve in one number. It equals the probability that a random positive sample ranks above a random negative sample, which is the ranking statement you just checked by hand. Random performance gives 0.5, and perfect separation gives 1.
In this formula s+ is the score of a randomly chosen positive sample and s- is the score of a randomly chosen negative sample. Because AUC is defined through ranking rather than through any one threshold, it describes performance across all thresholds together. The ROC curve itself is produced by roc_curve, which returns the false positive rate, the true positive rate, and the thresholds, one entry per operating point.
Why AUC Reveals What Accuracy Hides
The source's harder case is classifying all nines in the digits dataset against all other digits. The nines are a small share of the samples, so the problem is imbalanced. An SVM is trained with three gamma settings, which control the kernel bandwidth, and accuracy and AUC are recorded for each.
| Gamma setting | Accuracy | AUC | What the AUC says |
|---|---|---|---|
| gamma=1.0 | 90% | chance level | No better than random ranking |
| gamma=0.1 setting in the sweep | 90% | between the two | Separates the classes partly |
| gamma=0.01 | 90% | 1.0 | Every positive ranks above every negative |
Same accuracy, very different AUC. The middle row is a placeholder for the third setting, whose exact value the source does not print.
Accuracy is 90% for all three gamma settings, so accuracy alone would suggest the three models are equivalent. The source notes that this could be chance-level performance or might not be. The AUC values separate them clearly. With gamma=1.0 the AUC is at chance level, so the decision function is no better than random. With gamma=0.01 the AUC is 1.0. In the source's words, with the right threshold this model can classify the data perfectly. Accuracy alone would never have revealed that.
Choosing an Operating Point
An operating point is the threshold chosen to meet a requirement, such as 90% recall, while still keeping reasonable precision. Fixing an operating point is useful in business settings because it lets an organization make performance guarantees to customers or to other groups. The threshold is then set to meet that target, and the remaining question is whether precision at that threshold is still acceptable.
The curve shows the shape of this trade-off. On the left side of the source's example curve it is relatively flat, which means recall does not drop much while precision is increased up to about 0.5. For precision above 0.5, each gain in precision costs a lot of recall. This is why an operating point should be chosen by looking at the curve rather than by defaulting to a threshold.
Choose the threshold on a validation set, not on the test set. If you pick the threshold that looks best on the same test curve you later report, you have tuned the model to the test data, and the reported performance is optimistic.
Comparing Two Classifiers on Their Curves
Different classifiers can perform well in different parts of the curve, which means at different operating points. A support vector classifier (SVC) and a random forest trained on the same dataset can have different curve shapes. A random forest supplies probabilities through predict_proba and has no decision_function, so its curve is built from the probability of class 1, written rf.predict_proba(X_test)[:, 1]. The default threshold for predict_proba in binary classification is 0.5, and that is the threshold marked on the random forest curve.
The source reports that the random forest performs better at the extremes, for very high recall or very high precision requirements. Around the middle, at approximately precision 0.7, the SVM performs better. This is why comparing whole curves gives more detail than a single summary number taken at one threshold.
The F1 score illustrates the risk of a single number. The source's printed values are 0.610 for the random forest and 0.656 for the SVC, which would favor the SVC. But the F1 score captures only one point on the precision-recall curve, the one given by the default threshold. Comparing whole curves can show differences that the F1 score would miss.
average_precision_scoretakes the continuous scores, not the output of predict- The result summarizes the area under the whole precision-recall curve, between 0 and 1
Average precision summarizes the area under the curve in a single value. Under this summary the random forest and the SVC perform similarly, with the random forest slightly ahead, which differs from the earlier F1 comparison. Because the value is the area under a curve running from 0 to 1, it always lies between 0 (worst) and 1 (best). The source also states that the average precision of a classifier that assigns decision function values at random equals the fraction of positive samples in the dataset.
Common Mistakes When Reading These Curves
Common mistake Expecting precision to fall at every lower threshold
What it looks likeIn the printed sweep, precision rises from 0.500 at threshold 0.8 to 0.750 at threshold 0.6.
Why it failsLowering the threshold adds positive labels, but the new ones may be correct, so precision can rise as well as fall.
Do this insteadCheck each column against the printed rows and let the data decide the direction.
Common mistake Treating a high AUC as a finished decision rule
What it looks likeA model with AUC 1.0 is deployed at the default threshold without checking its decisions.
Why it failsAUC does not use the default threshold, so the default may still produce poor classifications.
Do this insteadUse AUC to decide that a good model exists, then choose the threshold on a validation set.
Common mistake Choosing the threshold on the test set
What it looks likePicking the point on the test curve that looks best, then reporting that same curve's performance.
Why it failsThe threshold is tuned to the test data, so the reported performance is optimistic.
Do this insteadSelect the threshold on a separate validation set and report test performance at that fixed threshold.
Common mistake Passing predict output instead of decision_function or predict_proba output to precision_recall_curve or average_precision_score
Reading a Sweep You Have Not Seen
Suppose a sweep prints recall 0.500 at threshold 0.9, 0.500 at threshold 0.7, and 0.400 at threshold 0.5, with precision 1.000, 0.800, and 0.700 at those same thresholds. Which printed row contradicts the expectation that recall never decreases as the threshold drops, and which column moves in the opposite direction from recall at the step from 0.7 to 0.5?
Hints
- Compare the recall values in the order the thresholds are printed, from 0.9 to 0.5.
- Recall should be non-decreasing as the threshold drops, so look for a step where it gets smaller.
- Precision falls from 0.800 to 0.700 at the same step; check whether recall moves in the same or opposite direction.
Key Takeaways
- A precision-recall curve plots precision against recall for every threshold, and each point is one threshold's trade-off;
precision_recall_curvereturns precision, recall, and thresholds arrays aligned by index. - Lowering the threshold never decreases recall in the printed sweep, while precision moves in both directions, so an expected steady decline in precision can be contradicted by the printed rows.
- TPR equals recall, and FPR divides false positives by the number of actual negatives; AUC equals the probability that a random positive ranks above a random negative, with 0.5 meaning random and 1 meaning perfect separation.
- Accuracy can hide differences between models on imbalanced data that AUC reveals, but a high AUC does not select a threshold, so choose the operating point on a validation set.
- Compare whole curves, or average precision, rather than one F1 score taken at the default threshold, when deciding between two classifiers.