Split (inductive) conformal prediction for classifiers and regressors.
Classes
class uncertainty.conformal.split.SplitConformalClassifier(ConformalPredictor, SetPredictorMixin)
Split conformal prediction sets with a finite-sample coverage guarantee.
__init__( self, estimator: Any, alpha: float = 0.1, score: str = 'lac', calibration_size: float = 0.25, random_state: Optional[int] = None) -> None, )
Overview
- Split the training data into a proper training part and a calibration
- Fit the wrapped estimator on the proper training part only.
- Score each calibration sample by its nonconformity — how poorly the
- Take the \lceil (n+1)(1-\alpha) \rceil / n empirical quantile
- A test label joins the prediction set when its nonconformity falls below
Theory
With the least-ambiguous-set score s(x, y) = 1 - \hat{p}_y(x) and the corrected quantile \hat{q} of the calibration scores, the set
satisfies
The finite-sample correction is what makes this exact: using the plain 1-\alpha quantile would undercover by roughly 1/n.
Coverage is marginal, averaged over the data draw. It says nothing about coverage for a particular subgroup — see MondrianConformalClassifier for class-conditional validity.
Parameters
estimator
predict_proba.
alpha
1 - alpha.
score
'lac' (least ambiguous set-valued classifier) uses :math:`1 - \hat{p}_y` and gives the smallest average set size; 'margin' uses the gap to the best competing class and adapts better to hard samples.
calibration_size
random_state
Attributes
classes_
fit.
scores_
quantile_
scores_.
fitted_
fit has been called.
Notes
Complexity. One estimator fit plus O(n \log n) for the quantile. Prediction costs one predict_proba call plus O(mc).
When to use. Use split conformal whenever a calibrated set is more useful than a point label — triage, selective prediction, or any setting where abstention is allowed. It is the cheapest conformal method: one model fit. When data is scarce and holding out 25% hurts, use CVPlusRegressor or its classification analogue instead. Calibration needs at least \lceil 1/\alpha \rceil - 1 samples; below that no finite threshold can certify the level and the predictor returns the full label set.
References
See Also
>>> import numpy as np
>>> from tuiml.uncertainty import SplitConformalClassifier
>>> from tuiml.algorithms.trees import DecisionTreeClassifier
>>> rng = np.random.default_rng(0)
>>> X = rng.normal(size=(400, 4))
>>> y = (X[:, 0] + X[:, 1] > 0).astype(int)
>>> cp = SplitConformalClassifier(DecisionTreeClassifier(max_depth=4),
... alpha=0.1, random_state=0)
>>> cp.fit(X, y)
SplitConformalClassifier(estimator=DecisionTreeClassifier(), alpha=0.1)
>>> sets = cp.predict_set(X[:5])
>>> sets.shape
(5, 2)
Methods
fit
(self, X: np.ndarray, y: np.ndarray) -> 'SplitConformalClassifier'
fit
(self, X: np.ndarray, y: np.ndarray) -> 'SplitConformalClassifier'
Fit the estimator on a training split and calibrate on the rest.
Parameters
X
y
Returns
self
fit_calibrated
(self, X_train: np.ndarray, y_train: np.ndarray, X_cal: np.ndarray, y_cal: np.ndarray) -> 'SplitConformalClassifier'
fit_calibrated
(self, X_train: np.ndarray, y_train: np.ndarray, X_cal: np.ndarray, y_cal: np.ndarray) -> 'SplitConformalClassifier'
Fit with an explicit, caller-supplied calibration set.
Parameters
X_train
y_train
X_cal
y_cal
Returns
self
predict_set
(self, X: np.ndarray) -> np.ndarray
predict_set
(self, X: np.ndarray) -> np.ndarray
Predict a boolean class-membership mask.
Parameters
X
Returns
include
include[i, k] is True when class k is in the prediction set of sample i.
class uncertainty.conformal.split.SplitConformalRegressor(ConformalPredictor)
Split conformal prediction intervals with guaranteed coverage.
__init__( self, estimator: Any, alpha: float = 0.1, calibration_size: float = 0.25, normalize: bool = False, random_state: Optional[int] = None) -> None, )
Overview
- Split the training data into a proper training part and a calibration
- Fit the wrapped regressor on the proper training part only.
- Take the absolute residual |y - \hat{y}| on each calibration
- The corrected empirical quantile of those residuals is the interval
Theory
With \hat{q} the corrected quantile of the calibration residuals,
satisfies P(Y_{n+1} \in C(X_{n+1})) \geq 1 - \alpha.
The width is constant across the input space, which is exactly its weakness: a homoscedastic interval over-covers where the model is confident and under-covers where it is not. Setting normalize=True divides residuals by a fitted difficulty estimate to restore local adaptivity, and ConformalizedQuantileRegressor does so directly by conformalising quantile predictions.
Parameters
estimator
alpha
1 - alpha.
calibration_size
normalize
random_state
Attributes
scores_
quantile_
scores_.
difficulty_estimator_
normalize.
fitted_
fit has been called.
Notes
Complexity. One estimator fit (two when normalize=True) plus O(n \log n) for the quantile.
When to use. This is the default interval method: cheapest to fit and exactly valid. Prefer CVPlusRegressor when data is too scarce to hold out a calibration split, and ConformalizedQuantileRegressor when the noise is strongly heteroscedastic.
References
See Also
>>> import numpy as np
>>> from tuiml.uncertainty import SplitConformalRegressor
>>> from tuiml.algorithms.trees import DecisionTreeRegressor
>>> rng = np.random.default_rng(0)
>>> X = rng.normal(size=(400, 3))
>>> y = X[:, 0] * 2.0 + rng.normal(0, 0.5, 400)
>>> cp = SplitConformalRegressor(DecisionTreeRegressor(max_depth=5),
... alpha=0.1, random_state=0)
>>> cp.fit(X, y)
SplitConformalRegressor(estimator=DecisionTreeRegressor(), alpha=0.1)
>>> intervals = cp.predict_interval(X[:5])
>>> intervals.shape
(5, 2)
Methods
fit
(self, X: np.ndarray, y: np.ndarray) -> 'SplitConformalRegressor'
fit
(self, X: np.ndarray, y: np.ndarray) -> 'SplitConformalRegressor'
Fit the regressor on a training split and calibrate on the rest.
Parameters
X
y
Returns
self