Unit 5.5 · about 4 h
164 / 324Cost-sensitive thresholds, imbalance and prevalence change
The default 0.5 threshold encodes equal costs that no deployment has. Imbalance and prevalence change move every thresholded metric except the ranking.
- derive
- measure
You can now
- Derive the cost-optimal threshold \(t = C_{\text{FP}} / (C_{\text{FP}} + C_{\text{FN}})\) for calibrated probabilities and set it with
FixedThresholdClassifier. - Tune a threshold with
TunedThresholdClassifierCVwithout letting the tuning data leak into the report. - Specify a selective (reject-option) rule with a coverage target and report its risk-coverage tradeoff.
- Predict how a prevalence shift moves precision, F1 and the operating threshold while ROC AUC stands still.
Covers
- Cost-sensitive thresholds and selective prediction
- Class imbalance, prevalence change and metric choice
Study, in this order
3 steps
- Tuning the decision threshold for class predictionscikit-learn - model selection and evaluation route
Sections 3.3 (0.5 and score-0 defaults), 3.3.1.1 (
TunedThresholdClassifierCV, default balanced-accuracy scoring,pos_labelviamake_scorer), 3.3.1.2 (internal 5-fold CV;cv='prefit'only on fresh validation data) and 3.3.1.4 (FixedThresholdClassifierwithFrozenEstimator)Depth · Run the 3.3.1.1 snippet. The page prints 0.88 for the refit model scored on its own training data (0.887 with scikit-learn 1.9.1), against an internal cross-validated
best_score_of 0.86. The gap is in-sample optimism, so trust the 0.86. - Selective classifier, coverage and selective riskEl-Yaniv and Wiener - On the Foundations of Noise-free Selective Classification
Abstract and Section 2, Preliminary Definitions (Definitions 1 and 2: coverage and selective risk, the risk-coverage tradeoff)
Depth · Stop before the noise-free learning bounds. The definitions plus your own confidence threshold are the whole assignment.
- Precision and recall definitions for the prevalence arithmeticscikit-learn - model selection and evaluation route
Section 3.4.4.9 for the binary precision and recall definitions; the prevalence-shift rescaling is derived in Reproduce below
Focus on
- Predict positive when \(p\) times \(C_{\text{FN}}\) exceeds \((1-p)\) times \(C_{\text{FP}}\), so \(t = C_{\text{FP}} / (C_{\text{FP}} + C_{\text{FN}})\). With miss cost 10 and false-alarm cost 1, the threshold is 1/11 = 0.091, not 0.5.
TunedThresholdClassifierCVmoves only the threshold by internal CV. When the vanilla model was fit on the same data with the same seed,predict_proba, and so the ROC and PR curves, are identical before and after.- The reject rule is a second threshold: abstain when \(\max(p, 1-p)\) is below 1 minus reject-cost over error-cost, then report risk at the achieved coverage.
- At fixed class-conditional score distributions, a prevalence shift moves precision and F1 but not recall, FPR or ROC AUC. The cost-optimal cutoff on the old scores moves too, because the calibrated probabilities change with the base rate.
Reproduce closed-book
make_classification(n_samples=4000, weights=[0.9, 0.1], class_sep=0.8, random_state=0), split 75/25 stratified with random_state=0, fit LogisticRegression on train and wrap it in FixedThresholdClassifier(FrozenEstimator(model), threshold=t). On the 1000 test rows (105 positives) recall rises from 0.238 at 0.5 to 0.714 at 0.2 and 0.848 at 1/11, while precision falls from 0.581 to 0.446 and 0.302.Traps
- Tuning the threshold on the test set, or with
cv='prefit'on training data. The user guide warns explicitly that tuning data must be disjoint from training data. - Moving the threshold to fix calibration. Thresholds spend probabilities; they cannot repair them. Recalibrate first.
- Reporting selective accuracy without coverage. Accuracy on the retained 60% says nothing beside accuracy on 100%; always pair risk with coverage.
Practice
scikit-learn cost-sensitive threshold example: German credit
Cost-sensitive learning with constant gains and costs: a bad credit scored as good costs 5 times the reverse. Rebuild the vanilla and tuned HistGradientBoosting models, confirm their predict_proba outputs are identical while their labels differ, and read best_threshold_ (0.03 on the page). Then run the cv="prefit" variant (0.25) and the page's explanation of why it overfits
Derive the threshold the cost matrix implies for calibrated probabilities, 1/(1 + 5) = 1/6 (the page's "1/5 of the cost ratio" wording is loose), and score it on the test split with FixedThresholdClassifier. With scikit-learn 1.9.1 the test gain is -209 at 0.5, -143 tuned and -136 at 1/6. Explain why the tuned cutoff sits so far below 1/6.
Self-test
-
Miss cost 10, false-alarm cost 1, calibrated \(p = 0.2\). Predict positive or not, and why?
Predict positive: the expected miss cost 0.2 times 10 = 2 exceeds the false-alarm cost 0.8 times 1 = 0.8. Equivalently, 0.2 exceeds 1/11. -
Why do the tuned and vanilla classifiers share ROC curves?
Tuning moves only the decision threshold whilepredict_probais untouched, so every threshold sweep (ROC, PR) is identical. -
Reject cost 0.2, error cost 1. When do you abstain?
When \(\max(p, 1-p)\) is below 0.8: the cheapest guess has error probability above the price of abstaining. -
Prevalence halves at fixed score quality. Which metrics move?
Precision and F1 fall; recall, FPR and ROC AUC hold. Any threshold tuned for the old base rate must be re-derived.
Completion criterion
Stop when
You derive the cost threshold from scratch, reproduce the tuned-versus-vanilla probability agreement, and report a reject rule as a (risk, coverage) pair.
Mark passed, then open 5.6 Only mark this when you can do it without notes.Leads to
- 5.6 Paired bootstrap, permutation tests and multiplicity Test whether the thresholded gap is real or noise.
- 5.7 Learning curves, error taxonomies and slices Find where the thresholded errors concentrate.
Comes after
- 2.8 Probability estimates, class priors and asymmetric thresholdsExtend cost-sensitive thresholds to imbalance and prevalence change.
- 3.8 Feature importance caveats and class weighting effectsSet cost-sensitive thresholds with calibrated probabilities.
- 4.7 Outlier and novelty detection, thresholds and representationCarry the threshold policy into cost-sensitive decisions under shifted prevalence.
- 5.2 Regression error and confusion-matrix metricsAct on the matrix with cost-derived thresholds.
- 5.3 ROC AUC, average precision, log loss and Brier scoreTurn scores into decisions at a cost-derived threshold.
- 5.4 Calibration curves and Platt or isotonic recalibrationSpend calibrated probabilities on thresholds and reject rules.
Resources for this unit
- scikit-learn - model selection and evaluation route Follow Cross-validation, Hyperparameter tuning, Decision threshold tuning, Metrics and scoring, Probability calibration, Validation curves, Permutation importance and Common Pitfalls. Retain raw predictions and independently hand-check central metrics.
- El-Yaniv and Wiener - On the Foundations of Noise-free Selective Classification Read the Abstract and Section 2 (Preliminary Definitions: Definitions 1 and 2 for coverage and selective risk) for the risk-coverage tradeoff. Stop before the noise-free learning bounds.
Also in this section
- ISLP - resampling and multiple testing Use Chapter 5 and the relevant selection-history parts of Chapter 13 with their Python labs. Connect resampling to uncertainty and multiplicity without repeating the full statistics stage.
- Classical ML Scientific Investigation Use Core requirements, architecture constraints, Milestones A-F and failure injection as the standard for end-to-end evidence. The full project remains a later capstone route.
- D2L - Environment and Distribution Shift Read 4.7, then construct one controlled covariate, label and concept shift. Record what changes, which signal detects it and what response the evidence supports.
- Deep-ML candidate - evaluation problems After the platform admission check, use at most one of 18 K-Fold CV, 260 Expected Calibration Error, 276 ROC, 277 AUC or 840 Stratified K-Fold. Hand-checked local metrics remain the evidence.
- SciPy - Resampling and Monte Carlo methods tutorials Work the notebooks linked from this page: Tutorial 3 (The Bootstrap) with
scipy.stats.bootstrap, includingpaired=True, and Tutorial 2b (Paired-Sample Permutation Tests) withpermutation_testandpermutation_type='samples'. Keep one resampling index stream across compared models.