← All notes

ML algorithms · Core Concepts

Calibration

A model is calibrated if, among all cases where it says "70%", roughly 70% are actually positive. Many classifiers violate this:

Abstract: In one line A classifier’s raw scores are often not honest probabilities. Calibration is a post-hoc map from scores to probabilities, learned on a held-out set. The two workhorse methods — Platt scaling (fit a sigmoid) and isotonic regression (fit any monotone step function) — are the same regression of label on score, differing only in the function class they allow.

Tip: Rendering Graphs use Mermaid xychart-beta / flowchart (Obsidian ≥ 1.5, Mermaid ≥ 10.3). If a chart doesn’t render, the table directly beneath it carries the identical numbers.

Contents


1 The calibration problem

A model is calibrated if, among all cases where it says “70%”, roughly 70% are actually positive. Many classifiers violate this:

  • SVMs output a signed distance from the hyperplane — not a probability at all.
  • Boosted trees (AdaBoost) push scores toward the middle, producing a sigmoidal reliability curve.
  • Naive Bayes / deep nets tend to be overconfident, pushing scores toward 0 and 1.

Important: Always use held-out data Calibration is assessed and fit on a held-out set (or via cross-validation) — never the data the base model trained on, or you bake in its optimism. Note also that logistic regression fit by maximum likelihood is usually already well-calibrated, because it directly optimizes log loss; the methods below matter most for SVMs, boosted trees, and naive Bayes.


2 The two methods at a glance

  Platt scaling Isotonic regression
Type Parametric (sigmoid) Non-parametric (monotone step fn)
Assumption Distortion is sigmoidal Distortion is monotonic
Parameters 2 ($A$, $B$) Many, data-dependent
Data appetite Small sets fine Needs more (~1000+)
Overfit risk Low Higher on small sets
Output Smooth continuous curve Piecewise-constant steps
Fitting objective Maximum likelihood (log loss) Least squares (via PAVA)

Note: The unifying view Both regress the binary label $y$ on a single feature, the raw score $f$. Platt restricts the regressor to the sigmoid family; isotonic restricts it only to be non-decreasing. That is the entire difference.

What “sigmoid-shaped distortion” means

The distortion is the curve mapping raw score → true probability. Platt assumes that curve is a member of the two-parameter logistic family $1/(1+e^{Af+B})$: monotone, a single inflection, symmetric saturation at both ends. When the true curve really is an S (SVMs, boosting) two knobs suffice. When it is monotone-but-not-sigmoidal, no $A,B$ can fit it and a systematic bias remains that more data cannot remove — which is exactly the gap isotonic fills.


3 Platt scaling

\[P(y=1 \mid f) = \frac{1}{1 + \exp(Af + B)}\]

Fit $A, B$ by maximizing likelihood (minimizing log loss) on the held-out pairs $(f_i, y_i)$ — i.e. a 1-D logistic regression whose only feature is the base model’s score. Platt’s practical tweak: use softened targets to avoid blow-up, with $N_+$ positives and $N_-$ negatives:

\[t_+ = \frac{N_+ + 1}{N_+ + 2}, \qquad t_- = \frac{1}{N_- + 2}\]

Low variance, works on small sets — but biased if the distortion isn’t sigmoidal.

Info: Modern cousin Temperature scaling (Guo et al., 2017) is the one-parameter version for deep nets: divide the logits by a single learned scalar $T$ before the softmax.


4 Isotonic regression and PAVA

Goal. Given score-ordered points, find fitted values minimizing squared error subject to monotonicity:

\[\min_{\hat m}\ \sum_i (y_i - \hat m_i)^2 \quad\text{s.t.}\quad \hat m_1 \le \hat m_2 \le \dots \le \hat m_n\]

The one idea. Where the data already climbs, keep it. Where it dips (a violation), replace the offending run with its mean (the least-squares constant). That replacement is pooling.

Pool Adjacent Violators Algorithm (PAVA). Scan left→right; add each point as its own block; if a block’s level is below the block to its left, merge them at their average; a merge can create a new violation to the left, so keep merging until non-decreasing. $O(n)$ after sorting.

Worked example

Input $y = 1,\ 4,\ 3,\ 2,\ 6$:

Step Sees Check / action Block levels
1 1 start 1
2 4 $1 \le 4$ ✓ 1, 4
3 3 $4 > 3$ ✗ → pool(4,3) = 3.5 1, 3.5
4 2 $3.5 > 2$ ✗ → pool(3.5-block, 2) = 3 1, 3
5 6 $3 \le 6$ ✓ 1, 3, 6

Result: $\hat y = 1,\ 3,\ 3,\ 3,\ 6$ — monotone, and each flat run is the mean of the points it absorbed. (Step 4 is the cascade: pooling created a fresh violation that pulled the whole block down.)

Warning: Overfitting With few points, isotonic happily flattens real signal as if it were a violation. This is why it needs ~1000+ examples to reliably beat Platt.


5 From fit to prediction

PAVA gives a fitted value at each training score — equivalently, a set of monotone breakpoints $(x_i, \hat y_i)$. To predict for a new score $x^\ast$:

  1. Locate which two breakpoints it falls between.
  2. Interpolate linearly between their fitted values (scikit-learn’s default; a piecewise-constant “hold” is the alternative).
  3. Clip anything past the ends to the nearest endpoint value (no data out there; stay monotone & bounded).

Prediction example

Toy calibration set — scores $s$ with binary labels:

\[s = 1,2,3,4,5,6 \qquad y = 0,0,1,0,1,1\]

PAVA pools the 1,0 violation at $s=3,4$ into $0.5$, giving fitted levels and breakpoints through $(1,0),(2,0),(3,0.5),(4,0.5),(5,1),(6,1)$. Each level is the fraction of positives among the pooled points.

New score $s^\ast$ Lands between Predicted prob
0.4 below range 0.00 (clipped)
2.5 $(2,0)$–$(3,0.5)$ 0.25
4.5 $(4,0.5)$–$(5,1)$ 0.75
5.5 flat top 1.00

6 Deciding whether and how to calibrate

Decision workflow

flowchart TD
    A["Held-out set: predicted probs + true labels"] --> B["Bin predictions, plot reliability diagram"]
    B --> C{"Points on the diagonal? (ECE ~ 0)"}
    C -- "Yes" --> D["No calibration needed"]
    C -- "No: systematic deviation" --> E{"How much calibration data?"}
    E -- "Small (~100s), sigmoidal distortion" --> F["Platt scaling"]
    E -- "Large (~1000+), unknown shape" --> G["Isotonic regression"]
    F --> H["Cross-validate both; keep lower log loss / Brier"]
    G --> H
    H --> I["Apply fitted map to new scores"]

Worked case: 100 held-out examples

A deliberately overconfident model; base rate 47% positive. Bin into 5 (≈20 each — far cleaner than 10 bins at $n=100$):

Predicted range n Mean predicted Observed positive rate
0.0–0.2 20 0.107 0.200
0.2–0.4 16 0.323 0.312
0.4–0.6 20 0.471 0.400
0.6–0.8 25 0.683 0.640
0.8–1.0 19 0.894 0.737

How to read it: a systematic tilt (low bin above the diagonal, high bins below) signals miscalibration; dots scattered on the diagonal within noise → skip calibration. Here the tilt is the overconfidence signature. ECE = 0.075, Brier = 0.222, log loss = 0.651 → calibrate.

Reliability diagram

xychart-beta
    title "Reliability — raw overconfident model"
    x-axis "bin (predicted prob)" [0.1, 0.3, 0.5, 0.7, 0.9]
    y-axis "probability" 0 --> 1
    line [0.107, 0.323, 0.471, 0.683, 0.894]
    bar [0.2, 0.312, 0.4, 0.64, 0.737]

Line = mean predicted (perfect-calibration reference); bars = observed rate. Bar above line at the low end and below it at the high end = overconfidence.

Choosing the method

Small set + sigmoidal distortion → Platt is the principled pick. Confirm by cross-validating both on log loss / Brier:

  Brier Log loss
Raw (uncalibrated) 0.222 0.651
Platt scaling 0.213 0.615
Isotonic regression 0.194 0.555

Warning: Read the isotonic win with suspicion Isotonic scores lower here, but this is measured on the very 100 points it was fit to — flattering the more flexible method. Its giveaway: the fitted ends snap to exactly 0 and 1 from a handful of points. Cross-validated at $n=100$, Platt’s stability usually wins; the verdict flips around $n \approx 1000+$.

The two fitted maps

  • Platt: $A = 3.05,\ B = -1.69$ → calibrated $= \sigma(3.05,p - 1.69)$ (smooth sigmoid; store 2 numbers).
  • Isotonic: pooled positive-rate levels $[,0,\ 0.333,\ 0.4,\ 0.556,\ 0.667,\ 0.762,\ 1,]$ across increasing score (a lookup staircase; store breakpoints).
xychart-beta
    title "Calibration maps (raw score -> calibrated prob)"
    x-axis "raw model score" [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    y-axis "calibrated probability" 0 --> 1
    line [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    line [0.155, 0.200, 0.253, 0.315, 0.384, 0.458, 0.534, 0.609, 0.679, 0.741, 0.795]
    line [0, 0, 0.333, 0.333, 0.4, 0.4, 0.4, 0.667, 0.762, 0.762, 1.0]

Three lines: straight diagonal = no change; the smooth one pulling extremes inward = Platt; the staircase = isotonic. Both sit below the diagonal at high scores and above it at low scores — squeezing overconfident predictions toward the middle.

End result on a few raw scores:

Raw score Platt Isotonic
0.10 0.200 0.000
0.50 0.458 0.400
0.90 0.741 0.762

The 0.10 → 0.000 from isotonic is the overfitting risk made visible.


7 Brier score

The mean squared error of probability predictions:

\[\text{Brier} = \frac{1}{N}\sum_{i=1}^{N}(p_i - y_i)^2, \qquad y_i \in {0,1}\]

Worked example

Predicted $p_i$ Outcome $y_i$ $(p_i - y_i)^2$
0.9 1 0.01
0.8 0 0.64
0.3 0 0.09
0.6 1 0.16
\[\text{Brier} = (0.01 + 0.64 + 0.09 + 0.16)/4 = 0.225\]

Properties worth knowing:

  • Range 0 → 1, lower better. A confident wrong prediction (row 2: 0.8 on a negative) dominates the sum.
  • It is a proper scoring rule — minimized in expectation only when you report your true beliefs, so it can’t be gamed by shading toward 0/1. That’s why it’s trustworthy for comparing calibrators.
  • Baseline: always predicting the base rate scores $\bar y(1-\bar y)$ = 0.25 for a balanced problem — any real model should beat that.
  • Multiclass version sums over $K$ class probabilities, $\sum_k (p_{ik}-y_{ik})^2$ (range 0 → 2).
  • Murphy decomposition splits Brier into calibration + refinement if you need to diagnose which is failing.

8 Why train with cross-entropy not MSE

The question: why not fit a sigmoid-output model (logistic regression / Platt) by minimizing squared error?

Reason 1 — convexity. Cross-entropy is convex in the weights for logistic regression (one global basin). Squared-error-through-a-sigmoid is non-convex: for $y=1$, $f(z)=(\sigma(z)-1)^2$ has $f’‘(z) = 2,s(1-s),g’(s)$ which is negative when $s < 1/3$ (the confidently-wrong region). The global-optimum guarantee is lost.

Reason 2 — the gradient (the real killer). Per example, with $s=\sigma(z)$:

\[\frac{\partial,\text{MSE}}{\partial z} = 2(s-y),\underbrace{s(1-s)}_{\sigma'(z)} \qquad \frac{\partial,\text{CE}}{\partial z} = s - y\]

The $\sigma’(z)=s(1-s)$ factor cancels in cross-entropy. So when the model is confidently wrong ($y=1$, $s\approx 0$): MSE gradient $\to 2(-1)(0) = 0$ (vanishes exactly where error is largest), while CE gradient $\to -1$ (full-strength correction).

xychart-beta
    title "Training loss vs logit z (true label = 1)"
    x-axis "model score z" [-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6]
    y-axis "loss" 0 --> 6
    line [6.002, 5.007, 4.018, 3.049, 2.127, 1.313, 0.693, 0.313, 0.127, 0.049, 0.018, 0.007, 0.002]
    line [0.995, 0.987, 0.964, 0.908, 0.776, 0.535, 0.25, 0.072, 0.014, 0.002, 0.000, 0.000, 0.000]

The line climbing to 6 on the left is cross-entropy — steep slope when wrong. The line capped at 1 is MSE — it flattens into a plateau on the left, where the gradient has died.

z (true label = 1) Cross-entropy loss MSE loss
-6 6.002 0.995
-4 4.018 0.964
-2 2.127 0.776
0 0.693 0.250
2 0.127 0.014
4 0.018 0.000

Note: Refining “multiple local minima” It is non-convex, as the intuition says. But for a single sigmoid the practically lethal symptom isn’t a maze of distinct minima — it’s the flat saturated plateaus where learning stalls, plus losing the convexity guarantee. Cross-entropy wins on both: convex landscape and a non-vanishing gradient.

Example: The bow on the thread This is exactly why Platt fits its sigmoid by minimizing log loss, even though we evaluate the result with Brier. Squared error is a fine proper scoring rule for grading probabilities; it’s a poor objective for training a sigmoid.


9 Formula reference

Concept Formula
Platt scaling $P = 1/(1+e^{Af+B})$
Isotonic objective $\min \sum (y_i-\hat m_i)^2$ s.t. $\hat m_1 \le \dots \le \hat m_n$
Sigmoid $\sigma(z) = 1/(1+e^{-z})$, $\sigma’(z)=\sigma(1-\sigma)$
Cross-entropy $-[y\ln s + (1-y)\ln(1-s)]$, grad $= s-y$
Squared error $(s-y)^2$, grad $= 2(s-y),s(1-s)$
Brier (binary) $\frac{1}{N}\sum (p_i-y_i)^2$
Expected Calibration Error $\sum_b \frac{n_b}{N},
Base-rate Brier baseline $\bar y(1-\bar y)$

Platt scaling · Isotonic regression · Pool Adjacent Violators Algorithm · Reliability diagram · Expected Calibration Error · Brier score · Proper scoring rule · Cross-entropy loss · Temperature scaling · Logistic regression