Get Simultaneous Confidence Bands

Compute confidence bands that guarantee joint coverage over the entire smooth curve, not just at individual points.

A pointwise confidence interval covers the true mean at each location with 95% probability. But it makes no guarantee about the curve as a whole. A simultaneous band is wider: it is constructed so that the entire true curve lies inside the band with 95% probability. Use simultaneous bands when you are making statements about curve shape, such as “the smooth is everywhere positive” or “the effect peaks between times 20 and 40.”

Fit

Fit a single-smooth GAM on the motorcycle helmet dataset.

import whittaker as wk
import numpy as np

data = wk.load_dataset("mcycle")
model = wk.GAM("accel ~ s(times)").fit(data)
model.summary()
GAM fit summary
============================================================
Formula:    accel ~ s(times)
Family:     Gaussian(link='identity')
Inference:  GCV
Observations: 133
Coefficients: 10

Parametric coefficients:
  Term                       Estimate    Std.Err    t value    p-value
  ------------------------ ---------- ---------- ---------- ----------
  (Intercept)                -45.6924     1.8364    -24.882    < 1e-16

Approximate significance of smooth terms:
  Term                        EDF Ref.df     Chi.sq    p-value
  ------------------------ ------ ------ ---------- ----------
  s(times)                   7.92      8    663.379    < 1e-16

Total EDF:  8.92
Scale est:  448.520495
Deviance:   55654.5201
Null dev:   357878.4929
Dev. expl:  84.4%
GCV score:  480.746115
AIC:        1198.44
BIC:        1224.21

Build a prediction grid

Create a dense grid across the full range of times to evaluate both band types.

grid = {"times": np.linspace(data["times"].min(), data["times"].max(), 300)}

Pointwise confidence interval

Pass interval="confidence" to get the standard pointwise band.

# Predict with pointwise confidence intervals
pw = model.predict(grid, interval="confidence")

# Compute mean band width
pw_width = (pw.upper - pw.lower).mean().round(3)
pw_width
np.float64(23.048)

This is the average width of the pointwise interval across the grid.

Simultaneous confidence band

Pass interval="simultaneous" to get the wider joint-coverage band.

# Predict with simultaneous confidence bands
sim = model.predict(grid, interval="simultaneous")

# Compute mean band width
sim_width = (sim.upper - sim.lower).mean().round(3)
sim_width
np.float64(35.08)

The simultaneous band is uniformly wider. The ratio below shows how much the correction inflates the interval to achieve joint coverage.

# Compute width inflation ratio
round(sim_width / pw_width, 3)
np.float64(1.522)

A ratio above 1 confirms the simultaneous band is wider. The magnitude of the inflation depends on the effective degrees of freedom of the smooth (more wiggly smooths require a larger correction).

Compare band widths at every grid point

Look at the width difference across the curve to see where the inflation is largest.

# Compute pointwise width difference across the grid
width_diff = (sim.upper - sim.lower) - (pw.upper - pw.lower)

# Show range of the difference
(width_diff.min().round(3), width_diff.max().round(3))
(np.float64(8.193), np.float64(22.552))

The inflation is not uniform: it is typically largest near the tails where the smooth is less constrained by data.

When to use simultaneous bands

Use interval="simultaneous" whenever your inference involves the curve as a whole:

  • Claiming a smooth is everywhere positive (or negative) over a range.
  • Identifying where an effect peaks or crosses zero.
  • Comparing two smooth curves and asking whether one is uniformly above the other.

Use interval="confidence" when you only need to characterise the mean at a specific, pre-chosen covariate value. For example, reporting the predicted mean at the observed data points.