1010Throughout this tutorial, we will answer the following questions:
1111
1212- How does the number of classes in the prediction sets vary according to
13- the significance level ?
13+ the confidence level?
1414
15- - Is the chosen conformal method well calibrated ?
15+ - Is the chosen conformal method well calibrated?
1616
17- - What are the pros and cons of the conformal methods included in MAPIE ?
17+ - What are the pros and cons of the conformal methods included in MAPIE?
1818"""
1919
2020import matplotlib .pyplot as plt
2121import numpy as np
22- from sklearn .model_selection import train_test_split
2322from sklearn .naive_bayes import GaussianNB
2423
25- from mapie .classification import _MapieClassifier
26- from mapie .conformity_scores import APSConformityScore
24+ from mapie .classification import SplitConformalClassifier
25+ from mapie .utils import train_conformalize_test_split
2726from mapie .metrics .classification import (
28- classification_coverage_score ,
27+ classification_coverage_score_v2 ,
2928 classification_mean_width_score ,
3029)
3130
3635# We will use MAPIE to estimate a prediction set of several classes such
3736# that the probability that the true label of a new test point is included
3837# in the prediction set is always higher than the target confidence level :
39- # ``P(Yₙ₊₁ ∈ Ĉₙ,α(Xₙ₊₁)) ≥ 1 - α``
38+ # ``P(Yₙ₊₁ ∈ Ĉₙ,α(Xₙ₊₁)) ≥ 1 - α``.
4039# We start by using the softmax score output by the base classifier as the
4140# conformity score on a toy two-dimensional dataset.
4241#
4342# We estimate the prediction sets as follows :
4443#
45- # * Generate a dataset with train, calibration and test, the model is
44+ # * Generate a dataset with train, conformalization and test, the model is
4645# fitted on the training set.
4746#
4847# * Set the conformal score ``Sᵢ = 𝑓̂(Xᵢ)ᵧᵢ``, the softmax
49- # output of the true class for each sample in the calibration set.
48+ # output of the true class for each sample in the conformity set.
5049#
5150# * Define ``q̂`` as being the ``(n + 1)(α) / n``
5251# previous quantile of ``S₁, ..., Sₙ``
7372 for center , cov in zip (centers , covs )
7473])
7574y = np .hstack ([np .full (n_samples , i ) for i in range (n_classes )])
76- X_train_cal , X_test , y_train_cal , y_test = train_test_split (
77- X , y , test_size = 0.2
78- )
79- X_train , X_cal , y_train , y_cal = train_test_split (
80- X_train_cal , y_train_cal , test_size = 0.25
75+ (X_train , X_conf , X_test ,
76+ y_train , y_conf , y_test ) = train_conformalize_test_split (
77+ X , y , train_size = 0.6 , conformalize_size = 0.2 , test_size = 0.2
8178)
8279
8380xx , yy = np .meshgrid (
105102
106103##############################################################################
107104# We fit our training data with a Gaussian Naive Base estimator. And then we
108- # apply MAPIE in the calibration data with the LAC conformity score to the
109- # estimator indicating that it has already been fitted with `cv=" prefit" `.
110- # We then estimate the prediction sets with differents alpha values with a
111- # ``fit `` and ``predict`` process.
105+ # apply MAPIE in the conformity data with the LAC conformity score to the
106+ # estimator indicating that it has already been fitted with `prefit=True `.
107+ # We then estimate the prediction sets with different confidence level values with a
108+ # ``conformalize `` and ``predict`` process.
112109
113- clf = GaussianNB ().fit (X_train , y_train )
110+ clf = GaussianNB ()
111+ clf .fit (X_train , y_train )
114112y_pred = clf .predict (X_test )
115113y_pred_proba = clf .predict_proba (X_test )
116114y_pred_proba_max = np .max (y_pred_proba , axis = 1 )
117- mapie_score = _MapieClassifier (estimator = clf , cv = "prefit" )
118- mapie_score .fit (X_cal , y_cal )
119- alpha = [0.2 , 0.1 , 0.05 ]
120- y_pred_score , y_ps_score = mapie_score .predict (X_test_mesh , alpha = alpha )
115+ confidence_level = [0.8 , 0.9 , 0.95 ]
116+ mapie_score = SplitConformalClassifier (
117+ estimator = clf ,
118+ confidence_level = confidence_level ,
119+ prefit = True
120+ )
121+ mapie_score .conformalize (X_conf , y_conf )
122+ y_pred_score , y_ps_score = mapie_score .predict_set (X_test_mesh )
121123
122124##############################################################################
123125# * ``y_pred_score``: represents the prediction in the test set by the base
124126# estimator.
125- # * ``y_ps_score``: reprensents the prediction sets estimated by MAPIE with
127+ # * ``y_ps_score``: represents the prediction sets estimated by MAPIE with
126128# the "lac" conformity score.
127129
128130
129- def plot_scores (n , alphas , scores , quantiles ):
131+ def plot_scores (n , confidence_levels , scores , quantiles ):
130132 colors = {0 : "#1f77b4" , 1 : "#ff7f0e" , 2 : "#2ca02c" }
131133 plt .figure (figsize = (7 , 5 ))
132134 plt .hist (scores , bins = "auto" )
@@ -137,7 +139,7 @@ def plot_scores(n, alphas, scores, quantiles):
137139 ymax = 400 ,
138140 color = colors [i ],
139141 ls = "dashed" ,
140- label = f"alpha = { alphas [i ]} "
142+ label = f"confidence_level = { confidence_levels [i ]} "
141143 )
142144 plt .title ("Distribution of scores" )
143145 plt .legend ()
@@ -149,22 +151,22 @@ def plot_scores(n, alphas, scores, quantiles):
149151##############################################################################
150152# Let’s see the distribution of the scores with the calculated quantiles.
151153
152- scores = mapie_score .conformity_scores_
153- n = len (mapie_score .conformity_scores_ )
154- quantiles = mapie_score .conformity_score_function_ .quantiles_
155- plot_scores (n , alpha , scores , quantiles )
154+ scores = mapie_score ._mapie_classifier . conformity_scores_
155+ n = len (mapie_score ._mapie_classifier . conformity_scores_ )
156+ quantiles = mapie_score ._mapie_classifier . conformity_score_function_ .quantiles_
157+ plot_scores (n , confidence_level , scores , quantiles )
156158
157159##############################################################################
158- # The estimated quantile increases with alpha .
159- # A high value of alpha can potentially lead to a high quantile which would
160- # not necessarily be reached by any class in uncertain areas, resulting in
161- # null regions.
160+ # The estimated quantile increases with the confidence level .
161+ # A low confidence level can potentially lead to a low quantile ``q``; the associated
162+ # ``1 - q`` threshold would therefore not necessarily be reached by any class in
163+ # uncertain areas, resulting in null regions.
162164#
163165# We will now visualize the differences between the prediction sets of the
164- # different values of alpha .
166+ # different values of confidence level .
165167
166168
167- def plot_results (alphas , X , y_pred , y_ps ):
169+ def plot_results (confidence_levels , X , y_pred , y_ps ):
168170 tab10 = plt .cm .get_cmap ('Purples' , 4 )
169171 colors = {0 : "#1f77b4" , 1 : "#ff7f0e" , 2 : "#2ca02c" , 3 : "#d62728" }
170172 y_pred_col = list (map (colors .get , y_pred ))
@@ -179,7 +181,7 @@ def plot_results(alphas, X, y_pred, y_ps):
179181 alpha = 0.4
180182 )
181183 axs [0 ].set_title ("Predicted labels" )
182- for i , alpha in enumerate (alphas ):
184+ for i , confidence_level in enumerate (confidence_levels ):
183185 y_pi_sums = y_ps [:, :, i ].sum (axis = 1 )
184186 num_labels = axs [i + 1 ].scatter (
185187 X [:, 0 ],
@@ -193,11 +195,11 @@ def plot_results(alphas, X, y_pred, y_ps):
193195 vmax = 3
194196 )
195197 plt .colorbar (num_labels , ax = axs [i + 1 ])
196- axs [i + 1 ].set_title (f"Number of labels for alpha= { alpha } " )
198+ axs [i + 1 ].set_title (f"Number of labels for confidence_level= { confidence_level } " )
197199 plt .show ()
198200
199201
200- plot_results (alpha , X_test_mesh , y_pred_score , y_ps_score )
202+ plot_results (confidence_level , X_test_mesh , y_pred_score , y_ps_score )
201203
202204##############################################################################
203205# When the class coverage is not large enough, the prediction sets can be
@@ -208,80 +210,94 @@ def plot_results(alphas, X, y_pred, y_ps):
208210# classifier.
209211#
210212# Let’s now study the effective coverage and the mean prediction set widths
211- # as function of the ``1 - α `` target coverage. To this aim, we use once
213+ # as function of the ``confidence_level `` target coverage. To this aim, we use once
212214# again the ``predict`` method of MAPIE to estimate predictions sets on a
213- # large number of ``α`` values.
214-
215- alpha2 = np .arange (0.02 , 0.98 , 0.02 )
216- _ , y_ps_score2 = mapie_score .predict (X_test , alpha = alpha2 )
217- coverages_score = [
218- classification_coverage_score (y_test , y_ps_score2 [:, :, i ])
219- for i , _ in enumerate (alpha2 )
220- ]
215+ # large number of ``confidence_level`` values.
216+
217+ confidence_level2 = np .arange (0.02 , 0.98 , 0.02 )
218+ mapie_score2 = SplitConformalClassifier (
219+ estimator = clf ,
220+ confidence_level = confidence_level2 ,
221+ prefit = True
222+ )
223+ mapie_score2 .conformalize (X_conf , y_conf )
224+ _ , y_ps_score2 = mapie_score2 .predict_set (X_test )
225+ coverages_score = classification_coverage_score_v2 (y_test , y_ps_score2 )
221226widths_score = classification_mean_width_score (y_ps_score2 )
222227
223228
224- def plot_coverages_widths (alpha , coverage , width , method ):
229+ def plot_coverages_widths (confidence_level , coverage , width , conformity_score ):
225230 fig , axs = plt .subplots (1 , 2 , figsize = (12 , 5 ))
226- axs [0 ].scatter (1 - alpha , coverage , label = method )
227- axs [0 ].set_xlabel ("1 - alpha " )
231+ axs [0 ].scatter (confidence_level , coverage , label = conformity_score )
232+ axs [0 ].set_xlabel ("Confidence level " )
228233 axs [0 ].set_ylabel ("Coverage score" )
229234 axs [0 ].plot ([0 , 1 ], [0 , 1 ], label = "x=y" , color = "black" )
230235 axs [0 ].legend ()
231- axs [1 ].scatter (1 - alpha , width , label = method )
232- axs [1 ].set_xlabel ("1 - alpha " )
236+ axs [1 ].scatter (confidence_level , width , label = conformity_score )
237+ axs [1 ].set_xlabel ("Confidence level " )
233238 axs [1 ].set_ylabel ("Average size of prediction sets" )
234239 axs [1 ].legend ()
235240 plt .show ()
236241
237242
238- plot_coverages_widths (alpha2 , coverages_score , widths_score , "lac" )
243+ plot_coverages_widths (
244+ confidence_level2 , coverages_score , widths_score , "lac"
245+ )
239246
240247##############################################################################
241248# 2. Conformal Prediction method using the cumulative softmax score
242249# -----------------------------------------------------------------
243250#
244251# We saw in the previous section that the "lac" conformity score is well calibrated by
245252# providing accurate coverage levels. However, it tends to give null
246- # prediction sets for uncertain regions, especially when the ``α ``
247- # value is high .
253+ # prediction sets for uncertain regions, especially when the ``confidence_level ``
254+ # value is low .
248255# MAPIE includes another method, called Adaptive Prediction Set (APS),
249256# whose conformity score is the cumulated score of the softmax output until
250257# the true label is reached (see the theoretical description for more details).
251- # We will see in this Section that this method no longer estimates null
252- # prediction sets but by giving slightly bigger prediction sets.
258+ # We will see in this section that this method no longer estimates null
259+ # prediction sets by giving slightly bigger prediction sets.
253260#
254261# Let's visualize the prediction sets obtained with the APS method on the test
255- # set after fitting MAPIE on the calibration set.
256-
257- mapie_aps = _MapieClassifier (
258- estimator = clf , cv = "prefit" , conformity_score = APSConformityScore ()
262+ # set after fitting MAPIE on the conformity set.
263+
264+ confidence_level = [0.8 , 0.9 , 0.95 ]
265+ mapie_aps = SplitConformalClassifier (
266+ estimator = clf ,
267+ confidence_level = confidence_level ,
268+ conformity_score = "aps" ,
269+ prefit = True
259270)
260- mapie_aps .fit (X_cal , y_cal )
261- alpha = [0.2 , 0.1 , 0.05 ]
262- y_pred_aps , y_ps_aps = mapie_aps .predict (
263- X_test_mesh , alpha = alpha , include_last_label = True
271+ mapie_aps .conformalize (X_conf , y_conf )
272+ y_pred_aps , y_ps_aps = mapie_aps .predict_set (
273+ X_test_mesh , conformity_score_params = {"include_last_label" : True }
264274)
265275
266- plot_results (alpha , X_test_mesh , y_pred_aps , y_ps_aps )
276+ plot_results (confidence_level , X_test_mesh , y_pred_aps , y_ps_aps )
267277
268278##############################################################################
269279# One can notice that the uncertain regions are emphasized by wider
270280# boundaries, but without null prediction sets with respect to the first
271281# "lac" method.
272282
273- _ , y_ps_aps2 = mapie_aps .predict (
274- X_test , alpha = alpha2 , include_last_label = "randomized"
283+ mapie_aps2 = SplitConformalClassifier (
284+ estimator = clf ,
285+ confidence_level = confidence_level2 ,
286+ conformity_score = "aps" ,
287+ prefit = True
275288)
276- coverages_aps = [
277- classification_coverage_score (y_test , y_ps_aps2 [:, :, i ])
278- for i , _ in enumerate (alpha2 )
279- ]
289+ mapie_aps2 .conformalize (X_conf , y_conf )
290+ _ , y_ps_aps2 = mapie_aps2 .predict_set (
291+ X_test , conformity_score_params = {"include_last_label" : "randomized" }
292+ )
293+ coverages_aps = classification_coverage_score_v2 (y_test , y_ps_aps2 )
280294widths_aps = classification_mean_width_score (y_ps_aps2 )
281295
282- plot_coverages_widths (alpha2 , coverages_aps , widths_aps , "lac" )
296+ plot_coverages_widths (
297+ confidence_level2 , coverages_aps , widths_aps , "aps"
298+ )
283299
284300##############################################################################
285- # This method also gives accurate calibration plots, meaning that the
301+ # This method also gives accurate conformalization plots, meaning that the
286302# effective coverage level is always very close to the target coverage,
287303# sometimes at the expense of slightly bigger prediction sets.
0 commit comments