Skip to content

Commit a3664f5

Browse files
Merge pull request #507 from scikit-learn-contrib/506-ccp-reoptimize-inference
506 ccp reoptimize inference
2 parents 2b7207d + 48b8730 commit a3664f5

File tree

5 files changed

+298
-55
lines changed

5 files changed

+298
-55
lines changed

examples/classification/4-tutorials/plot_ccp_class_tutorial.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
Tutorial: Conditional CP for classification
44
============================================
55
6-
We will use a synthetic toy dataset for the tutorial of the CCP method, and
7-
its comparison with the other methods available in MAPIE. The CCP method
6+
The tutorial will explain how to use the CCP method for classification
7+
and will wompare it with the other methods available in MAPIE. The CCP method
88
implements the method described in the Gibbs et al. (2023) paper [1].
99
1010
In this tutorial, the classifier will be
1111
:class:`~sklearn.linear_model.LogisticRegression`.
12+
We will use a synthetic toy dataset.
1213
1314
We will compare the CCP method (using
1415
:class:`~mapie.futur.split.SplitCPRegressor`,
@@ -21,6 +22,13 @@
2122
predicted softmax, to keep all the classes above the threshold
2223
(``alpha`` is ``1 - target coverage``).
2324
25+
Warning:
26+
In this tutorial, we use ``unsafe_approximation=True`` to have a faster
27+
computation (because Read The Docs examples require fast computation).
28+
This mode use an approximation, which make the inference (``predict``) faster,
29+
but induce a small miscoverage. It is recommanded not to use it, or be
30+
very careful and empirically check the coverage and a test set.
31+
2432
[1] Isaac Gibbs, John J. Cherian, and Emmanuel J. Candès,
2533
"Conformal Prediction With Conditional Guarantees",
2634
`arXiv <https://arxiv.org/abs/2305.12616>`_, 2023.
@@ -45,6 +53,7 @@
4553
np.random.seed(random_state)
4654

4755
ALPHA = 0.2
56+
UNSAFE_APPROXIMATION = True
4857
N_CLASSES = 5
4958

5059
##############################################################################
@@ -88,7 +97,7 @@ def generate_data(seed=1, n_train=2000, n_calib=2000, n_test=2000, ):
8897
# Let's visualize the data and its distribution
8998

9099

91-
x_train, y_train, *_ = generate_data(seed=None, n_train=2000)
100+
x_train, y_train, *_ = generate_data(seed=None, n_train=1000)
92101

93102
for c in range(N_CLASSES):
94103
plt.scatter(x_train[y_train == c, 0], x_train[y_train == c, 1],
@@ -103,8 +112,9 @@ def generate_data(seed=1, n_train=2000, n_calib=2000, n_test=2000, ):
103112

104113

105114
def run_exp(
106-
mapies, names, alpha, n_train=2000, n_calib=2000,
107-
n_test=2000, grid_step=100, plot=True, seed=1, max_display=2000
115+
mapies, names, alpha,
116+
n_train=1000, n_calib=1000, n_test=1000,
117+
grid_step=100, plot=True, seed=1, max_display=2000
108118
):
109119
(
110120
x_train, y_train, x_calib, y_calib, x_test, y_test
@@ -148,7 +158,9 @@ def run_exp(
148158
mapie.fit(
149159
np.vstack([x_train, x_calib]), np.hstack([y_train, y_calib])
150160
)
151-
_, y_ps_test = mapie.predict(x_test)
161+
_, y_ps_test = mapie.predict(
162+
x_test, unsafe_approximation=UNSAFE_APPROXIMATION
163+
)
152164
if plot:
153165
y_pred_mesh, y_ps_mesh = mapie.predict(X_test_mesh)
154166
else:

examples/regression/3-scientific-articles/plot_gibbs2023_simulations.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
MAPIE gives the same results as [1], and that the bounds of the PIs are
2121
obtained.
2222
23+
It is important to note that we are checking here if the adaptativity property
24+
of the prediction intervals are well obtained. However, the paper do this
25+
computations with the full conformal prediction approach, whereas we
26+
implemented the faster but more conservatice split method. Thus, the results
27+
may vary a little.
28+
2329
[1] Isaac Gibbs, John J. Cherian, Emmanuel J. Candès (2023).
2430
Conformal Prediction With Conditional Guarantees
2531
@@ -352,22 +358,10 @@ def plot_results(X_test, y_test, n_trials=10,
352358
# 5. Reproduce experiment and results
353359
# -----------------------------------------------------------------------------
354360

355-
plot_results(X_test, y_test, 50, experiment="Groups")
361+
plot_results(X_test, y_test, 20, experiment="Groups")
356362

357-
plot_results(X_test, y_test, 50, experiment="Shifts")
363+
plot_results(X_test, y_test, 20, experiment="Shifts")
358364

359365

360366
##############################################################################
361367
# We succesfully reproduced the experiement of the Gibbs et al. paper [1].
362-
363-
##############################################################################
364-
# 6. Variant of the experiments: let's compare what is comparable
365-
# -----------------------------------------------------------------------------
366-
#
367-
# In the paper, the proposed method (used with not symetrical PI) is compared
368-
# to the split method with symetrical PI. Let's compare it to the split CP with
369-
# unsymetrical PI, to have a fair comparison.
370-
371-
plot_results(X_test, y_test, 50, experiment="Groups", split_sym=False)
372-
373-
plot_results(X_test, y_test, 50, experiment="Shifts", split_sym=False)

examples/regression/4-tutorials/plot_ccp_tutorial.py

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33
Tutorial: Conditional CP for regression
44
============================================
55
6-
We will use a synthetic toy dataset for the tutorial of the CCP method, and
7-
its comparison with the other methods available in MAPIE. The CCP method
6+
The tutorial will explain how to use the CCP method, and
7+
will compare it with the other methods available in MAPIE. The CCP method
88
implements the method described in the Gibbs et al. (2023) paper [1].
99
1010
We will see in this tutorial how to use the method. It has a lot of advantages:
1111
1212
- It is model agnostic (it doesn't depend on the model but only on the
1313
predictions, unlike `CQR`)
14-
- It uses the `split` approach (it require a calibration set, but is very fast
15-
at inference time, unlike the `CV` approach)
1614
- It can create very adaptative intervals (with a varying width which truly
1715
eflects the model uncertainty)
1816
- while providing coverage guantee on all sub-groups of interest
@@ -24,8 +22,11 @@
2422
- The adaptativity depends on the calibrator we use: It can be difficult to
2523
choose the correct calibrator,
2624
with the best parameters (this tutorial will try to help you with this task).
27-
- If the inference is very fast, the calibration phase can be very long,
28-
depending on the complexity of your calibrator
25+
- The calibration and even more the inference are much longer than for the
26+
other methods. We can reduce the inference time using
27+
``unsafe_approximation=True``, but we lose the theoretical guarantees and
28+
risk a small miscoverage
29+
(even if, most of the time, the coverage is achieved).
2930
3031
Conclusion on the method:
3132
@@ -35,7 +36,8 @@
3536
3637
----
3738
38-
In this tutorial, the estimator will be :class:`~sklearn.pipeline.Pipeline`
39+
In this tutorial, we will use a synthetic toy dataset.
40+
The estimator will be :class:`~sklearn.pipeline.Pipeline`
3941
with :class:`~sklearn.preprocessing.PolynomialFeatures` and
4042
:class:`~sklearn.linear_model.LinearRegression` (or
4143
:class:`~sklearn.linear_model.QuantileRegressor` for CQR).
@@ -51,6 +53,14 @@
5153
5254
Recall that the ``alpha`` is ``1 - target coverage``.
5355
56+
Warning:
57+
58+
In this tutorial, we use ``unsafe_approximation=True`` to have a faster
59+
computation (because Read The Docs examples require fast computation).
60+
This mode use an approximation, which make the inference (``predict``) faster,
61+
but induce a small miscoverage. It is recommanded not to use it, or be
62+
very careful and empirically check the coverage and a test set.
63+
5464
[1] Isaac Gibbs, John J. Cherian, and Emmanuel J. Candès,
5565
"Conformal Prediction With Conditional Guarantees",
5666
`arXiv <https://arxiv.org/abs/2305.12616>`_, 2023.
@@ -78,6 +88,7 @@
7888
np.random.seed(random_state)
7989

8090
ALPHA = 0.1
91+
UNSAFE_APPROXIMATION = True
8192

8293
##############################################################################
8394
# 1. Data generation
@@ -90,8 +101,8 @@
90101
# - between 0 and 5: normal distribution with a noise value which
91102
# increase with ``x``
92103
#
93-
# We are going to use 3000 samples for training, 3000 for calibration and
94-
# 20 000 for testing (to have an accurate conditional coverage).
104+
# We are going to use 5000 samples for training, 5000 for calibration and
105+
# 5000 for testing.
95106

96107

97108
def x_sinx(x):
@@ -123,7 +134,7 @@ def get_1d_data_with_heteroscedastic_noise(
123134
return X.reshape(-1, 1), y, true_pi
124135

125136

126-
def generate_data(n_train=6000, n_test=20000, noise=0.8, power=2):
137+
def generate_data(n_train=10000, n_test=5000, noise=0.8, power=2):
127138
X, y, true_pi = get_1d_data_with_heteroscedastic_noise(
128139
x_sinx, -1, 5, n_train + n_test, noise, power)
129140
indexes = list(range(len(X)))
@@ -428,7 +439,9 @@ def plot_evaluation(titles, y_pis, X_test, y_test):
428439
mapie_ccp = SplitCPRegressor(estimator, calibrator=GaussianCCP(),
429440
alpha=ALPHA, cv=cv)
430441
mapie_ccp.fit(X_train, y_train)
431-
y_pred_ccp, y_pi_ccp = mapie_ccp.predict(X_test)
442+
y_pred_ccp, y_pi_ccp = mapie_ccp.predict(
443+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
444+
)
432445

433446
# ================== PLOT ==================
434447
mapies = [mapie_split, mapie_cv, mapie_cqr, mapie_ccp]
@@ -533,19 +546,25 @@ def plot_evaluation(titles, y_pis, X_test, y_test):
533546
mapie_ccp_1 = SplitCPRegressor(estimator, calibrator=calibrator_gauss1,
534547
cv=cv, alpha=ALPHA)
535548
mapie_ccp_1.fit(X_train, y_train)
536-
y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict(X_test)
549+
y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict(
550+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
551+
)
537552

538553
# # ================== CCP 2 ==================
539554
mapie_ccp_2 = SplitCPRegressor(estimator, calibrator=calibrator_gauss2,
540555
cv=cv, alpha=ALPHA)
541556
mapie_ccp_2.fit(X_train, y_train)
542-
y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict(X_test)
557+
y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict(
558+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
559+
)
543560

544561
# # ================== CCP 3 ==================
545562
mapie_ccp_3 = SplitCPRegressor(estimator, calibrator=calibrator_gauss3,
546563
cv=cv, alpha=ALPHA)
547564
mapie_ccp_3.fit(X_train, y_train)
548-
y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict(X_test)
565+
y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict(
566+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
567+
)
549568

550569

551570
mapies = [mapie_split, mapie_cv, mapie_cqr,
@@ -605,19 +624,25 @@ def plot_evaluation(titles, y_pis, X_test, y_test):
605624
mapie_ccp_1 = SplitCPRegressor(estimator, calibrator=calibrator1,
606625
cv=cv, alpha=ALPHA)
607626
mapie_ccp_1.fit(X_train, y_train)
608-
y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict(X_test)
627+
y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict(
628+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
629+
)
609630

610631
# ================== CCP 2 ==================
611632
mapie_ccp_2 = SplitCPRegressor(estimator, calibrator=calibrator2,
612633
cv=cv, alpha=ALPHA)
613634
mapie_ccp_2.fit(X_train, y_train)
614-
y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict(X_test)
635+
y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict(
636+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
637+
)
615638

616639
# ================== CCP 3 ==================
617640
mapie_ccp_3 = SplitCPRegressor(estimator, calibrator=calibrator3,
618641
cv=cv, alpha=ALPHA)
619642
mapie_ccp_3.fit(X_train, y_train)
620-
y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict(X_test)
643+
y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict(
644+
X_test, unsafe_approximation=UNSAFE_APPROXIMATION
645+
)
621646

622647
mapies = [mapie_split, mapie_cv, mapie_cqr,
623648
mapie_ccp_1, mapie_ccp_2, mapie_ccp_3]

0 commit comments

Comments
 (0)