Prediction Intervals and Split Conformal Prediction

Michael BrenndoerferOctober 29, 202646 min read

Build distribution-free prediction intervals and label sets with split conformal prediction, including finite-sample quantiles and marginal coverage guarantees.

Machine Learning from ScratchAll chapters
Part 12 of 15Calibration and Prediction Uncertainty
Chapter 77Prediction Intervals and Split Conformal Prediction
Reading the full chapter · 10 sections · 46 min10 sections · 46 min

All 10 sections · 46 min read

Prediction Intervals and Split Conformal PredictionFull chapter · Sections in this chapter1 / 10 ↓
Reading tools Definitions, links & notes

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Notes & comments

Prediction Intervals and Split Conformal Prediction

A regression model hands us a single number: f^(x)\hat f(x). If we are forecasting tomorrow's demand, pricing an insurance contract, or deciding whether a patient needs a follow-up test, that number alone does not describe how wrong the prediction might be. A prediction of 1,000 units that is usually off by 20 is a different business situation from one that is usually off by 400, even though both point predictions are 1,000.

Part II introduced confidence intervals for population quantities. In regression, a confidence interval for the conditional mean E[Y∣X=x]\mathbb{E}[Y\mid X=x] describes estimation uncertainty about that mean. A future observation YY has additional randomness around it. A prediction interval targets that future observation. The familiar Gaussian linear-model construction uses distributional and variance assumptions; split conformal takes a different route.

Split conformal prediction takes a fitted predictor, calibrates a score on examples held out from fitting and model selection, and returns an interval or label set. Its finite-sample guarantee requires the calibration and fresh test scores to be exchangeable, conditional on the fitting procedure. It guarantees marginal coverage over calibration and test draws. It does not guarantee coverage for each individual, subgroup, fixed calibration sample, or observed test batch.

The mechanism is simple. We measure how badly the model misses on the calibration set, take a particular quantile of those misses, and add that quantile as a margin around every future prediction. Almost all of the subtlety lives in exactly which quantile to take, and in understanding precisely what the resulting guarantee does and does not promise. That is where we will spend our time.

This chapter builds directly on Probability Calibration, where we asked whether a model's stated probabilities match observed frequencies. Conformal prediction asks a related but distinct question for regression: not whether the model is right, but how wide a band we must draw around it before a stated fraction of future observations fall inside.

Advantages

The coverage bound holds in finite samples under exchangeability of the held-out scores. It does not require a Gaussian error distribution or a correctly specified predictor. A fixed Gaussian margin can under-cover when its assumptions fail. Split conformal instead calibrates the chosen score, including an infinite threshold when the calibration sample is too small for a finite cutoff. The resulting sets can be wide or uninformative while remaining marginally valid.

Conformal prediction wraps a fitted model. Linear regression, a boosted ensemble, or another predictor can supply the score, provided fitting and selection are settled using fitting data only. The residual-score version needs predictions on nn calibration examples and a sort of nn scores, conventionally O(nlog⁡n)O(n\log n) time for sorting. This extra work depends on the predictor and calibration size; it is not universally negligible.

Changing the score can change the shape and adaptivity of the output. Absolute residuals give constant-width regression intervals; positive input-dependent scaling can redistribute width; class-probability scores give label sets. All use the same marginal rank argument when their scores are fixed before calibration. Better probability calibration or a different score may improve set efficiency, but neither guarantees smaller sets or better subgroup coverage in every problem.

Interval width and set size can inform operational rules, such as routing broad intervals to human review. Such a rule is an additional selection step: marginal coverage of the original procedure does not imply the same coverage among automatically accepted cases. Evaluate the selected cases separately and distinguish a useful triage signal from a calibrated conditional error rate.

Disadvantages

The guarantee is marginal. It averages over calibration data and a fresh test point, rather than promising the target coverage at every input or within every subgroup. Constant-width intervals can over-cover low-noise regions and under-cover high-noise regions. A particular realized calibration set and finite test batch can also have coverage below nominal. None of these observations alone contradicts the marginal theorem.

Exchangeability can fail under distribution shift and ordinary serial dependence. A future regime can differ from the calibration period, and a sequence whose dependence changes with temporal lag is generally not invariant to arbitrary permutations. Dependence alone is not enough to rule out exchangeability: dependent exchangeable samples exist. A chronological split or rolling recalibration does not by itself restore the ordinary split-conformal guarantee.

Holding out calibration data leaves fewer observations for fitting. When data are scarce, related methods such as jackknife+ and CV+ reuse observations through additional model fits. Their constructions and finite-sample bounds differ from ordinary split conformal. Jackknife+ is the leave-one-out special case of CV+, obtained when each fold contains one observation. These methods should not be treated as interchangeable ways to preserve the split-conformal guarantee. This chapter keeps the separate fitting and calibration roles visible.

Conformal calibration does not improve the predictor itself. Large calibration errors can require a wide margin, and a constant margin can still leave a difficult subgroup under-covered. A finite calibration sample does not force the realized test fraction to meet nominal. Width is useful alongside coverage, but model choice, score choice and sampling variation all affect it.

Discrete scores and ties can make deterministic sets conservative. Classification sets can contain several labels or be empty. For the probability-threshold score, an empty set means that no class probability reaches the calibrated threshold. It does not by itself establish that the input is out of distribution. A downstream rule can add a label to an empty set, which only enlarges the set and therefore cannot reduce inclusion coverage.

Exchangeability, marginal coverage, and failure modes

Exchangeability is the assumption that the joint distribution of the n+1n+1 points (the nn calibration points plus the test point) is invariant to permutation of their indices. In symbols, for any permutation π\pi of {1,…,n+1}\{1,\dots,n+1\}, the joint distribution of (Z1,…,Zn+1)(Z_1,\dots,Z_{n+1}) equals that of (Zπ(1),…,Zπ(n+1))(Z_{\pi(1)},\dots,Z_{\pi(n+1)}), where Zi=(Xi,Yi)Z_i = (X_i, Y_i). Independent and identically distributed data are exchangeable. Exchangeable data need not be independent: a uniformly ordered sample without replacement from a fixed population is exchangeable but dependent. A calibration/test distinction that systematically changes the joint distribution lacks this permutation symmetry.

Write C^(x)\hat C(x) for the prediction set returned at input xx. Let α∈(0,1)\alpha\in(0,1) be the target miscoverage level, so 1−α1-\alpha is the target inclusion probability.

Marginal coverage is P(Yn+1∈C^(Xn+1))≥1−αP(Y_{n+1}\in\hat C(X_{n+1}))\ge1-\alpha, with probability over calibration and test draws. Conditional coverage would require P(Yn+1∈C^(Xn+1)∣Xn+1=x)≥1−αP(Y_{n+1}\in\hat C(X_{n+1})\mid X_{n+1}=x)\ge1-\alpha at every relevant xx. For regression over unrestricted distributions with continuously varying covariates, exact distribution-free conditional coverage has strong impossibility results: nontrivial finite-length intervals cannot be guaranteed uniformly without additional restrictions (Vovk, 2012; Barber, Candès, Ramdas and Tibshirani, 2021). Group-conditional guarantees and assumptions about the conditional distribution are different, more restricted targets.

These distinctions give practical failure checks. Compare calibration and deployment populations; check whether temporal or clustered structure defeats exchangeability; and keep model fitting, preprocessing and selection outside the calibration and test outcomes. Training residuals can be optimistic because fitting used their responses. Reusing calibration outcomes for model selection can also destroy the held-out symmetry argument. Either practice removes the ordinary proof; it does not imply an identical numerical shortfall in every dataset.

Formula

We now build the machinery. The aim is to turn a bare point prediction into a band, and to do it in a way that comes with a guarantee we can state precisely. Three questions have to be answered along the way:

  1. What are we trying to cover? Not the regression surface, but the next observation. If the response retains nondegenerate noise, additional fitting data do not remove that noise.
  2. How do we measure a miss? We need a number that grows when a candidate observation becomes implausible under the fitted model, a nonconformity score.
  3. How do we convert finitely many measured misses into a margin that is valid for the next one? This is where exchangeability enters, and where a seemingly cosmetic +1+1 turns out to carry the entire guarantee.

Notation throughout: fit the predictor and score on Dtrain\mathcal D_{\mathrm{train}}, then use a disjoint calibration set Dcal={(Xi,Yi)}i=1n\mathcal D_{\mathrm{cal}}=\{(X_i,Y_i)\}_{i=1}^n. A fresh test pair is (Xn+1,Yn+1)(X_{n+1},Y_{n+1}). Conditional on the fitted score function, require these n+1n+1 calibration and test scores to be exchangeable. Independent observations from one distribution, with an independent fitting split, are a sufficient setting. The separate test sample in the example evaluates the completed procedure.

Confidence intervals, prediction intervals, and prediction sets

Before building the procedure, distinguish three targets: a population quantity, a future observation, and a class label. The target determines which inclusion statement we need to establish.

A confidence interval targets a population quantity, such as a mean, coefficient or quantile. For example, an interval for μ(x)=E[Y∣X=x]\mu(x)=\mathbb E[Y\mid X=x] aims to contain that fixed conditional mean across repeated fitting samples at the specified input. Its width can shrink under regular consistent estimation; shrinking is not an unconditional property of every confidence procedure.

A prediction interval targets a future observation and aims for a specified inclusion probability. It accounts for response variation as well as uncertainty in the fitted predictor. With persistent nondegenerate noise it can remain wide even when mean estimation is precise. For a symmetric noise distribution, a symmetric band around its center uses the (1−α)(1-\alpha) quantile of the absolute noise as its half-width.

A prediction set is the classification analogue: a random subset C^(x)⊆{1,…,K}\hat C(x) \subseteq \{1,\dots,K\} with P(Yn+1∈C^(Xn+1))≥1−αP\big(Y_{n+1} \in \hat C(X_{n+1})\big) \ge 1-\alpha. Whereas an interval is an ordered range on the real line, a set is an unordered collection of labels, and its natural size measure is cardinality rather than length.

For comparison, consider the correctly specified linear model with nn fitting observations and pp nonconstant predictors plus an intercept. In this comparison only, nn denotes fitting size rather than calibration size. Assume n>p+1n>p+1, a fixed full-rank design, independent Gaussian errors with variance σ2\sigma^2, and an independent future error with the same variance. At a fixed new design vector x0x_0, the Gaussian prediction interval is

y^0±tn−p−1, 1−α/2  σ^1+x0⊤(X⊤X)−1x0,\hat y_0 \pm t_{n-p-1,\,1-\alpha/2}\;\hat\sigma\sqrt{1 + x_0^\top (X^\top X)^{-1} x_0},

where:

  • y^0=x0⊤β^\hat y_0 = x_0^\top \hat\beta: the fitted value at the new input
  • σ^2\hat\sigma^2: the residual variance estimate (the sum of squared residuals divided by n−p−1n-p-1)
  • XX: the full-rank n×(p+1)n\times(p+1) training design matrix, including an intercept column and pp nonconstant predictors
  • tn−p−1,1−α/2t_{n-p-1,1-\alpha/2}: the 1−α/21-\alpha/2 quantile of a tt distribution with n−p−1n-p-1 degrees of freedom
  • x0⊤(X⊤X)−1x0x_0^\top (X^\top X)^{-1} x_0: the new-point leverage, with x0x_0 containing the intercept and the same pp predictors as the design matrix

The "1+1+" inside the square root reflects the additional noise of the future observation. It is there because the error of prediction decomposes as

Yn+1−y^n+1  =  (Yn+1−μ(xn+1))⏟irreducible noise  +  (μ(xn+1)−y^n+1)⏟estimation error.Y_{n+1} - \hat y_{n+1} \;=\; \underbrace{\big(Y_{n+1} - \mu(x_{n+1})\big)}_{\text{irreducible noise}} \;+\; \underbrace{\big(\mu(x_{n+1}) - \hat y_{n+1}\big)}_{\text{estimation error}} .

Under these Gaussian-model assumptions, conditional on the fixed design and new input, the new observation error is independent of the fitting-sample estimation error. Their variances therefore add:

Var⁡(Yn+1−y^n+1)=Var⁡(Yn+1−μ(xn+1))⏟noise variance σ2+Var⁡(μ(xn+1)−y^n+1)⏟estimation variance.\operatorname{Var}(Y_{n+1} - \hat y_{n+1}) = \underbrace{\operatorname{Var}\big(Y_{n+1} - \mu(x_{n+1})\big)}_{\text{noise variance } \sigma^2} + \underbrace{\operatorname{Var}\big(\mu(x_{n+1}) - \hat y_{n+1}\big)}_{\text{estimation variance}} .

where:

  • Yn+1Y_{n+1}: the future observation whose value is not yet known
  • y^n+1\hat y_{n+1}: the fitted model's prediction at the future input xn+1x_{n+1}
  • μ(xn+1)\mu(x_{n+1}): the true conditional mean E[Y∣X=xn+1]\mathbb{E}[Y \mid X = x_{n+1}]
  • σ2\sigma^2: the noise variance Var⁡(Yn+1−μ(xn+1))\operatorname{Var}(Y_{n+1} - \mu(x_{n+1}))

Under regular increasing-sample designs with a fixed number of predictors, mean-estimation uncertainty decreases. The mean confidence interval uses only the estimation term, while the prediction interval also contains the future-noise term. For a 95% Gaussian interval, its large-sample noise margin is approximately 1.96σ1.96\sigma. This comparison explains the extra 11 in the displayed square root.

The weakness of this construction is the assumption stack: Gaussian errors, constant variance, a correctly specified linear model, and independent observations. Split conformal keeps the same target, the observation, but replaces every one of those assumptions with exchangeability alone.

Calibration scores and finite-sample quantiles

The engine of conformal prediction is the nonconformity score. The idea is to condense each candidate pair (x,y)(x, y) and the fitted model f^\hat f into a single number, s(x,y)s(x,y), that grows as the pair becomes less plausible under the model. A score is doing its job when it is small for observations the model explains well and large for observations it explains poorly.

For regression with a scalar response the standard choice is the absolute residual

si=∣ yi−f^(xi) ∣,s_i = \big|\,y_i - \hat f(x_i)\,\big|,

where:

  • sis_i: the nonconformity score for calibration point ii, measuring how far the model's prediction misses the observed response
  • yiy_i: the observed response for calibration point ii
  • f^(xi)\hat f(x_i): the fitted model's prediction for calibration point ii

For classification with fitted class probabilities p^(y∣x)\hat p(y \mid x) the standard choice is

si=1−p^(yi∣xi),s_i = 1 - \hat p\big(y_i \mid x_i\big),

where:

  • sis_i: the nonconformity score for calibration point ii, equal to one minus the probability of the observed label
  • p^(yi∣xi)\hat p(y_i \mid x_i): the fitted probability the model assigns to the observed label yiy_i at input xix_i
  • yiy_i: the observed class label of calibration point ii

This score is small when the model assigns high probability to the observed label and large when it assigns low probability. Many other scores are possible; we will meet several. Choose and freeze the score function without using the calibration or test outcomes for fitting or selection. At prediction time, evaluate it for candidate labels or responses; the unknown true future response is not supplied to the procedure.

Given the scores s1,…,sns_1,\dots,s_n, sort them and write the order statistics as

s(1)≤s(2)≤⋯≤s(n).s_{(1)} \le s_{(2)} \le \dots \le s_{(n)} .

The conformal quantile at miscoverage level α\alpha is the order statistic at index

k=⌈(n+1)(1−α)⌉,k = \left\lceil (n+1)(1-\alpha) \right\rceil ,

For k≤nk\le n, set q^=s(k)\hat q=s_{(k)}. If k=n+1k=n+1, set q^=+∞\hat q=+\infty and return the full response space. Clipping kk to nn would lose the requested guarantee at small calibration sizes.

where:

  • nn: the calibration set size
  • α\alpha: the miscoverage level, so 1−α1-\alpha is the nominal coverage
  • kk: the ceiling index ⌈(n+1)(1−α)⌉\lceil (n+1)(1-\alpha)\rceil, which can equal n+1n+1; that case uses an infinite threshold
  • s(k)s_{(k)}: the kk-th smallest calibration score
  • q^\hat q: the conformal score threshold; for absolute-residual regression it is the interval half-width

This implementation selects an order statistic without interpolation. Other quantile conventions need to be checked against the stated finite-sample cutoff; an ordinary interpolating call is not generally equivalent.

The ⌈⋅⌉\lceil \cdot \rceil symbol denotes the ceiling function: the smallest integer greater than or equal to its argument. For n=100n = 100 and α=0.10\alpha = 0.10 we get (n+1)(1−α)=101×0.90=90.9(n+1)(1-\alpha) = 101 \times 0.90 = 90.9, so k=⌈90.9⌉=91k = \lceil 90.9 \rceil = 91 and q^=s(91)\hat q = s_{(91)}.

To see the role of n+1n+1, first assume the n+1n+1 exchangeable scores are almost surely distinct. The test score then has a uniform rank in {1,…,n+1}\{1,\ldots,n+1\}. For k≤nk\le n, it falls below the kkth calibration score exactly when that rank is at most kk. Thus

P(sn+1≤s(k))=kn+1,P\big(s_{n+1} \le s_{(k)}\big) = \frac{k}{n+1},

where:

  • sn+1s_{n+1}: the nonconformity score of the future test point, an exchangeable draw from the same pool as the calibration scores
  • s(k)s_{(k)}: the kk-th smallest calibration score, used as the conformal quantile q^\hat q
  • kk: the ceiling index ⌈(n+1)(1−α)⌉\lceil (n+1)(1-\alpha)\rceil, computed from the calibration size nn and miscoverage level α\alpha

The equality holds because sn+1≤s(k)s_{n+1} \le s_{(k)} happens exactly when the rank of sn+1s_{n+1} is one of the kk smallest.

The rank calculation behind the guarantee can be inspected directly. With n=10n=10 and α=0.10\alpha=0.10, we have (n+1)(1−α)=11×0.90=9.9(n+1)(1-\alpha)=11\times0.90=9.9, so k=⌈9.9⌉=10k=\lceil9.9\rceil=10. Under distinct exchangeable scores, the test score has eleven equally likely ranks, and ranks one through ten fall at or below the calibrated cutoff s(10)s_{(10)}; only the largest rank falls outside it. The cell below prepares the rank probabilities for the figure: it computes the ceiling index without clipping, builds uniform rank probabilities, and flags the ranks covered by the cutoff. This is an exact rank illustration, with no sampled data.

PythonIn [2]
CollapseExpand
import numpy as np

n_rank = 10
alpha_rank = 0.10
k_rank = int(np.ceil((n_rank + 1) * (1 - alpha_rank)))
ranks = np.arange(1, n_rank + 2)
rank_prob = np.full(ranks.shape, 1.0 / (n_rank + 1))
covered_rank = (k_rank - ranks) >= 0
VisualizationOut [3]
CollapseExpand
Eleven equal rank probabilities; ten covered bars sum to 10/11 and one is uncovered.
Uniform rank probabilities for eleven exchangeable scores at n = 10 and alpha = 0.10. Under distinct exchangeable scores, each rank is equally likely. With k = 10, ranks one through ten are covered by the conformal cutoff, so the covered bars sum to coverage probability 10/11.

Setting k=⌈(n+1)(1−α)⌉k = \lceil (n+1)(1-\alpha)\rceil gives

P(sn+1≤q^)=⌈(n+1)(1−α)⌉n+1  ≥  1−α.P\big(s_{n+1} \le \hat q\big) = \frac{\lceil (n+1)(1-\alpha)\rceil}{n+1} \;\ge\; 1-\alpha .

The ceiling gives the lower bound in the distinct-score case, provided k≤nk\le n so the displayed finite order statistic is used. Below the finite-threshold cutoff, k=n+1k=n+1, so k/(n+1)=1k/(n+1)=1 and the infinite threshold covers the full response space. With ties, independently randomizing the order within equal scores gives a uniform rank, and the deterministic event sn+1≤q^s_{n+1}\le\hat q includes every rank-at-most-kk case. Its probability is therefore at least k/(n+1)k/(n+1), although equality need not hold. If k=n+1k=n+1, the infinite threshold covers the full response space. Using ⌈n(1−α)⌉\lceil n(1-\alpha)\rceil or an ordinary interpolating quantile does not supply this general finite-sample guarantee; the values can coincide for some inputs, so the issue is the missing guarantee rather than universal under-coverage.

There is a matching upper bound. If the scores are almost surely distinct, then

1−α  ≤  P(sn+1≤q^)  ≤  1−α+1n+1,1-\alpha \;\le\; P\big(s_{n+1} \le \hat q\big) \;\le\; 1-\alpha + \frac{1}{n+1},

so the guarantee is tight to within 1/(n+1)1/(n+1). For α=0.10\alpha = 0.10 and n=100n = 100, coverage lands between 0.9000.900 and roughly 0.9100.910. This statement requires exchangeable scores, while leaving the response distribution otherwise unrestricted.

A finite threshold under this convention requires k≤nk\le n, equivalently α≥1/(n+1)\alpha\ge1/(n+1). At least nine calibration observations permit a finite 90% threshold; at least 99 permit a finite 99% threshold. Smaller calibration samples still give valid sets through q^=+∞\hat q=+\infty, but those sets are uninformative. These cutoffs do not guarantee stable or narrow finite thresholds.

The finite-threshold cutoff is only part of the story. At fixed α\alpha, the guaranteed floor k/(n+1)k/(n+1) equals one while the infinite-threshold branch is active at small calibration sizes. Once a finite threshold exists, the ceiling index makes the floor vary nonmonotonically as nn grows. The figure below plots the rank-based floors for calibration sizes from 1 to 200. It evaluates the formula directly, with no sampled data.

PythonIn [4]
CollapseExpand
n_grid = np.arange(1, 201)


def coverage_floor_for(nominal):
    alpha_level = 1.0 - nominal
    k = np.ceil((n_grid + 1) * (1.0 - alpha_level)).astype(int)
    return np.where(k > n_grid, 1.0, k / (n_grid + 1))


coverage_floor_90 = coverage_floor_for(0.90)
coverage_floor_95 = coverage_floor_for(0.95)
VisualizationOut [5]
CollapseExpand
Coverage floors by calibration size for nominal 0.90 and 0.95, with granular steps.
Finite-sample guaranteed coverage floor k/(n+1) against calibration-set size for nominal 0.90 and 0.95. The sawtooth shows rank granularity: between ceiling-index jumps the ratio falls, then rises at the next jump. The floor equals one while the infinite-threshold branch is active at small calibration sizes.

This bound arises because k≤nk \le n requires ⌈(n+1)(1−α)⌉≤n\lceil (n+1)(1-\alpha)\rceil \le n, equivalently (n+1)(1−α)≤n(n+1)(1-\alpha) \le n since nn is an integer. Solving:

(n+1)(1−α)≤nn+1−αn−α≤n1−α≤αnn≥1−αα=1α−1.\begin{aligned} (n+1)(1-\alpha) &\le n \\ n+1 - \alpha n - \alpha &\le n \\ 1 - \alpha &\le \alpha n \\ n &\ge \frac{1-\alpha}{\alpha} = \frac{1}{\alpha} - 1 . \end{aligned}

Split conformal regression and classification

Putting the pieces together, split conformal regression is a four-step procedure, sometimes called inductive conformal prediction (Papadopoulos et al., 2002). Notice how cleanly the steps separate the modelling from the calibration. The model is fit and frozen first, and only then does the conformal machinery measure its mistakes.

  1. Fit the point predictor f^\hat f on Dtrain\mathcal{D}_{\text{train}}. Nothing about this step is special; use whatever model you like and whatever model selection procedure you like, as long as it never touches Dcal\mathcal{D}_{\text{cal}}.
  2. Compute calibration scores si=∣yi−f^(xi)∣s_i = |y_i - \hat f(x_i)| for i=1,…,ni = 1,\dots,n.
  3. Compute k=⌈(n+1)(1−α)⌉k=\lceil(n+1)(1-\alpha)\rceil. Set q^=s(k)\hat q=s_{(k)} if k≤nk\le n and q^=+∞\hat q=+\infty otherwise.
  4. For a new input xx, return C^(x)=[f^(x)−q^,  f^(x)+q^]\hat C(x) = \big[\hat f(x) - \hat q,\; \hat f(x) + \hat q\big] when q^\hat q is finite, and return the full response space when q^=+∞\hat q = +\infty.

The interval is the point prediction plus or minus a constant margin. When q^\hat q is finite its width is exactly 2q^2\hat q everywhere, independent of xx; when q^=+∞\hat q = +\infty the set is the full response space. Here q^\hat q is the conformal quantile computed from calibration scores, and there is no guarantee that averaging a realized test batch reproduces the nominal coverage. That is both its simplicity and its main weakness, and we will return to the consequence shortly.

Step 4 is worth reading backwards, because that is how the guarantee is usually proved. The event Yn+1∈C^(Xn+1)Y_{n+1} \in \hat C(X_{n+1}) is the same as ∣Yn+1−f^(Xn+1)∣≤q^|Y_{n+1} - \hat f(X_{n+1})| \le \hat q, which is the same as sn+1≤q^s_{n+1} \le \hat q. Everything reduces to the rank argument in the previous subsection. The proof does not require a particular predictor family or parametric response law. Its sampling argument uses exchangeability of the held-out scores.

For classification, the same four steps apply with a different score, and step 4 becomes a set construction:

C^(x)={ y∈{1,…,K}  :  1−p^(y∣x)≤q^ }={ y  :  p^(y∣x)≥1−q^ }.\hat C(x) = \big\{\, y \in \{1,\dots,K\} \;:\; 1 - \hat p(y \mid x) \le \hat q \,\big\} = \big\{\, y \;:\; \hat p(y \mid x) \ge 1 - \hat q \,\big\}.

where:

  • yy: a candidate class label in {1,…,K}\{1,\dots,K\}
  • p^(y∣x)\hat p(y \mid x): the fitted probability the model assigns to label yy at input xx
  • q^\hat q: the conformal quantile from the calibration scores, so 1−q^1-\hat q is the probability threshold

For the score 1−p^(y∣x)1-\hat p(y\mid x), classification keeps labels whose fitted probability is at or above 1−q^1-\hat q. The calibration step chooses the threshold automatically, in such a way that the fraction of calibration points whose nonconformity score 1−p^(yi∣xi)1-\hat p(y_i\mid x_i) exceeds q^\hat q is at most α\alpha. This uses held-out outcomes to calibrate set inclusion. It is different from Probability Calibration, which evaluates or adjusts probability reliability. Accurate class probabilities are useful, but are not required for this marginal set-coverage proof.

The threshold applies to each candidate label, so set size varies with the probability vector and the calibrated cutoff. Several labels may pass, or none may pass. The marginal guarantee controls overall inclusion under its sampling assumptions. For a proper nonempty subset of the class space, set size alone does not determine its conditional inclusion probability. Set size alone also does not establish an out-of-distribution interpretation.

Mathematical Properties

Several properties follow from the construction and are worth naming. Treat them as a checklist of what the formula does and does not give us.

  • Coverage is finite-sample. Under the score-exchangeability condition, P(Yn+1∈C^(Xn+1))≥1−αP(Y_{n+1}\in\hat C(X_{n+1}))\ge1-\alpha holds for every n≥1n\ge1 and 0<α<10<\alpha<1, using the infinite-threshold branch when necessary. No asymptotic approximation is used.
  • The guarantee is distribution-free over score distributions satisfying exchangeability. The predictor and score construction must be fixed before calibration; no correctly specified parametric response model is required.
  • Monotonicity in α\alpha. With the same calibration scores, decreasing α\alpha cannot decrease kk or q^\hat q. The sets are nested, although the discrete index can stay unchanged over a range of levels.
  • Invariance to monotone rescaling of scores. Replacing ss by any strictly increasing transform g(s)g(s) yields the same prediction sets, since the ranking is unchanged. The transform must be well-defined and the same for every calibration and candidate score. The small-calibration branch still returns the full response space; it does not require evaluating g(+∞)g(+\infty). Dividing by an input-dependent scale is a different score construction and can change the resulting sets.
  • Width depends on the score distribution. With a fixed score and independent calibration samples growing in size, the empirical cutoff converges to its population score quantile at continuity and identifiability points. When the fitted score also changes, additional consistency assumptions are needed. Improving a predictor under one loss does not universally shrink every conformal cutoff.
  • Ties can make deterministic inclusion conservative: P(sn+1≤q^)P(s_{n+1}\le\hat q) may exceed k/(n+1)k/(n+1). This removes the distinct-score upper slack bound; it does not by itself prove that an interval can be narrowed while keeping the same guarantee.

Example

A small numerical example makes the quantile convention concrete. Let us work through a complete split conformal calculation by hand with ten calibration points and a simple regression model, so that every index in the formula is visible.

We have fitted f^\hat f on a training set and evaluated it on a calibration set of n=10n = 10 points, obtaining absolute residuals. Sorted, they are

0.05,  0.12,  0.19,  0.27,  0.31,  0.45,  0.53,  0.62,  0.74,  0.88.0.05,\; 0.12,\; 0.19,\; 0.27,\; 0.31,\; 0.45,\; 0.53,\; 0.62,\; 0.74,\; 0.88 .

The largest residual is 0.880.88 in the response units of this illustrative example. Suppose we want 90% coverage, so α=0.10\alpha=0.10 and 1−α=0.901-\alpha=0.90. The index is

k=⌈(n+1)(1−α)⌉=⌈(10+1)×0.90⌉=⌈9.9⌉=10.k = \left\lceil (n+1)(1-\alpha) \right\rceil = \left\lceil (10+1)\times 0.90 \right\rceil = \lceil 9.9 \rceil = 10 .

where:

  • n=10n = 10: the calibration set size
  • α=0.10\alpha = 0.10: the miscoverage level, so 1−α=0.901-\alpha = 0.90 is the nominal coverage
  • kk: the ceiling index, which selects the kk-th smallest calibration score

Because k=10=nk = 10 = n, the conformal quantile is the largest observed residual, q^=0.88\hat q = 0.88. A new input with f^(x)=5.00\hat f(x) = 5.00 gets the interval

C^(x)=[ 5.00−0.88,  5.00+0.88 ]=[ 4.12,  5.88 ].\hat C(x) = [\,5.00 - 0.88,\; 5.00 + 0.88\,] = [\,4.12,\; 5.88\,].

If the realized value turns out to be y=5.5y = 5.5, it is inside the interval and this particular point is covered. If y=6.2y = 6.2, it is not; the interval width of 1.761.76 is simply not enough to catch a miss that large. The marginal guarantee averages over calibration and fresh test draws; it does not certify this particular point.

With almost surely distinct exchangeable scores, the repeated-sample coverage for this rule is 10/11≈0.90910/11\approx0.909. With ties, that value is a lower bound. This is a statement about the procedure over calibration and test draws, not the conditional coverage of the particular ten residuals displayed above. At this level and calibration size, the rule selects the sample maximum.

Now compare an 80% interval, α=0.20\alpha = 0.20. Then

k=⌈(n+1)(1−α)⌉=⌈11×0.80⌉=⌈8.8⌉=9,k = \left\lceil (n+1)(1-\alpha) \right\rceil = \left\lceil 11 \times 0.80 \right\rceil = \lceil 8.8 \rceil = 9,

where:

  • α=0.20\alpha = 0.20: the miscoverage level, so 1−α=0.801-\alpha = 0.80
  • k=9k = 9: the resulting index, so q^=s(9)=0.74\hat q = s_{(9)} = 0.74
  • n=10n = 10: the calibration set size, giving the rank lower bound 9/(10+1)≈0.8189/(10+1) \approx 0.818; equality holds for almost surely distinct exchangeable scores, while ties can, but need not, increase coverage

With q^=0.74\hat q = 0.74, the same prediction becomes [4.26,5.74][4.26, 5.74], narrower as expected, with guarantee 9/11≈0.8189/11 \approx 0.818.

The (n+1)(n+1) convention matters here. Suppose we had carelessly used ⌈n(1−α)⌉\lceil n(1-\alpha) \rceil instead. For α=0.10\alpha = 0.10 that gives ⌈9.0⌉=9\lceil 9.0 \rceil = 9 and q^=0.74\hat q = 0.74, exactly the margin we should have used for the 80% interval. The reported interval would cover about 9/10=0.909/10 = 0.90 of calibration points, matching the nominal level on the calibration data, yet its coverage of future points is only guaranteed at the lower level k/(n+1)=9/11≈0.818k/(n+1) = 9/11 \approx 0.818, not at the nominal 0.900.90. The shortfall comes from replacing (n+1)(n+1) with nn: the resulting index is too small by roughly one position, so at α=0.10\alpha = 0.10 the effective guarantee falls below the nominal 0.900.90. The wrong index can appear correct on the data used to compute it.

Now the classification case. Suppose the same ten calibration points give scores 1−p^(yi∣xi)1 - \hat p(y_i \mid x_i), sorted:

0.02,  0.05,  0.11,  0.18,  0.22,  0.30,  0.41,  0.55,  0.66,  0.80.0.02,\; 0.05,\; 0.11,\; 0.18,\; 0.22,\; 0.30,\; 0.41,\; 0.55,\; 0.66,\; 0.80 .

At α=0.10\alpha = 0.10 we again have

k=⌈(n+1)(1−α)⌉=⌈11×0.90⌉=10.k = \left\lceil (n+1)(1-\alpha) \right\rceil = \left\lceil 11 \times 0.90 \right\rceil = 10 .

So q^=s(10)=0.80\hat q = s_{(10)} = 0.80, giving the probability threshold 1−0.80=0.201 - 0.80 = 0.20:

  • k=10k = 10: the resulting index, the tenth smallest calibration score
  • q^=0.80\hat q = 0.80: the conformal quantile, equal to s(10)s_{(10)}
  • 1−q^=0.201-\hat q = 0.20: the calibrated probability threshold applied to each class

A new input with class probabilities (0.55,0.30,0.15)(0.55, 0.30, 0.15) yields the set {A,B}\{A, B\}: AA and BB clear the 0.200.20 bar and CC does not. The set has size two. If the true label is CC, this set misses it. The marginal bound does not assign an error probability to this particular vector or set.

Consider a classifier that spreads its probability mass across all three labels. Suppose the probabilities for some input are (0.40,0.33,0.27)(0.40, 0.33, 0.27). Since all three exceed 0.200.20, the prediction set is all three labels. That input is effectively unclassified, and the set says so. Conversely, an input with probabilities (0.90,0.07,0.03)(0.90, 0.07, 0.03) yields the singleton {A}\{A\}. Set size reports how many labels this score and calibrated threshold retain at that input. It does not supply a calibrated probability that a singleton is correct or prove that an empty set is out of distribution.

Implementation in NumPy and scikit-learn

We build the conformal quantile and interval arithmetic from NumPy primitives, using scikit-learn for the base predictors. Fitting and calibration data construct the intervals; untouched test data evaluate them. The example keeps all three roles disjoint and performs no model or score selection using calibration or test outcomes.

The data are one-dimensional and heteroscedastic, with the noise standard deviation growing quadratically away from the origin. This is a realistic situation where a constant-width interval will struggle, so it doubles as a stress test.

PythonIn [7]
CollapseExpand
def make_data(n, rng, shift=0.0):
    """y = sin(x) + 0.5x + noise whose sd grows with |x|."""
    x = rng.uniform(-3.0, 3.0, size=n) + shift
    sigma = 0.30 + 0.25 * x**2  # heteroscedastic noise scale
    y = np.sin(x) + 0.5 * x + rng.normal(0.0, 1.0, size=n) * sigma
    return x, y


x_all, y_all = make_data(6000, rng)

# Three disjoint roles: fit, calibrate, evaluate.
x_tr, y_tr = x_all[:3000], y_all[:3000]
x_ca, y_ca = x_all[3000:4500], y_all[3000:4500]
x_te, y_te = x_all[4500:], y_all[4500:]

We fit an ordinary least-squares line even though the synthetic mean is nonlinear. This makes model misspecification visible. The held-out calibration procedure still has its marginal coverage guarantee under the sampling assumptions, but the predictor and score can produce inefficient intervals or uneven local coverage.

PythonIn [8]
CollapseExpand
X_tr, X_ca, X_te = (a.reshape(-1, 1) for a in (x_tr, x_ca, x_te))

model = LinearRegression().fit(X_tr, y_tr)
pred_ca = model.predict(X_ca)
pred_te = model.predict(X_te)

conformal_quantile implements the explicit order-statistic rule and its infinite-threshold case. regression_intervals adds the calibrated margin to predictions. Sorting and indexing make the finite-sample convention visible; calling an ordinary interpolating quantile at 1−α1-\alpha is not generally equivalent.

PythonIn [9]
CollapseExpand
def conformal_quantile(scores, alpha):
    """Finite-sample conformal quantile: the ceil((n+1)(1-alpha))-th smallest score."""
    scores = np.asarray(scores, dtype=float)
    if scores.ndim != 1 or scores.size == 0 or not np.all(np.isfinite(scores)):
        raise ValueError(
            "scores must be a nonempty finite one-dimensional array"
        )
    if not np.isscalar(alpha) or not np.isfinite(alpha) or not 0 < alpha < 1:
        raise ValueError("alpha must lie strictly between zero and one")
    n = scores.size
    k = int(np.ceil((n + 1) * (1 - alpha)))
    if k > n:
        return np.inf, k
    return float(np.sort(scores)[k - 1]), k


def regression_intervals(pred, q_hat, scale=1.0):
    """Symmetric conformal band; `scale` lets us plug in a local noise estimate."""
    return pred - q_hat * scale, pred + q_hat * scale


# Small calibration samples must use the full-space branch rather than clipping.
assert np.isinf(conformal_quantile([0.5, 0.8, 1.2, 2.5], 0.10)[0])
assert conformal_quantile([0.5, 0.8, 1.2, 2.5], 0.20) == (2.5, 4)
assert conformal_quantile(np.arange(19), 0.10) == (17.0, 18)

With those in hand, the entire method is six lines.

PythonIn [10]
CollapseExpand
alpha = 0.10
scores_ca = np.abs(y_ca - pred_ca)
q_hat, k_ca = conformal_quantile(scores_ca, alpha)

lo, hi = regression_intervals(pred_te, q_hat)
covered = (y_te >= lo) & (y_te <= hi)
ConsoleOut [11]
CollapseExpand
n_cal = 1500, k = 1351, q_hat = 2.338
empirical test coverage = 0.909  (nominal target = 0.90)
mean interval width     = 4.675

The printed coverage describes this realized held-out sample. Constant-width intervals can cover more often near the low-noise center and less often in the noisy tails. The mean width alone does not reveal those local differences, and a result near nominal in this run is not proof of conditional or per-sample validity.

The sweep applies several nominal levels to the same calibration scores and test data. Each row changes the quantile cutoff and recomputes inclusion; for levels that require the infinite-threshold branch the row reports the full response space and its empirical coverage is one. The rows are related evaluations of one sample, not independent replications or a guarantee that every measured coverage exceeds nominal.

PythonIn [12]
CollapseExpand
alphas = np.array([0.02, 0.05, 0.10, 0.20, 0.30, 0.40, 0.50])
rows = []
for a in alphas:
    q, kk = conformal_quantile(scores_ca, a)
    l, h = regression_intervals(pred_te, q)
    rows.append(
        {
            "alpha": a,
            "nominal": 1 - a,
            "k": kk,
            "q_hat": q,
            "test_coverage": ((y_te >= l) & (y_te <= h)).mean(),
            "mean_width": np.mean(h - l),
        }
    )

coverage_table = pd.DataFrame(rows)
Out[13]:
alpha nominal k q_hat test_coverage mean_width
0 0.02 0.98 1471 3.859 0.974 7.719
1 0.05 0.95 1426 3.083 0.957 6.167
2 0.10 0.90 1351 2.338 0.909 4.675
3 0.20 0.80 1201 1.550 0.817 3.100
4 0.30 0.70 1051 1.086 0.720 2.172
5 0.40 0.60 901 0.818 0.619 1.636
6 0.50 0.50 751 0.634 0.524 1.267

The interval width grows as nominal coverage rises. Empirical test coverage fluctuates around the target and can fall below it for a particular calibration sample and finite test set; the marginal theorem does not require every row of this table to exceed nominal.

Constants and Calibration Size

Three key design choices are the miscoverage level α\alpha, the calibration size nn, and the score. Understanding their roles is what separates a working deployment from a mysterious one.

The level α\alpha specifies the tolerated marginal miscoverage. Its choice depends on the decision, the cost of misses and the usefulness of the resulting sets. Calibration size constrains whether that level permits a finite cutoff, and the experiment uses α=0.10\alpha=0.10 as an illustrative choice.

The calibration size controls rank granularity. With distinct scores the coverage excess from rounding is less than 1/(n+1)1/(n+1); this is a probability-scale bound, not a universal bound on excess interval width. For example, n=19n=19 and α=0.10\alpha=0.10 give k=18k=18. Quantile variability also depends on the score distribution, especially its density near the cutoff, so there is no distribution-free sample count that guarantees a stable narrow interval.

The score is the main modelling lever. Absolute residuals give constant width. Normalized residuals give locally adaptive width. Signed residuals give one-sided bounds. We turn to the adaptive case next, because it is where the constant-width weakness becomes visible.

Normalized Scores

Absolute-residual scores use the same cutoff at every input. An input-dependent positive scale can redistribute width. Fix that scale using fitting data only, then calibrate si=∣yi−f^(xi)∣/σ^(xi)s_i=|y_i-\hat f(x_i)|/\hat\sigma(x_i). The same exchangeability proof applies, because the score is fixed before calibration. Here σ^(x)>0\hat\sigma(x)>0 is an error-scale proxy, not a validated conditional standard deviation; the construction does not guarantee improved conditional coverage.

We build σ^(x)\hat\sigma(x) by regressing the training absolute residuals on ∣x∣|x|, then clip it away from zero to avoid division blow-ups. This is a crude but honest noise model, and it is fitted only on training data, consistent with the requirement that the score function be frozen before calibration.

PythonIn [14]
CollapseExpand
abs_res_tr = np.abs(y_tr - model.predict(X_tr))
scale_model = LinearRegression().fit(np.abs(x_tr).reshape(-1, 1), abs_res_tr)


def sigma_hat(x):
    """Local noise scale, fitted on TRAIN residuals only."""
    return np.maximum(scale_model.predict(np.abs(x).reshape(-1, 1)), 1e-2)


scores_ca_n = np.abs(y_ca - pred_ca) / sigma_hat(x_ca)
q_norm, k_norm = conformal_quantile(scores_ca_n, alpha)

lo_n, hi_n = regression_intervals(pred_te, q_norm, sigma_hat(x_te))
covered_n = (y_te >= lo_n) & (y_te <= hi_n)
ConsoleOut [15]
CollapseExpand
constant-width   coverage = 0.909, mean width = 4.675
normalized-score coverage = 0.898, mean width = 4.138

The printed results show how normalization changes both width and measured coverage. The normalized version allocates less width near the origin and more width at larger ∣x∣|x|, but this crude scale model can still under-cover a region. Its empirical test coverage can also lie below nominal. Both score choices have the same type of marginal guarantee, rather than identical realized coverage or guaranteed local accuracy.

Next we demonstrate the failure mode. We keep the model and the calibrated quantile fixed, then evaluate on data drawn from a shifted input distribution. The input shift breaks exchangeability with calibration, so the ordinary coverage theorem no longer applies. The following evaluation measures what happens in this sample.

PythonIn [16]
CollapseExpand
x_sh, y_sh = make_data(
    1500, np.random.default_rng(99), shift=1.5
)  # inputs pushed right

pred_sh = model.predict(x_sh.reshape(-1, 1))
lo_sh, hi_sh = regression_intervals(pred_sh, q_hat)
cov_sh = ((y_sh >= lo_sh) & (y_sh <= hi_sh)).mean()
ConsoleOut [17]
CollapseExpand
exchangeable test coverage = 0.909
shifted test coverage      = 0.807  (nominal target = 0.90)

The shifted set is covered far less often than nominal. Nothing about the model or the quantile changed; only the assumption did. The guarantee depends on the specified set-valued procedure and the joint distribution of calibration and test scores. When the deployment distribution differs from the calibration distribution, coverage can fall below nominal and must be monitored empirically.

Classification follows the same recipe with a different score. We generate a three-class problem, fit a multinomial logistic regression, and conformalize it.

PythonIn [18]
CollapseExpand
Xc, yc = make_classification(
    n_samples=6000,
    n_features=8,
    n_informative=5,
    n_redundant=0,
    n_classes=3,
    n_clusters_per_class=1,
    class_sep=0.9,
    random_state=0,
)
Xc_tr, yc_tr = Xc[:3000], yc[:3000]
Xc_ca, yc_ca = Xc[3000:4500], yc[3000:4500]
Xc_te, yc_te = Xc[4500:], yc[4500:]

clf = LogisticRegression(max_iter=1000).fit(Xc_tr, yc_tr)
p_ca = clf.predict_proba(Xc_ca)
p_te = clf.predict_proba(Xc_te)

# Nonconformity score: 1 minus the probability assigned to the true label.
s_cls = 1.0 - p_ca[np.arange(yc_ca.size), yc_ca]
q_cls, k_cls = conformal_quantile(s_cls, alpha)
threshold = 1.0 - q_cls

in_set = p_te >= threshold  # (n_test, n_classes) boolean
set_sizes = in_set.sum(axis=1)
covered_cls = in_set[np.arange(yc_te.size), yc_te]
ConsoleOut [19]
CollapseExpand
n_cal = 1500, k = 1351, q_hat = 0.690
probability threshold      = 0.310
empirical test coverage    = 0.895  (nominal target = 0.90)
mean prediction set size   = 1.18
singleton sets             = 0.819
empty sets                 = 0.000

The printed classification coverage can be slightly below nominal on this finite test sample. In this seeded run there are no empty sets: most inputs receive one label, some receive two, and one receives all three. A calibration-set check is different from a test-set guarantee: by construction, the fraction of calibration scores above the chosen cutoff is at most α\alpha. None of these summaries gives conditional correctness for a specific singleton.

Key Parameters

The main parameters that govern the conformal procedure are the miscoverage level α\alpha, the calibration size nn, and the choice of nonconformity score.

  • alpha: The miscoverage level, so 1−α1-\alpha is the nominal coverage. It specifies the target marginal miscoverage and determines the interval width through the quantile index. There is no universally correct value; this example uses 0.100.10.
  • n (calibration size): Controls the rank grid and the probability-scale rounding bound. A finite threshold requires n≥1/α−1n\ge1/\alpha-1; otherwise the full-space branch is valid. Stability and width also depend on the score distribution.
  • scores (nonconformity score): The main modelling lever. Absolute residuals give constant-width intervals; scaled residuals (dividing by a training-only local noise estimate) give locally adaptive width; signed residuals give one-sided bounds. The same strictly increasing scalar transform applied to every score preserves the sets; an input-dependent normalization generally changes them.

Visualizing Split Conformal Prediction

The figures reuse the fitted models, calibration scores and test observations. Ordinary calculation cells prepare the additional cutoff, prediction grid, bin summaries and set-size counts; rendering cells do not refit the models or regenerate the data.

The histogram displays calibration absolute residuals and the cutoffs for two nominal levels. Scores to the right of a cutoff exceed that calibrated margin. The plot illustrates an empirical order statistic, not a promise that an identical fraction of every future batch will lie in the tail. It is a descriptive view of one synthetic calibration sample drawn once from the seeded generator, not a repeated-seed evaluation of variability in the cutoff.

PythonIn [20]
CollapseExpand
q20, _ = conformal_quantile(scores_ca, 0.20)
VisualizationOut [21]
CollapseExpand
Histogram of 1500 calibration absolute residuals on the heteroscedastic sine-plus-linear response, heavily right skewed, with dotted and dashed vertical lines marking the empirical conformal margins at 80% and 90% coverage, respectively.
Distribution of calibration nonconformity scores (absolute residuals) on the heteroscedastic dataset, with the 90% and 80% conformal margins marked. The right-skewed distribution shows the width cost of raising the target: the 90% margin exceeds the 80% margin on the same scores. The horizontal axis ends at the empirical 99.5th percentile, so the most extreme scores are outside the displayed range.

The calibration residuals have a long right tail in this synthetic example. The 90% cutoff exceeds the 80% cutoff, illustrating the width cost of the higher target on these same scores. The size of that increase depends on the score distribution.

The second figure shows the intervals themselves in input space. The band is the model plus and minus the fixed margin, and the points are test observations coloured by whether they fall inside.

PythonIn [22]
CollapseExpand
grid = np.linspace(x_te.min(), x_te.max(), 200)
grid_pred = model.predict(grid.reshape(-1, 1))
VisualizationOut [23]
CollapseExpand
Scatter of 1500 test observations against a fitted linear trend, with a sloped band of constant vertical width; most points inside the band are blue, while red outside points cluster at large positive and negative x where the noise is largest.
Constant-width split conformal band around the fitted line on held-out test data. Points inside the band are shown in blue and points outside in red. The uncovered points cluster at the extremes of x where the noise is largest, so the band is too wide in the low-noise centre and too narrow in the tails.

On this seeded test split, the uncovered points are more frequent at large absolute inputs, where the noise is larger. The band has the same vertical width everywhere, so it cannot adapt to that local noise. The binned coverage in the next figure measures the difference directly.

The third figure quantifies that gap. We split the test inputs into five bins by ∣x∣|x| and compute coverage within each bin, for the constant-width and the normalized-score intervals. The horizontal line marks nominal coverage.

PythonIn [24]
CollapseExpand
n_bins = 5
bin_edges = np.quantile(np.abs(x_te), np.linspace(0, 1, n_bins + 1))
bin_idx = np.clip(np.digitize(np.abs(x_te), bin_edges[1:-1]), 0, n_bins - 1)
centers, cov_const, cov_norm_b = [], [], []
for b in range(n_bins):
    mask = bin_idx == b
    centers.append(np.abs(x_te)[mask].mean())
    cov_const.append(covered[mask].mean())
    cov_norm_b.append(covered_n[mask].mean())
VisualizationOut [25]
CollapseExpand
Line chart with five bins of absolute x on the horizontal axis; the constant-width series falls from high coverage near the origin to lower coverage farther out, while the normalized-score series is below nominal in the innermost bin and varies across the others.
Coverage within bins of |x| for the constant-width and normalized-score intervals. The constant-width series falls as absolute input grows, and the crude normalized score also under-covers the innermost bin. Neither method has a conditional-coverage guarantee, so similar overall coverage can hide quite different local failures.

Because the horizontal axis is ∣x∣|x|, moving right means moving farther from the low-noise center. Constant-width coverage falls at larger ∣x∣|x|. Normalization changes that pattern, but its crude scale estimate also under-covers the innermost bin. Similar overall coverage can therefore coexist with quite different local failures; neither score has a conditional-coverage guarantee.

The fourth figure shows coverage against nominal level for the sweep we computed, with the shifted-distribution result plotted as a single failing point.

VisualizationOut [26]
CollapseExpand
Line chart of empirical coverage against nominal coverage from 0.50 to 0.98; the exchangeable curve lies near and can cross the diagonal, while a single red marker at nominal 0.90 sits far below it, well under nominal.
Empirical coverage versus nominal coverage on exchangeable held-out data, with the 45-degree reference line. The exchangeable curve lies near the diagonal and can cross it because calibration and test samples are finite, while the shifted-distribution evaluation at nominal 0.90 falls far below the line, illustrating that the guarantee is not a property of the algorithm alone.

The exchangeable evaluation lies near the diagonal and can cross it because calibration and test samples are finite. The shifted sample has coverage of about 0.807 at the same nominal 0.90 level. The predictor and calibrated margin are unchanged in that comparison; the input distribution was deliberately shifted. These are evaluations of one calibration sample and one shifted test draw, illustrating a failure mode when the original sampling assumption no longer applies.

The final figure summarizes the classification side. The distribution of prediction-set sizes tells us how much work the conformal threshold is doing.

PythonIn [27]
CollapseExpand
sizes = np.arange(0, set_sizes.max() + 1)
counts = np.array([(set_sizes == s).sum() for s in sizes])
VisualizationOut [28]
CollapseExpand
Bar chart of prediction set sizes from zero to three classes for 1500 test inputs, dominated by singleton sets, with a smaller bar at size two, one observation at size three, and zero observations at size zero.
Distribution of conformal prediction set sizes on held-out classification data at a nominal 90% level. Most inputs receive a single label, some receive two, one receives three, and no empty sets occur in this seeded run. Set size counts the labels retained by this score and calibrated cutoff.

Set size counts the labels retained by this particular probability score and calibrated cutoff. A larger set leaves more labels unresolved.

  • An empty set necessarily misses the true label.
  • A set containing all KK labels necessarily includes the true label, provided the declared class space is exhaustive.
  • The size of a proper nonempty subset, including a singleton when K>1K>1, does not by itself determine an individual inclusion probability.

Set size alone does not identify an out-of-distribution input. Those conditional error-rate and out-of-distribution interpretations require separate evaluation. The displayed counts come from one seeded classification split, so the absence of empty sets is a conditional observation on that sample rather than a repeated-seed estimate of the empty-set rate.

Practical Implications

Split conformal is useful when a fitted predictor needs an additional marginal inclusion guarantee and an appropriate held-out calibration sample is available. Valuation or screening examples can use width to expose the limits of a point prediction. Classification sets can support routing or abstention rules, but those selected decisions need separate evaluation. Sequential demand forecasting additionally requires an argument for its dependence and deployment assumptions; ordinary split conformal is not automatically valid there.

Fit and select the predictor, preprocessing and score using fitting data only, then use held-out calibration outcomes to choose the cutoff. Keep evaluation outcomes outside those choices as well. Data-reuse alternatives such as jackknife+ and CV+ require their own refitting procedures and coverage results. Conformalized quantile regression, discussed in relation to Quantile Regression, calibrates a score built from fitted lower and upper quantile functions. It can redistribute width in heteroscedastic problems; neither the initial quantile fit nor its conformalized version automatically supplies distribution-free conditional coverage.

Plan calibration size against the desired level. A finite cutoff is available when α≥1/(n+1)\alpha\ge1/(n+1); otherwise the infinite threshold still gives valid but uninformative sets. The distinct-score rounding excess is below 1/(n+1)1/(n+1), while the sampling variability and width of the cutoff depend on the score distribution. Report observed coverage together with a width summary and the calibration and evaluation sample sizes.

Two implementation pitfalls are worth checking directly. An ordinary call to np.quantile(scores, 1-alpha) need not implement the required finite-sample index. Computing scores from data used to fit or select the predictor can also invalidate the held-out proof. Training errors can be optimistic, but the size and direction of a particular test-coverage change are not determined solely by model capacity. Use the specified cutoff and keep the data roles separate.

Monitor labeled deployment outcomes for changes in coverage and width. Refreshing calibration data can respond to a changing population, but it does not itself establish exchangeability. A chronological split, a blocked holdout trained on earlier observations, or a rolling-origin split supports honest temporal evaluation when fitting, preprocessing and feature construction use only information available at each forecast origin; it does not automatically provide conformal validity under serial dependence. Specialized online and dependent-data methods have their own assumptions and targets, such as long-run rather than per-step coverage. Their guarantees must be checked for the intended forecasting task.

When intervals are too wide for the intended decision, examine the predictor and the score as well as the data. Lowering α\alpha asks for higher coverage and cannot narrow intervals built from the same scores. Improving one predictive loss does not universally reduce every conformal quantile, and a narrow interval alone does not establish useful individual coverage. Evaluate the tradeoff on an appropriate held-out population.

Summary

Confidence intervals target population quantities; prediction intervals target future observations. Split conformal constructs sets from a predictor and score fixed before calibration. Compute held-out scores, choose k=⌈(n+1)(1−α)⌉k=\lceil(n+1)(1-\alpha)\rceil, use the kkth calibration score when k≤nk\le n, and use +∞+\infty otherwise. Absolute-residual scores turn that cutoff into a symmetric margin around the prediction.

The guarantee P(Yn+1∈C^(Xn+1))≥1−αP(Y_{n+1}\in\hat C(X_{n+1}))\ge1-\alpha averages over calibration and fresh test draws under score exchangeability. Almost surely distinct scores also give the upper slack bound 1−α+1/(n+1)1-\alpha+1/(n+1); ties can be more conservative. Using an ordinary uncorrected empirical quantile does not provide the same general lower-bound argument.

This marginal guarantee does not ensure conditional or subgroup coverage, nor nominal coverage for every realized test batch. Training-only positive normalization can redistribute width, but our crude scale proxy still has local failures. Classification uses the same rank mechanism to threshold candidate label scores. An empty classification set necessarily misses the true label; a set containing every label in an exhaustive class space necessarily includes it. For proper nonempty subsets, cardinality alone does not calibrate individual inclusion.

Check score construction and data roles before interpreting the guarantee. Distribution shift, ordinary serial dependence and reuse of calibration outcomes for model selection can remove its justification. Keep fitting, calibration and evaluation separate, handle the infinite-threshold case explicitly, and monitor labeled deployment outcomes. The coverage theorem is a precise probability statement under assumptions, not a promise that every reported interval or observed batch succeeds.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about prediction intervals and split conformal prediction.

Prediction Intervals and Split Conformal Prediction

Question 1 of 80 of 8 completed
Which statement best distinguishes a prediction interval from a confidence interval for a regression model?
Join the discussionAsk a question or share what you learned.

Comments

Add to the conversation

A question, a correction, or an example from your own work.

No comments yet. Be the first to share your thoughts!

A different angle
All writing
Machine Learning

Probability Calibration

Probability calibration for classifiers: reliability diagrams, Brier score, log loss, sigmoid and isotonic recalibration, and practical monitoring.

41 min read
World Models Handbook · Vol. 4

Frontier Questions and Research Roadmaps

Frontier questions and research roadmaps for world models: generality contracts, causal structure, persistent memory, and decision-relevant evaluation.

98 min read
World Models Handbook · Vol. 4

Sim-to-Real Deployment and Continual Correction

A reproducible sim-to-real workflow covering structural mismatch, domain randomization, delay ablations, residual monitoring, and gated continual correction.

74 min read

About the author

Reference

Citation details

Cite or share this article.

BIBTEXAcademic
@misc{brenndoerfer2026predictionintervals, author = {Michael Brenndoerfer}, title = {Prediction Intervals and Split Conformal Prediction}, year = {2026}, url = {https://mbrenndoerfer.com/writing/prediction-intervals-conformal-from-scratch}, organization = {mbrenndoerfer.com}, note = {Accessed: 2026-10-30} }
APAAcademic
Michael Brenndoerfer (2026). Prediction Intervals and Split Conformal Prediction. Retrieved from https://mbrenndoerfer.com/writing/prediction-intervals-conformal-from-scratch
MLAAcademic
Michael Brenndoerfer. "Prediction Intervals and Split Conformal Prediction." 2026. Web. October 30, 2026. <https://mbrenndoerfer.com/writing/prediction-intervals-conformal-from-scratch>.
CHICAGOAcademic
Michael Brenndoerfer. "Prediction Intervals and Split Conformal Prediction." Accessed October 30, 2026. https://mbrenndoerfer.com/writing/prediction-intervals-conformal-from-scratch.
HARVARDAcademic
Michael Brenndoerfer (2026) 'Prediction Intervals and Split Conformal Prediction'. Available at: https://mbrenndoerfer.com/writing/prediction-intervals-conformal-from-scratch (Accessed: October 30, 2026).
SimpleBasic
Michael Brenndoerfer (2026). Prediction Intervals and Split Conformal Prediction. https://mbrenndoerfer.com/writing/prediction-intervals-conformal-from-scratch
Newsletter

Stay up to date

Get new articles, book updates, and notes on AI and technology.

Unsubscribe at any time. Privacy policy