Prediction Intervals and Split Conformal Prediction › Visualizing Split Conformal Prediction

Michael BrenndoerferOctober 29, 20268 min read
Machine Learning from ScratchAll chapters
Part 12 of 15Calibration and Prediction Uncertainty
Chapter 77Prediction Intervals and Split Conformal Prediction › Visualizing Split Conformal Prediction
Reading section 7 of 10 · Visualizing Split Conformal Prediction · 8 minSection 7 of 10 · 8 min

Section 7 of 10 · 8 min read

Prediction Intervals and Split Conformal Prediction › Visualizing Split Conformal PredictionSection view · Sections in this chapter7 / 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

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.

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!

Newsletter

Stay up to date

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

Unsubscribe at any time. Privacy policy