Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add J+aB and APS methods #99

Merged
merged 105 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from 92 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
51e634a
fisrt instance of the classification tutorial
Sep 13, 2021
41838f6
Add method cumulated_score
Sep 13, 2021
a51ffaa
Merge branch 'add_method_cumulated_score' of https://github.com/simai…
Sep 13, 2021
805e765
corrections added
Sep 14, 2021
f60f246
corrections to mathmatical expressions
Sep 14, 2021
2ceb115
Update fit and predict
Sep 14, 2021
dd0f8a8
first implementation of jackknife+-aB
Sep 14, 2021
c405cb3
fix_error_in_first_implementation
Sep 14, 2021
da84b82
next step: choose aggregation function
Sep 15, 2021
ba1a5ff
ADD: can choose between agg_function mean and median
Sep 16, 2021
d62184a
ADD customized aggregation function
Sep 16, 2021
89f341f
add corrections
Sep 20, 2021
61ad53b
ADD: Jackknife+-AB
Sep 20, 2021
8db9e9a
UPDATE AUTHORS and HISTORY
Sep 20, 2021
4adfa10
add corrections + data splitted in train/calib
Sep 21, 2021
801a93a
commit before merge of dev
Sep 21, 2021
416bc50
Merge branch 'dev' into j_plus_aB
Sep 21, 2021
3540344
CORRECTION: application of Vianney's remarks
Sep 22, 2021
c7eb715
[CORRECTION]: corrections from Vianney remarks.
Sep 22, 2021
c5711e6
Merge pull request #95 from scikit-learn-contrib/j_plus_aB
vtaquet Sep 22, 2021
90ab090
class JackknifeAB restricted to a smaller class Resample and argument…
Sep 27, 2021
d231a40
add corrections +
Sep 27, 2021
fb3e541
Merge pull request #92 from scikit-learn-contrib/add_classification_t…
vtaquet Sep 27, 2021
9c2f3a4
Correction of JRO MR
Sep 29, 2021
c431c6c
update test classification + method aps
Sep 29, 2021
b9b0999
corrections according to most of Vianney remarks on Julien PR
Sep 30, 2021
9da45ec
update method score with 1-score
Sep 30, 2021
326b537
Documentation corrected and lines split to avoid black correction
Oct 4, 2021
c874cb9
Add unit test to cumulated_score
Oct 4, 2021
8ffdc63
Fix typing
Oct 4, 2021
473b6ef
Add method comparison on 2d dataset
Oct 4, 2021
726728b
Add method comparison on 2d dataset
Oct 4, 2021
6e1ea49
Add method comparison on 2d dataset
Oct 4, 2021
49de3ba
Add method comparison on 2d dataset
Oct 4, 2021
97df924
Add method comparison on 2d dataset
Oct 4, 2021
029588e
Add method comparison on 2d dataset
Oct 4, 2021
7a47a40
Add method comparison on 2d dataset
Oct 4, 2021
7fc290d
Include GMA comments
Oct 4, 2021
dfd4c27
plot_barber repaired and error type corrected
Oct 4, 2021
a1dbd95
Fix HISTORY
Oct 4, 2021
15f8d13
Merge branch 'dev' into add_method_cumulated_score
vtaquet Oct 4, 2021
1a7fff6
Merge pull request #93 from scikit-learn-contrib/add_method_cumulated…
vtaquet Oct 4, 2021
13bc8a4
documentation of Subsample.get_n_samples improved
Oct 5, 2021
f429290
merge
Oct 7, 2021
23e2e5e
Add randomness in quantile estimate and inclusion of last label
Oct 11, 2021
5af6786
Add unit tests
Oct 11, 2021
9ed548c
Fix CI issues
Oct 11, 2021
07dc4af
Fix CI issues
Oct 11, 2021
b310a0a
Finish example.
Oct 11, 2021
4a42a83
Finish example.
Oct 11, 2021
d79ee69
gitignore merged
Oct 11, 2021
fbde8e9
Merge pull request #96 from scikit-learn-contrib/reviewing_regression…
vtaquet Oct 12, 2021
8d3ce2d
Add size in np.random.uniform
Oct 12, 2021
0eb54a4
Change inequality to estimate prediction sets
Oct 12, 2021
f810cfb
Merge pull request #98 from scikit-learn-contrib/randomness-in-cumula…
vtaquet Oct 12, 2021
c0c73b0
integration of GMA remarks
Oct 18, 2021
b62eef6
add some examples
Oct 19, 2021
6f3fdb2
Reply to GMA remarks. Notably add examples to all functions
Oct 25, 2021
2898b9a
correcting typing
Oct 25, 2021
16ac0fc
all tests should pass
Oct 25, 2021
6475d99
Prise en compte des remarques de Grégoire Martinon sur les deux derni…
Oct 26, 2021
e504503
Prise en compte des remarques de Grégoire Martinon sur les deux derni…
Oct 26, 2021
a3582de
Take first comments from GMA on PR
Oct 26, 2021
a1c9e31
Ajout d'un commentaire sur les méthodes d'aggrégation et correction d…
Oct 27, 2021
c9854a2
Merge pull request #106 from scikit-learn-contrib/reply_TMO_to_GMA_PR…
gmartinonQM Oct 27, 2021
e872ace
Correct code with GMA coments
Oct 28, 2021
a743037
merge TMO branch into this branch
Oct 28, 2021
ffbb682
FIX: interpolation higher and random state
Oct 29, 2021
162fc5a
ENH: add comments in test functions
Oct 29, 2021
be1318d
Fix plot_comp_methods example
Oct 29, 2021
6ede71d
ENH: add typing
Oct 29, 2021
07aaa67
FIX: add missing typing
Oct 29, 2021
6abd21b
Last fixes after PR
Oct 29, 2021
cb320cc
Merge pull request #107 from scikit-learn-contrib/comments-gma-on-cla…
vtaquet Oct 29, 2021
b625571
ENH : resolve typo comments + put include_last_label argument in predict
Nov 2, 2021
d3fc778
ENH : remove some arguments from _add_random_tie_breaking function
Nov 2, 2021
5c80725
ENH change y_proba_sorted_argmax to y_proba_sorted_last
Nov 2, 2021
4ac6ebb
ENH: change verificaiton that all probas sum to one
Nov 3, 2021
79f0a17
Add docstirng and typing to new tests
Nov 3, 2021
4cb8cad
FIX: correct typing issues in tests
Nov 3, 2021
75ac320
FIX: correct typing issues in tests (2)
Nov 3, 2021
df416cf
FIX: correct typing issues in tests (3)
Nov 3, 2021
8282467
FIX: change call to argument includ_last_label from MapieClassifier t…
Nov 3, 2021
d012198
ENH: change argmax on boolean into argmax on masked array
Nov 4, 2021
31b83ab
ENH: remove argsort on already sorted array
Nov 4, 2021
7a0f470
Reply to the last remarks of Gregoire Martinon on
Nov 5, 2021
7d219b9
Minor linting modifications.
Nov 5, 2021
037a2a6
Vectorize randomization of last label incorporation.
Nov 5, 2021
2154f4f
Take GMA comments into account
Nov 8, 2021
f1605df
ENH: take into account GMO comments
Nov 8, 2021
e7b5975
FIX: fix typing issue
Nov 8, 2021
d811813
ENH: change u = 1- uniform into u = uniform
Nov 8, 2021
4f70db3
ENH: correct typos in comments
Nov 8, 2021
958a0e8
all remarks taken into account
Nov 9, 2021
d4d5854
Merge branch 'dev' of https://github.com/scikit-learn-contrib/MAPIE i…
Nov 9, 2021
aa3a00e
ENH: change from sorted to unsorted array for randomized and include_…
Nov 9, 2021
667dd04
ENH : work on unsorted probabilities
Nov 10, 2021
e183783
Merge branch 'dev' of github.com:scikit-learn-contrib/MAPIE into dev
Nov 10, 2021
9d103aa
FIX typing issue withh np.int64
Nov 10, 2021
bfc03a5
FIX : typing issue
Nov 10, 2021
b4b75b3
FIX : typing issue
Nov 10, 2021
7a207e4
FIX : typing issue
Nov 10, 2021
098330e
ENH : take into account GMO comments
Nov 15, 2021
3b638e6
ENH : take into account GMO comments
Nov 15, 2021
74ce283
ENH: directly add proba cumsed in random_tie_breaking function
Nov 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
__pycache__/
*.py[cod]
*$py.class
.DS_Store

# C extensions
*.so

# scikit-learn specific
# documentation specific
doc/_build/
doc/examples_classification/
doc/examples_regression/
doc/auto_examples/
doc/modules/generated/
doc/datasets/generated/
doc/generated/

# Distribution / packaging

Expand Down Expand Up @@ -68,3 +72,7 @@ target/

# VSCode
.vscode

# Images
*.png
*.jpeg
5 changes: 3 additions & 2 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ Contributors
* Alizé Papp <[email protected]>
* Abdou Akim Goumbala <[email protected]>
* Adirtha Borgohain <[email protected]>

To be continued ...
* Thomas Morzadec <[email protected]>
* Julien Roussel <[email protected]>
To be continued ...
9 changes: 8 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
History
=======

0.3.0 (XXXX-XX-XX)
0.3.1 (XXXX-XX-XX)
------------------

* Add Jackknife+-after-Bootstrap method and add mean and median as aggregation functions
* Add "cumulative_score" method in MapieClassifier


0.3.0 (2021-09-10)
------------------

* Renaming estimators.py module to regression.py
Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.PHONY: tests doc build

lint:
lint:
flake8 . --exclude=doc

type-check:
Expand All @@ -10,7 +9,7 @@ tests:
pytest -vs --doctest-modules mapie

coverage:
pytest -vs --doctest-modules --cov-branch --cov=mapie --pyargs mapie
pytest -vs --doctest-modules --cov-branch --cov=mapie --pyargs --cov-report term-missing mapie

doc:
$(MAKE) clean -C doc
Expand Down
Binary file modified doc/images/quickstart_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/tuto_classification_1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/tuto_classification_2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/tuto_classification_3.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
169 changes: 168 additions & 1 deletion doc/tutorial_classification.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,171 @@
Tutorial
========

TO BE CONTINUED
In this tutorial, we compare the prediction sets estimating by :class:`mapie.classification.MapieClassifier`.

Throughout this tutorial, we will answer the following question:

How does the number of classes in the prediction sets vary according to the significance level ?

1. Conformal Prediction method using the softmax score of the true label
========================================================================
We will use MAPIE to estimate a prediction set of several classes such that the probability that the true label
of a new test point is included in the prediction set is always higher than the target confidence level :
:math:` P(Y \in C) \geq 1 - \alpha`.
We start by using the softmax score output by the base classifier as the conformity score on a toy two-dimensional dataset.
We estimate the prediction sets as follows :

* First we generate a dataset with train, calibration and test, the model is fitted on the training set.
* We set the conformal score :math:`S_i = \hat{f}(X_{i})_{y_i}` the softmax output of the true class for each sample in the calibration set.
* Then we define :math:`\hat{q}` as being the :math:`(n + 1) (\alpha) / n` previous quantile of :math:`S_{1}, ..., S_{n}`
(this is essentially the quantile :math:`\alpha`, but with a small sample correction).
* Finally, for a new test data point (where :math:`X_{n + 1}` is known but :math:`Y_{n + 1}` is not), create a prediction set
:math:`C(X_{n+1}) = \{y: \hat{f}(X_{n+1})_{y} > \hat{q}\}` which includes all the classes with a sufficiently high softmax output.

We use a two-dimensional dataset with three labels. The distribution of the data is a bivariate normal with diagonal covariance matrices for each label.

.. code-block:: python

import numpy as np
centers = [(0, 3.5), (-2, 0), (2, 0)]
covs = [np.eye(2), np.eye(2)*2, np.diag([5, 1])]
x_min, x_max, y_min, y_max, step = -6, 8, -6, 8, 0.1
n_samples = 500
n_classes = 3
np.random.seed(42)
X = np.vstack([
np.random.multivariate_normal(center, cov, n_samples)
for center, cov in zip(centers, covs)
])
y = np.hstack([np.full(n_samples, i) for i in range(n_classes)])
X_train, X_cal, y_train, y_cal = train_test_split(X, y, test_size=0.3)

xx, yy = np.meshgrid(
np.arange(x_min, x_max, step), np.arange(x_min, x_max, step)
)
X_test = np.stack([xx.ravel(), yy.ravel()], axis=1)

Let's see our training data

.. code-block:: python

import matplotlib.pyplot as plt
colors = {0: "#1f77b4", 1: "#ff7f0e", 2: "#2ca02c", 3: "#d62728"}
y_train_col = list(map(colors.get, y_train))
fig = plt.figure()
plt.scatter(
X_train[:, 0],
X_train[:, 1],
color=y_train_col,
marker='o',
s=10,
edgecolor='k'
)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()

.. image:: images/tuto_classification_1.jpeg
:align: center

We fit our training data with a Gaussian Naive Base estimator. And then we apply :class:`mapie.classification.MapieClassifier` in the calibration data with the method ``score`` to the estimator indicating that it has already been fitted with `cv="prefit"`.
We then estimate the prediction sets with differents alpha values with a
``fit`` and ``predict`` process.

.. code-block:: python

from sklearn.naive_bayes import GaussianNB
from mapie.classification import MapieClassifier
from mapie.metrics import classification_coverage_score
clf = GaussianNB().fit(X_train, y_train)
y_pred = clf.predict(X_test)
y_pred_proba = clf.predict_proba(X_test)
y_pred_proba_max = np.max(y_pred_proba, axis=1)
mapie = MapieClassifier(estimator=clf, cv="prefit")
mapie.fit(X_cal, y_cal)
alpha = [0.2, 0.1, 0.05]
y_pred_mapie, y_ps_mapie = mapie.predict(X_test, alpha=alpha)


* ``y_pred_mapie``: represents the prediction in the test set by the base estimator.
* ``y_ps_mapie``: the prediction sets estimated by MAPIE.

.. code-block:: python

def plot_scores(n, alphas, scores, quantiles):
colors = {0:'#1f77b4', 1:'#ff7f0e', 2:'#2ca02c'}
fig = plt.figure()
plt.hist(scores, bins='auto')
i=0
for quantile in quantiles:
plt.vlines(x = quantile, ymin=0, ymax=400, color = colors[i], linestyles = 'dashed',label=f'alpha = {alphas[i]}')
i=i+1
plt.title("Distribution of scores")
plt.legend()
plt.xlabel("scores")
plt.ylabel("count")
plt.show()

Let's see the distribution of the scores with the calculated quantiles.

.. code-block:: python

scores = mapie.scores_
n = mapie.n_samples_val_
quantiles = mapie.quantiles_
plot_scores(n, alpha, scores, quantiles)

.. image:: images/tuto_classification_2.jpeg
:align: center

The estimated quantile depends on alpha and a high value of alpha can potentially lead to a high quantile which would
not necessarily be reached by any class in uncertain areas, resulting in null regions.

We will now compare the differences between the prediction sets of the different values ​​of alpha.

.. code-block:: python

def plot_results(alphas, y_pred_mapie, y_ps_mapie):
tab10 = plt.cm.get_cmap('Purples', 4)
colors = {0: "#1f77b4", 1: "#ff7f0e", 2: "#2ca02c", 3: "#d62728"}
y_pred_col = list(map(colors.get, y_pred_mapie))
fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2, figsize=(10, 10))
axs = {0: ax1, 1: ax2, 2: ax3, 3: ax4}
axs[0].scatter(
X_test[:, 0],
X_test[:, 1],
color=y_pred_col,
marker='.',
s=10,
alpha=0.4
)
axs[0].set_title("Predicted labels")
for i, alpha in enumerate(alphas):
y_pi_sums = y_ps_mapie[:, :, i].sum(axis=1)
num_labels = axs[i+1].scatter(
X_test[:, 0],
X_test[:, 1],
c=y_pi_sums,
marker='.',
s=10,
alpha=1,
cmap=tab10,
vmin=0,
vmax=3
)
cbar = plt.colorbar(num_labels, ax=axs[i+1])
coverage= classification_coverage_score(y_pred_mapie,y_ps_mapie[:,:,i])
axs[i+1].set_title(f"Number of labels for alpha={alpha_}")
plt.show()

.. code-block:: python

plot_results(alpha, y_pred_mapie, y_ps_mapie)

.. image:: images/tuto_classification_3.jpeg
:align: center

When the class coverage is not large enough, the prediction sets can be empty
when the model is uncertain at the border between two class. The null region
disappears for larger class coverages but ambiguous classification regions
arise with several labels included in the prediction sets.
Loading