Selective Prediction
Selective prediction lets a model decline to answer. Instead of returning a label for every input, the system answers the cases it is most likely to get right and sends the rest elsewhere: to a person, a slower model, or a "cannot answer" response. It is also called classification with a reject option or abstention.
Two components
A selective predictor is a pair \((f, g)\): a predictor \(f\) that produces an answer, and a selection function \(g\) that decides whether to give it. Usually \(g\) is a confidence score \(s(x)\) compared with a threshold \(\tau\): answer when \(s(x) \ge \tau\), abstain otherwise. The score can be the maximum class probability, a calibrated probability, a verifier model's output, or the agreement among several samples.
Two quantities describe the result:
- Coverage: the fraction of inputs the system answers.
- Selective risk: the error rate on the answered inputs only.
Raising the threshold lowers coverage. When higher scores really do indicate a lower chance of error, selective risk is expected to fall as well, but this has to be measured at each threshold, as in the example below. The plot of risk against coverage is the risk-coverage curve. Geifman and El-Yaniv study this setting for deep networks and show how to choose a threshold that meets a target risk level.
Example (synthetic)
Draw 20,000 confidence values uniformly between 0.5 and 1, and let each prediction be correct with probability equal to its confidence. The score is calibrated by construction; the distribution determines how much coverage each threshold retains. This NumPy example uses seed 7 and prints both the risk table and the cost table used below:
import numpy as np
rng = np.random.default_rng(7)
confidence = rng.uniform(0.5, 1.0, 20_000)
correct = rng.random(len(confidence)) < confidence
for threshold in (0.50, 0.70, 0.80, 0.90, 0.95):
answer = confidence >= threshold
risk = (~correct).mean()
print(f"{threshold:.2f} {answer.mean():.3f} {risk:.3f}")
print("costs: wrong=10, defer=2")
for threshold in (0.00, 0.70, 0.80, 0.85, 0.90, 1.01):
answer = confidence >= threshold
cost = np.where(answer, 10 * (~correct), 2).mean()
print(f"{threshold:.2f} {answer.mean():.3f} {cost:.3f}")
| threshold | coverage | selective error |
|---|---|---|
| 0.50 | 1.000 | 0.254 |
| 0.70 | 0.599 | 0.151 |
| 0.80 | 0.407 | 0.098 |
| 0.90 | 0.204 | 0.052 |
| 0.95 | 0.102 | 0.024 |
Answering the 20.4% of cases with confidence at least 0.90 cuts observed error from 25.4% to 5.2%. The remaining 79.6% go to a human. A different confidence distribution would give different coverage at the same threshold.
Choosing the threshold from costs
The threshold is not a free parameter when the costs are known. Let a wrong answer cost \(C_w\), a correct answer cost 0, and handling by a person cost \(h\). If the probability of being right is \(p\), answering costs \((1-p)\,C_w\) in expectation and abstaining costs \(h\). The system should answer when
\[ (1-p)\,C_w < h \quad\Longleftrightarrow\quad p > 1 – \frac{h}{C_w}. \]
With \(C_w = 10\) and \(h = 2\) (hypothetical units), the threshold is \(p > 0.80\). Evaluating the average cost per case on the synthetic data above:
| threshold | coverage | average cost |
|---|---|---|
| 0.00 (always answer) | 1.000 | 2.539 |
| 0.70 | 0.599 | 1.706 |
| 0.80 | 0.407 | 1.587 |
| 0.85 | 0.304 | 1.616 |
| 0.90 | 0.204 | 1.698 |
| 1.01 (always defer) | 0.000 | 2.000 |
Among the listed thresholds, the lowest observed average cost is at 0.80, matching the population decision rule. Pushing the threshold higher reduces errors but loses money on cases that would have been answered correctly, since each deferral costs \(h\) even when the model was right. The Cost Matrix entry gives the general form with several error types.
If abstention instead loses a benefit \(C_a\) only when the answer would have been correct, its expected opportunity cost is \(pC_a\), not a fixed handling fee. Comparing \((1-p)C_w\) with \(pC_a\) gives \(p > C_w/(C_w+C_a)\). With \(C_w=10\) and \(C_a=2\), that threshold is \(5/6\), rather than 0.80. Choose the cost model that matches the deferral path; if both a handling fee and a lost benefit apply, include both.
Conditions and failure modes
- The rule assumes \(p\) is calibrated. Uncalibrated scores shift the best threshold; estimate \(p\) from labeled data, including the share of unanswerable inputs seen in production.
- A score that does not rank correct above incorrect predictions gives a flat risk-coverage curve, and abstention is no better than random deferral. Measure the curve before relying on it.
- Selective risk is measured on answered cases only. Reporting it without coverage hides a system that abstains on everything difficult; always report both.
- Distribution shift moves the score distribution, so a threshold fixed last quarter may no longer give the same coverage or risk. Monitor both.
- Abstaining is not free: the deferred cases need a path, with capacity to handle them. Coverage of 50% requires a human team sized for the other 50%.
Neighbors
Calibration makes a score a probability, selective prediction decides what to do with it. Out-of-distribution detection asks whether the input is unlike the training data, which is one reason to abstain but not the only one: an in-distribution but ambiguous input also deserves abstention. In retrieval-based answering, abstention is the decision to say that the evidence does not support an answer.
References
Discover more from Insightful Data Lab
Subscribe to get the latest posts sent to your email.
