Skip to content

Commit 4d823ab

Browse files
authored
Merge branch 'master' into 415-documentation-for-winkler-interval-score
2 parents 9f21fda + be78d7a commit 4d823ab

File tree

3 files changed

+145
-17
lines changed

3 files changed

+145
-17
lines changed

HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ History
1010
* Fix invalid certificate when downloading data.
1111
* Add citations utility to the documentation.
1212
* Add documentation for metrics.
13+
* Add explanation and example for symmetry argument in CQR.
1314

1415
0.8.3 (2024-03-01)
1516
------------------

doc/theoretical_description_regression.rst

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -245,30 +245,43 @@ uncertainty is higher than :math:`CV+`, because the models' prediction spread
245245
is then higher.
246246

247247

248-
9. The conformalized quantile regression (CQR) method
248+
9. The Conformalized Quantile Regression (CQR) Method
249249
=====================================================
250250

251-
The conformalized quantile method allows for better interval widths with
252-
heteroscedastic data. It uses quantile regressors with different quantile
253-
values to estimate the prediction bounds and the residuals of these methods are
254-
used to create the guaranteed coverage value.
251+
The conformalized quantile regression (CQR) method allows for better interval widths with
252+
heteroscedastic data. It uses quantile regressors with different quantile values to estimate
253+
the prediction bounds. The residuals of these methods are used to create the guaranteed
254+
coverage value.
255+
256+
Notations and Definitions
257+
-------------------------
258+
- :math:`\mathcal{I}_1` is the set of indices of the data in the training set.
259+
- :math:`\mathcal{I}_2` is the set of indices of the data in the calibration set.
260+
- :math:`\hat{q}_{\alpha_{\text{low}}}`: Lower quantile model trained on :math:`{(X_i, Y_i) : i \in \mathcal{I}_1}`.
261+
- :math:`\hat{q}_{\alpha_{\text{high}}}`: Upper quantile model trained on :math:`{(X_i, Y_i) : i \in \mathcal{I}_1}`.
262+
- :math:`E_i`: Residuals for the i-th sample in the calibration set.
263+
- :math:`E_{\text{low}}`: Residuals from the lower quantile model.
264+
- :math:`E_{\text{high}}`: Residuals from the upper quantile model.
265+
- :math:`Q_{1-\alpha}(E, \mathcal{I}_2)`: The :math:`(1-\alpha)(1+1/|\mathcal{I}_2|)`-th empirical quantile of the set :math:`{E_i : i \in \mathcal{I}_2}`.
266+
267+
Mathematical Formulation
268+
------------------------
269+
The prediction interval :math:`\hat{C}_{n, \alpha}^{\text{CQR}}(X_{n+1})` for a new sample :math:`X_{n+1}` is given by:
255270

256-
.. math::
271+
.. math::
272+
273+
\hat{C}_{n, \alpha}^{\text{CQR}}(X_{n+1}) =
274+
[\hat{q}_{\alpha_{\text{lo}}}(X_{n+1}) - Q_{1-\alpha}(E_{\text{low}}, \mathcal{I}_2),
275+
\hat{q}_{\alpha_{\text{hi}}}(X_{n+1}) + Q_{1-\alpha}(E_{\text{high}}, \mathcal{I}_2)]
257276
258-
\hat{C}_{n, \alpha}^{\rm CQR}(X_{n+1}) =
259-
[\hat{q}_{\alpha_{lo}}(X_{n+1}) - Q_{1-\alpha}(E_{low}, \mathcal{I}_2),
260-
\hat{q}_{\alpha_{hi}}(X_{n+1}) + Q_{1-\alpha}(E_{high}, \mathcal{I}_2)]
277+
Where:
261278

262-
Where :math:`Q_{1-\alpha}(E, \mathcal{I}_2) := (1-\alpha)(1+1/ |\mathcal{I}_2|)`-th
263-
empirical quantile of :math:`{E_i : i \in \mathcal{I}_2}` and :math:`\mathcal{I}_2` is the
264-
residuals of the estimator fitted on the calibration set. Note that in the symmetric method,
265-
:math:`E_{low}` and :math:`E_{high}` are equal.
279+
- :math:`\hat{q}_{\alpha_{\text{lo}}}(X_{n+1})` is the predicted lower quantile for the new sample.
280+
- :math:`\hat{q}_{\alpha_{\text{hi}}}(X_{n+1})` is the predicted upper quantile for the new sample.
266281

267-
As justified by [3], this method offers a theoretical guarantee of the target coverage
268-
level :math:`1-\alpha`.
282+
Note: In the symmetric method, :math:`E_{\text{low}}` and :math:`E_{\text{high}}` sets are no longer distinct. We consider directly the union set :math:`E_{\text{all}} = E_{\text{low}} \cup E_{\text{high}}` and the empirical quantile is then calculated on all the absolute (positive) residuals.
269283

270-
Note that only the split method has been implemented and that it will run three separate
271-
regressions when using :class:`mapie.quantile_regression.MapieQuantileRegressor`.
284+
As justified by the literature, this method offers a theoretical guarantee of the target coverage level :math:`1-\alpha`.
272285

273286

274287
10. The ensemble batch prediction intervals (EnbPI) method
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""
2+
====================================
3+
Plotting CQR with symmetric argument
4+
====================================
5+
An example plot of :class:`~mapie.quantile_regression.MapieQuantileRegressor`
6+
illustrating the impact of the symmetry parameter.
7+
"""
8+
import numpy as np
9+
from matplotlib import pyplot as plt
10+
from sklearn.datasets import make_regression
11+
from sklearn.ensemble import GradientBoostingRegressor
12+
13+
from mapie.metrics import regression_coverage_score
14+
from mapie.quantile_regression import MapieQuantileRegressor
15+
16+
random_state = 2
17+
18+
##############################################################################
19+
# We generate a synthetic data.
20+
21+
X, y = make_regression(n_samples=500, n_features=1, noise=20, random_state=59)
22+
23+
# Define alpha level
24+
alpha = 0.2
25+
26+
# Fit a Gradient Boosting Regressor for quantile regression
27+
gb_reg = GradientBoostingRegressor(
28+
loss="quantile", alpha=0.5, random_state=random_state
29+
)
30+
31+
# MAPIE Quantile Regressor
32+
mapie_qr = MapieQuantileRegressor(estimator=gb_reg, alpha=alpha)
33+
mapie_qr.fit(X, y, random_state=random_state)
34+
y_pred_sym, y_pis_sym = mapie_qr.predict(X, symmetry=True)
35+
y_pred_asym, y_pis_asym = mapie_qr.predict(X, symmetry=False)
36+
y_qlow = mapie_qr.estimators_[0].predict(X)
37+
y_qup = mapie_qr.estimators_[1].predict(X)
38+
39+
# Calculate coverage scores
40+
coverage_score_sym = regression_coverage_score(
41+
y, y_pis_sym[:, 0], y_pis_sym[:, 1]
42+
)
43+
coverage_score_asym = regression_coverage_score(
44+
y, y_pis_asym[:, 0], y_pis_asym[:, 1]
45+
)
46+
47+
# Sort the values for plotting
48+
order = np.argsort(X[:, 0])
49+
X_sorted = X[order]
50+
y_pred_sym_sorted = y_pred_sym[order]
51+
y_pis_sym_sorted = y_pis_sym[order]
52+
y_pred_asym_sorted = y_pred_asym[order]
53+
y_pis_asym_sorted = y_pis_asym[order]
54+
y_qlow = y_qlow[order]
55+
y_qup = y_qup[order]
56+
57+
##############################################################################
58+
# We will plot the predictions and prediction intervals for both symmetric
59+
# and asymmetric intervals. The line represents the predicted values, the
60+
# dashed lines represent the prediction intervals, and the shaded area
61+
# represents the symmetric and asymmetric prediction intervals.
62+
63+
plt.figure(figsize=(14, 7))
64+
65+
plt.subplot(1, 2, 1)
66+
plt.xlabel("x")
67+
plt.ylabel("y")
68+
plt.scatter(X, y, alpha=0.3)
69+
plt.plot(X_sorted, y_qlow, color="C1")
70+
plt.plot(X_sorted, y_qup, color="C1")
71+
plt.plot(X_sorted, y_pis_sym_sorted[:, 0], color="C1", ls="--")
72+
plt.plot(X_sorted, y_pis_sym_sorted[:, 1], color="C1", ls="--")
73+
plt.fill_between(
74+
X_sorted.ravel(),
75+
y_pis_sym_sorted[:, 0].ravel(),
76+
y_pis_sym_sorted[:, 1].ravel(),
77+
alpha=0.2,
78+
)
79+
plt.title(
80+
f"Symmetric Intervals\n"
81+
f"Target and effective coverages for "
82+
f"alpha={alpha:.2f}: ({1-alpha:.3f}, {coverage_score_sym:.3f})"
83+
)
84+
85+
# Plot asymmetric prediction intervals
86+
plt.subplot(1, 2, 2)
87+
plt.xlabel("x")
88+
plt.ylabel("y")
89+
plt.scatter(X, y, alpha=0.3)
90+
plt.plot(X_sorted, y_qlow, color="C2")
91+
plt.plot(X_sorted, y_qup, color="C2")
92+
plt.plot(X_sorted, y_pis_asym_sorted[:, 0], color="C2", ls="--")
93+
plt.plot(X_sorted, y_pis_asym_sorted[:, 1], color="C2", ls="--")
94+
plt.fill_between(
95+
X_sorted.ravel(),
96+
y_pis_asym_sorted[:, 0].ravel(),
97+
y_pis_asym_sorted[:, 1].ravel(),
98+
alpha=0.2,
99+
)
100+
plt.title(
101+
f"Asymmetric Intervals\n"
102+
f"Target and effective coverages for "
103+
f"alpha={alpha:.2f}: ({1-alpha:.3f}, {coverage_score_asym:.3f})"
104+
)
105+
plt.tight_layout()
106+
plt.show()
107+
108+
##############################################################################
109+
# The symmetric intervals (`symmetry=True`) use a combined set of residuals
110+
# for both bounds, while the asymmetric intervals use distinct residuals for
111+
# each bound, allowing for more flexible and accurate intervals that reflect
112+
# the heteroscedastic nature of the data. The resulting effective coverages
113+
# demonstrate the theoretical guarantee of the target coverage level
114+
# :math:`1 - \alpha`.

0 commit comments

Comments
 (0)