Skip to content

Commit ec04387

Browse files
Update classification_coverage_score (#686)
This PR implements the transition from classification_coverage_score to classification_coverage_score_v2: * Replace all instances of classification_coverage_score with classification_coverage_score_v2 in the codebase and associated tests; * Remove the original classification_coverage_score function; * Rename classification_coverage_score_v2 to classification_coverage_score; * Update migration guide about this change.
1 parent 5043a0b commit ec04387

File tree

10 files changed

+33
-117
lines changed

10 files changed

+33
-117
lines changed

doc/api.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ Classification Metrics
7171
:template: function.rst
7272

7373
mapie.metrics.classification.classification_coverage_score
74-
mapie.metrics.classification.classification_coverage_score_v2
7574
mapie.metrics.classification.classification_mean_width_score
7675
mapie.metrics.classification.classification_ssc
7776
mapie.metrics.classification.classification_ssc_score

doc/quick_start.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ Similarly, it's possible to do the same for a basic classification problem.
138138
139139
.. code:: python
140140
141-
from mapie.metrics import classification_coverage_score_v2
141+
from mapie.metrics import classification_coverage_score
142142
143-
coverage_scores = classification_coverage_score_v2(y_test, y_pis)
143+
coverage_scores = classification_coverage_score(y_test, y_pis)
144144
145145
.. code:: python
146146

doc/v1_migration_guide.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ Additionally, a number of classification and regression functions have been upda
209209
- **v0.x**: Took the prediction sets in an array of shape (n_samples, n_class) for a given confidence level as input, and returned the effective mean width as a float.
210210
- **v1**: Now takes the prediction sets in an array of shape (n_samples, n_class, n_confidence_level) as input, and returns the effective mean width for each confidence level as an array of shape (n_confidence_level,).
211211

212+
``classification_coverage_score``
213+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214+
215+
- **v0.x**: Had two separate versions: ``classification_coverage_score`` and ``classification_coverage_v2``.
216+
- **v1**: ``classification_coverage_score`` now corresponds to MAPIE v0.x's ``classification_coverage_score_v2``.
217+
212218
``regression_mean_width``
213219
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214220

examples/classification/1-quickstart/plot_comp_methods_on_2d_dataset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
from numpy.typing import NDArray
5757
from mapie.classification import SplitConformalClassifier
5858
from mapie.metrics.classification import (
59-
classification_coverage_score_v2,
59+
classification_coverage_score,
6060
classification_mean_width_score,
6161
)
6262

@@ -264,7 +264,7 @@ def plot_results(
264264
X, conformity_score_params={"include_last_label": "randomized"}
265265
)
266266
coverage[conformity_score] = [
267-
classification_coverage_score_v2(y, y_ps_mapie[conformity_score])
267+
classification_coverage_score(y, y_ps_mapie[conformity_score])
268268
]
269269
mean_width[conformity_score] = classification_mean_width_score(
270270
y_ps_mapie[conformity_score]

examples/classification/4-tutorials/plot_crossconformal.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from numpy.typing import NDArray
3939
from mapie.classification import SplitConformalClassifier, CrossConformalClassifier
4040
from mapie.metrics.classification import (
41-
classification_coverage_score_v2,
41+
classification_coverage_score,
4242
classification_mean_width_score,
4343
)
4444

@@ -193,7 +193,7 @@ def plot_results(
193193
vmin=0,
194194
vmax=3
195195
)
196-
coverage = classification_coverage_score_v2(
196+
coverage = classification_coverage_score(
197197
y_test2, mapie.predict_set(X_test2)[1][:, :, 89]
198198
)[0]
199199
axs[i].set_title(f"coverage = {coverage:.3f}")
@@ -266,7 +266,7 @@ def plot_coverage_width(
266266
split_coverages = np.array(
267267
[
268268
[
269-
classification_coverage_score_v2(y_test_distrib, y_ps)
269+
classification_coverage_score(y_test_distrib, y_ps)
270270
for _, y_ps in y_ps2.items()
271271
] for _, y_ps2 in y_ps_mapies.items()
272272
]
@@ -414,7 +414,7 @@ def plot_coverage_width(
414414

415415
for strategy, y_ps_ in y_ps.items():
416416
coverages[strategy] = np.array(
417-
classification_coverage_score_v2(y_test_distrib, y_ps_)
417+
classification_coverage_score(y_test_distrib, y_ps_)
418418
)
419419
widths[strategy] = np.array(
420420
classification_mean_width_score(y_ps_)

examples/classification/4-tutorials/plot_main-tutorial-binary-classification.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
from mapie.classification import SplitConformalClassifier
3838
from mapie.utils import train_conformalize_test_split
3939
from mapie.metrics.classification import (
40-
classification_coverage_score_v2,
40+
classification_coverage_score,
4141
classification_mean_width_score,
4242
)
4343

@@ -304,7 +304,7 @@ def plot_results(
304304
mapie_clf.conformalize(X_c2, y_c2)
305305
_, y_ps_mapie = mapie_clf.predict_set(X)
306306

307-
coverage = classification_coverage_score_v2(y, y_ps_mapie)
307+
coverage = classification_coverage_score(y, y_ps_mapie)
308308
mean_width = classification_mean_width_score(y_ps_mapie)
309309

310310

examples/classification/4-tutorials/plot_main-tutorial-classification.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from mapie.classification import SplitConformalClassifier
2525
from mapie.utils import train_conformalize_test_split
2626
from mapie.metrics.classification import (
27-
classification_coverage_score_v2,
27+
classification_coverage_score,
2828
classification_mean_width_score,
2929
)
3030

@@ -222,7 +222,7 @@ def plot_results(confidence_levels, X, y_pred, y_ps):
222222
)
223223
mapie_score2.conformalize(X_conf, y_conf)
224224
_, y_ps_score2 = mapie_score2.predict_set(X_test)
225-
coverages_score = classification_coverage_score_v2(y_test, y_ps_score2)
225+
coverages_score = classification_coverage_score(y_test, y_ps_score2)
226226
widths_score = classification_mean_width_score(y_ps_score2)
227227

228228

@@ -290,7 +290,7 @@ def plot_coverages_widths(confidence_level, coverage, width, conformity_score):
290290
_, y_ps_aps2 = mapie_aps2.predict_set(
291291
X_test, conformity_score_params={"include_last_label": "randomized"}
292292
)
293-
coverages_aps = classification_coverage_score_v2(y_test, y_ps_aps2)
293+
coverages_aps = classification_coverage_score(y_test, y_ps_aps2)
294294
widths_aps = classification_mean_width_score(y_ps_aps2)
295295

296296
plot_coverages_widths(

mapie/metrics/classification.py

Lines changed: 5 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import numpy as np
44
from numpy.typing import ArrayLike, NDArray
5-
from sklearn.utils import column_or_1d, check_array
5+
from sklearn.utils import column_or_1d
66

77
from mapie.utils import (
88
_check_arrays_length,
@@ -12,63 +12,6 @@
1212
)
1313

1414

15-
def classification_coverage_score(
16-
y_true: ArrayLike,
17-
y_pred_set: ArrayLike
18-
) -> float:
19-
"""
20-
Effective coverage score obtained by the prediction sets.
21-
22-
The effective coverage is obtained by estimating the fraction
23-
of true labels that lie within the prediction sets.
24-
25-
Parameters
26-
----------
27-
y_true: ArrayLike of shape (n_samples,)
28-
True labels.
29-
y_pred_set: ArrayLike of shape (n_samples, n_class)
30-
Prediction sets given by booleans of labels.
31-
32-
Returns
33-
-------
34-
float
35-
Effective coverage obtained by the prediction sets.
36-
37-
Examples
38-
--------
39-
>>> from mapie.metrics.classification import classification_coverage_score
40-
>>> import numpy as np
41-
>>> y_true = np.array([3, 3, 1, 2, 2])
42-
>>> y_pred_set = np.array([
43-
... [False, False, True, True],
44-
... [False, True, False, True],
45-
... [False, True, True, False],
46-
... [False, False, True, True],
47-
... [False, True, False, True]
48-
... ])
49-
>>> print(classification_coverage_score(y_true, y_pred_set))
50-
0.8
51-
"""
52-
y_true = cast(NDArray, column_or_1d(y_true))
53-
y_pred_set = cast(
54-
NDArray,
55-
check_array(
56-
y_pred_set, dtype=["bool"]
57-
)
58-
)
59-
60-
_check_arrays_length(y_true, y_pred_set)
61-
_check_array_nan(y_true)
62-
_check_array_inf(y_true)
63-
_check_array_nan(y_pred_set)
64-
_check_array_inf(y_pred_set)
65-
66-
coverage = np.take_along_axis(
67-
y_pred_set, y_true.reshape(-1, 1), axis=1
68-
).mean()
69-
return float(coverage)
70-
71-
7215
def classification_mean_width_score(y_pred_set: ArrayLike) -> float:
7316
"""
7417
Mean width of prediction set output by
@@ -106,7 +49,7 @@ def classification_mean_width_score(y_pred_set: ArrayLike) -> float:
10649
return mean_width
10750

10851

109-
def classification_coverage_score_v2(
52+
def classification_coverage_score(
11053
y_true: NDArray,
11154
y_pred_set: NDArray
11255
) -> NDArray:
@@ -141,7 +84,7 @@ def classification_coverage_score_v2(
14184
14285
Examples
14386
--------
144-
>>> from mapie.metrics.classification import classification_coverage_score_v2
87+
>>> from mapie.metrics.classification import classification_coverage_score
14588
>>> from mapie.classification import SplitConformalClassifier
14689
>>> from mapie.utils import train_conformalize_test_split
14790
>>> from sklearn.datasets import make_classification
@@ -163,7 +106,7 @@ def classification_coverage_score_v2(
163106
... ).fit(X_train, y_train).conformalize(X_conformalize, y_conformalize)
164107
165108
>>> predicted_points, predicted_sets = mapie_classifier.predict_set(X_test)
166-
>>> coverage = classification_coverage_score_v2(y_test, predicted_sets)[0]
109+
>>> coverage = classification_coverage_score(y_test, predicted_sets)[0]
167110
"""
168111
_check_arrays_length(y_true, y_pred_set)
169112
_check_array_nan(y_true)
@@ -258,7 +201,7 @@ def classification_ssc(
258201
]
259202

260203
for i, indexes in enumerate(indexes_bybins):
261-
coverages[alpha, i] = classification_coverage_score_v2(
204+
coverages[alpha, i] = classification_coverage_score(
262205
y_true[indexes],
263206
np.take_along_axis(
264207
y_pred_set[:, :, alpha],

mapie/tests/test_classification.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,7 @@ def test_toy_dataset_predictions(strategy: str) -> None:
14601460
)
14611461
np.testing.assert_allclose(y_ps[:, :, 0], y_toy_mapie[strategy])
14621462
np.testing.assert_allclose(
1463-
classification_coverage_score(y_toy, y_ps[:, :, 0]),
1463+
classification_coverage_score(y_toy, y_ps)[0],
14641464
COVERAGES[strategy],
14651465
)
14661466

@@ -1482,7 +1482,7 @@ def test_large_dataset_predictions(strategy: str) -> None:
14821482
agg_scores=args_predict["agg_scores"]
14831483
)
14841484
np.testing.assert_allclose(
1485-
classification_coverage_score(y, y_ps[:, :, 0]),
1485+
classification_coverage_score(y, y_ps)[0],
14861486
LARGE_COVERAGES[strategy], rtol=1e-2
14871487
)
14881488

@@ -1507,7 +1507,7 @@ def test_toy_binary_dataset_predictions(strategy: str) -> None:
15071507
)
15081508
np.testing.assert_allclose(y_ps[:, :, 0], y_toy_binary_mapie[strategy])
15091509
np.testing.assert_allclose(
1510-
classification_coverage_score(y_toy_binary, y_ps[:, :, 0]),
1510+
classification_coverage_score(y_toy_binary, y_ps)[0],
15111511
COVERAGES_BINARY[strategy],
15121512
)
15131513

mapie/tests/test_metrics.py

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
top_label_ece,
2727
)
2828
from mapie.metrics.classification import (
29-
classification_coverage_score,
3029
classification_mean_width_score,
31-
classification_coverage_score_v2,
30+
classification_coverage_score,
3231
classification_ssc, classification_ssc_score,
3332
)
3433
from mapie.metrics.regression import (
@@ -265,10 +264,6 @@ def test_regression_toydata_coverage_score() -> None:
265264

266265
def test_classification_y_true_shape() -> None:
267266
"""Test shape of y_true."""
268-
with pytest.raises(ValueError, match=r".*y should be a 1d array*"):
269-
classification_coverage_score(
270-
np.tile(y_true_class, (2, 1)), y_pred_set
271-
)
272267
with pytest.raises(ValueError, match=r".*y should be a 1d array*"):
273268
classification_ssc(np.tile(y_true_class, (2, 1)), y_pred_set_2alphas)
274269
with pytest.raises(ValueError, match=r".*are arrays with different len*"):
@@ -278,8 +273,6 @@ def test_classification_y_true_shape() -> None:
278273

279274
def test_classification_y_pred_set_shape() -> None:
280275
"""Test shape of y_pred_set."""
281-
with pytest.raises(ValueError, match=r".*Expected 2D array*"):
282-
classification_coverage_score(y_true_class, y_pred_set[:, 0])
283276
with pytest.raises(ValueError, match=r".*should be a 3D array*"):
284277
classification_ssc(y_true_class, y_pred_set[:, 0])
285278
with pytest.raises(ValueError, match=r".*should be a 3D array*"):
@@ -305,19 +298,7 @@ def test_classification_valid_input_shape() -> None:
305298

306299
def test_classification_toydata() -> None:
307300
"""Test coverage_score for toy data."""
308-
assert classification_coverage_score(y_true_class, y_pred_set) == 0.8
309-
310-
311-
def test_classification_ytrue_type() -> None:
312-
"""Test that list(y_true_class) gives right coverage."""
313-
scr = classification_coverage_score(list(y_true_class), y_pred_set)
314-
assert scr == 0.8
315-
316-
317-
def test_classification_y_pred_set_type() -> None:
318-
"""Test that list(y_pred_set) gives right coverage."""
319-
scr = classification_coverage_score(y_true_class, list(y_pred_set))
320-
assert scr == 0.8
301+
assert classification_coverage_score(y_true_class, y_pred_set)[0] == 0.8
321302

322303

323304
def test_classification_mean_width_score_toydata() -> None:
@@ -550,28 +531,15 @@ def test_regression_coverage_score_intervals_invalid_shape() -> None:
550531
)
551532

552533

553-
def test_classification_coverage_v1andv2() -> None:
554-
"""
555-
Test that ``classification_coverage_score`` and
556-
```classification_coverage_score_v2``` returns the same results
557-
"""
558-
cov_v1 = classification_coverage_score(y_true_class, y_pred_set)
559-
cov_v2 = classification_coverage_score_v2(
560-
np.expand_dims(y_true_class, axis=1),
561-
np.expand_dims(y_pred_set, axis=2)
562-
)
563-
np.testing.assert_allclose(cov_v1, cov_v2[0])
564-
565-
566-
def test_classification_coverage_score_v2_ytrue_valid_shape() -> None:
534+
def test_classification_coverage_score_ytrue_valid_shape() -> None:
567535
"""Test that no error is raised if y_true has a shape (n_samples,)."""
568-
classification_coverage_score_v2(y_true_class, y_pred_set_2alphas)
536+
classification_coverage_score(y_true_class, y_pred_set_2alphas)
569537

570538

571-
def test_classification_coverage_score_v2_ypredset_invalid_shape() -> None:
539+
def test_classification_coverage_score_ypredset_invalid_shape() -> None:
572540
"""Test that an error is raised if y_pred_set has not the good shape."""
573541
with pytest.raises(ValueError):
574-
classification_coverage_score_v2(
542+
classification_coverage_score(
575543
np.expand_dims(y_true_class, axis=1), y_pred_set[:, 0]
576544
)
577545

0 commit comments

Comments
 (0)