Skip to content

Commit 91486d6

Browse files
API Replace y_pred with y_score in DetCurveDisplay and PrecisionRecallDisplay (scikit-learn#31764)
Co-authored-by: Jérémie du Boisberranger <jeremie@probabl.ai>
1 parent c84c33e commit 91486d6

8 files changed

Lines changed: 157 additions & 86 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- `y_pred` is deprecated in favour of `y_score` in
2+
:func:`metrics.DetCurveDisplay.from_predictions` and
3+
:func:`metrics.PrecisionRecallDisplay.from_predictions`. `y_pred` will be removed in
4+
v1.10.
5+
By :user:`Luis <luiser1401>`

sklearn/metrics/_plot/det_curve.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import numpy as np
55
import scipy as sp
66

7-
from ...utils._plotting import _BinaryClassifierCurveDisplayMixin
7+
from ...utils._plotting import (
8+
_BinaryClassifierCurveDisplayMixin,
9+
_deprecate_y_pred_parameter,
10+
)
811
from .._ranking import det_curve
912

1013

@@ -67,8 +70,8 @@ class DetCurveDisplay(_BinaryClassifierCurveDisplayMixin):
6770
>>> X_train, X_test, y_train, y_test = train_test_split(
6871
... X, y, test_size=0.4, random_state=0)
6972
>>> clf = SVC(random_state=0).fit(X_train, y_train)
70-
>>> y_pred = clf.decision_function(X_test)
71-
>>> fpr, fnr, _ = det_curve(y_test, y_pred)
73+
>>> y_score = clf.decision_function(X_test)
74+
>>> fpr, fnr, _ = det_curve(y_test, y_score)
7275
>>> display = DetCurveDisplay(
7376
... fpr=fpr, fnr=fnr, estimator_name="SVC"
7477
... )
@@ -178,7 +181,7 @@ def from_estimator(
178181
<...>
179182
>>> plt.show()
180183
"""
181-
y_pred, pos_label, name = cls._validate_and_get_response_values(
184+
y_score, pos_label, name = cls._validate_and_get_response_values(
182185
estimator,
183186
X,
184187
y,
@@ -189,7 +192,7 @@ def from_estimator(
189192

190193
return cls.from_predictions(
191194
y_true=y,
192-
y_pred=y_pred,
195+
y_score=y_score,
193196
sample_weight=sample_weight,
194197
drop_intermediate=drop_intermediate,
195198
name=name,
@@ -202,13 +205,14 @@ def from_estimator(
202205
def from_predictions(
203206
cls,
204207
y_true,
205-
y_pred,
208+
y_score=None,
206209
*,
207210
sample_weight=None,
208211
drop_intermediate=True,
209212
pos_label=None,
210213
name=None,
211214
ax=None,
215+
y_pred="deprecated",
212216
**kwargs,
213217
):
214218
"""Plot the DET curve given the true and predicted labels.
@@ -225,11 +229,14 @@ def from_predictions(
225229
y_true : array-like of shape (n_samples,)
226230
True labels.
227231
228-
y_pred : array-like of shape (n_samples,)
232+
y_score : array-like of shape (n_samples,)
229233
Target scores, can either be probability estimates of the positive
230234
class, confidence values, or non-thresholded measure of decisions
231235
(as returned by `decision_function` on some classifiers).
232236
237+
.. versionadded:: 1.8
238+
`y_pred` has been renamed to `y_score`.
239+
233240
sample_weight : array-like of shape (n_samples,), default=None
234241
Sample weights.
235242
@@ -253,6 +260,15 @@ def from_predictions(
253260
Axes object to plot on. If `None`, a new figure and axes is
254261
created.
255262
263+
y_pred : array-like of shape (n_samples,)
264+
Target scores, can either be probability estimates of the positive
265+
class, confidence values, or non-thresholded measure of decisions
266+
(as returned by “decision_function” on some classifiers).
267+
268+
.. deprecated:: 1.8
269+
`y_pred` is deprecated and will be removed in 1.10. Use
270+
`y_score` instead.
271+
256272
**kwargs : dict
257273
Additional keywords arguments passed to matplotlib `plot` function.
258274
@@ -278,19 +294,20 @@ def from_predictions(
278294
>>> X_train, X_test, y_train, y_test = train_test_split(
279295
... X, y, test_size=0.4, random_state=0)
280296
>>> clf = SVC(random_state=0).fit(X_train, y_train)
281-
>>> y_pred = clf.decision_function(X_test)
297+
>>> y_score = clf.decision_function(X_test)
282298
>>> DetCurveDisplay.from_predictions(
283-
... y_test, y_pred)
299+
... y_test, y_score)
284300
<...>
285301
>>> plt.show()
286302
"""
303+
y_score = _deprecate_y_pred_parameter(y_score, y_pred, "1.8")
287304
pos_label_validated, name = cls._validate_from_predictions_params(
288-
y_true, y_pred, sample_weight=sample_weight, pos_label=pos_label, name=name
305+
y_true, y_score, sample_weight=sample_weight, pos_label=pos_label, name=name
289306
)
290307

291308
fpr, fnr, _ = det_curve(
292309
y_true,
293-
y_pred,
310+
y_score,
294311
pos_label=pos_label,
295312
sample_weight=sample_weight,
296313
drop_intermediate=drop_intermediate,

sklearn/metrics/_plot/precision_recall_curve.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from ...utils._plotting import (
77
_BinaryClassifierCurveDisplayMixin,
8+
_deprecate_y_pred_parameter,
89
_despine,
910
_validate_style_kwargs,
1011
)
@@ -383,7 +384,7 @@ def from_estimator(
383384
<...>
384385
>>> plt.show()
385386
"""
386-
y_pred, pos_label, name = cls._validate_and_get_response_values(
387+
y_score, pos_label, name = cls._validate_and_get_response_values(
387388
estimator,
388389
X,
389390
y,
@@ -394,7 +395,7 @@ def from_estimator(
394395

395396
return cls.from_predictions(
396397
y,
397-
y_pred,
398+
y_score,
398399
sample_weight=sample_weight,
399400
name=name,
400401
pos_label=pos_label,
@@ -410,7 +411,7 @@ def from_estimator(
410411
def from_predictions(
411412
cls,
412413
y_true,
413-
y_pred,
414+
y_score=None,
414415
*,
415416
sample_weight=None,
416417
drop_intermediate=False,
@@ -420,6 +421,7 @@ def from_predictions(
420421
plot_chance_level=False,
421422
chance_level_kw=None,
422423
despine=False,
424+
y_pred="deprecated",
423425
**kwargs,
424426
):
425427
"""Plot precision-recall curve given binary class predictions.
@@ -434,9 +436,12 @@ def from_predictions(
434436
y_true : array-like of shape (n_samples,)
435437
True binary labels.
436438
437-
y_pred : array-like of shape (n_samples,)
439+
y_score : array-like of shape (n_samples,)
438440
Estimated probabilities or output of decision function.
439441
442+
.. versionadded:: 1.8
443+
`y_pred` has been renamed to `y_score`.
444+
440445
sample_weight : array-like of shape (n_samples,), default=None
441446
Sample weights.
442447
@@ -478,6 +483,13 @@ def from_predictions(
478483
479484
.. versionadded:: 1.6
480485
486+
y_pred : array-like of shape (n_samples,)
487+
Estimated probabilities or output of decision function.
488+
489+
.. deprecated:: 1.8
490+
`y_pred` is deprecated and will be removed in 1.10. Use
491+
`y_score` instead.
492+
481493
**kwargs : dict
482494
Keyword arguments to be passed to matplotlib's `plot`.
483495
@@ -514,25 +526,26 @@ def from_predictions(
514526
>>> clf = LogisticRegression()
515527
>>> clf.fit(X_train, y_train)
516528
LogisticRegression()
517-
>>> y_pred = clf.predict_proba(X_test)[:, 1]
529+
>>> y_score = clf.predict_proba(X_test)[:, 1]
518530
>>> PrecisionRecallDisplay.from_predictions(
519-
... y_test, y_pred)
531+
... y_test, y_score)
520532
<...>
521533
>>> plt.show()
522534
"""
535+
y_score = _deprecate_y_pred_parameter(y_score, y_pred, "1.8")
523536
pos_label, name = cls._validate_from_predictions_params(
524-
y_true, y_pred, sample_weight=sample_weight, pos_label=pos_label, name=name
537+
y_true, y_score, sample_weight=sample_weight, pos_label=pos_label, name=name
525538
)
526539

527540
precision, recall, _ = precision_recall_curve(
528541
y_true,
529-
y_pred,
542+
y_score,
530543
pos_label=pos_label,
531544
sample_weight=sample_weight,
532545
drop_intermediate=drop_intermediate,
533546
)
534547
average_precision = average_precision_score(
535-
y_true, y_pred, pos_label=pos_label, sample_weight=sample_weight
548+
y_true, y_score, pos_label=pos_label, sample_weight=sample_weight
536549
)
537550

538551
class_count = Counter(y_true)

sklearn/metrics/_plot/roc_curve.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
# SPDX-License-Identifier: BSD-3-Clause
33

44

5-
import warnings
6-
75
import numpy as np
86

97
from ...utils import _safe_indexing
@@ -12,6 +10,7 @@
1210
_check_param_lengths,
1311
_convert_to_list_leaving_none,
1412
_deprecate_estimator_name,
13+
_deprecate_y_pred_parameter,
1514
_despine,
1615
_validate_style_kwargs,
1716
)
@@ -576,24 +575,7 @@ def from_predictions(
576575
<...>
577576
>>> plt.show()
578577
"""
579-
# TODO(1.9): remove after the end of the deprecation period of `y_pred`
580-
if y_score is not None and not (
581-
isinstance(y_pred, str) and y_pred == "deprecated"
582-
):
583-
raise ValueError(
584-
"`y_pred` and `y_score` cannot be both specified. Please use `y_score`"
585-
" only as `y_pred` is deprecated in 1.7 and will be removed in 1.9."
586-
)
587-
if not (isinstance(y_pred, str) and y_pred == "deprecated"):
588-
warnings.warn(
589-
(
590-
"y_pred is deprecated in 1.7 and will be removed in 1.9. "
591-
"Please use `y_score` instead."
592-
),
593-
FutureWarning,
594-
)
595-
y_score = y_pred
596-
578+
y_score = _deprecate_y_pred_parameter(y_score, y_pred, "1.7")
597579
pos_label_validated, name = cls._validate_from_predictions_params(
598580
y_true, y_score, sample_weight=sample_weight, pos_label=pos_label, name=name
599581
)

sklearn/metrics/_plot/tests/test_det_curve_display.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,9 @@ def test_det_curve_display(
3737

3838
lr = LogisticRegression()
3939
lr.fit(X, y)
40-
y_pred = getattr(lr, response_method)(X)
41-
if y_pred.ndim == 2:
42-
y_pred = y_pred[:, 1]
43-
40+
y_score = getattr(lr, response_method)(X)
41+
if y_score.ndim == 2:
42+
y_score = y_score[:, 1]
4443
# safe guard for the binary if/else construction
4544
assert constructor_name in ("from_estimator", "from_predictions")
4645

@@ -54,11 +53,11 @@ def test_det_curve_display(
5453
if constructor_name == "from_estimator":
5554
disp = DetCurveDisplay.from_estimator(lr, X, y, **common_kwargs)
5655
else:
57-
disp = DetCurveDisplay.from_predictions(y, y_pred, **common_kwargs)
56+
disp = DetCurveDisplay.from_predictions(y, y_score, **common_kwargs)
5857

5958
fpr, fnr, _ = det_curve(
6059
y,
61-
y_pred,
60+
y_score,
6261
sample_weight=sample_weight,
6362
drop_intermediate=drop_intermediate,
6463
pos_label=pos_label,
@@ -103,12 +102,30 @@ def test_det_curve_display_default_name(
103102
X, y = X[y < 2], y[y < 2]
104103

105104
lr = LogisticRegression().fit(X, y)
106-
y_pred = lr.predict_proba(X)[:, 1]
105+
y_score = lr.predict_proba(X)[:, 1]
107106

108107
if constructor_name == "from_estimator":
109108
disp = DetCurveDisplay.from_estimator(lr, X, y)
110109
else:
111-
disp = DetCurveDisplay.from_predictions(y, y_pred)
110+
disp = DetCurveDisplay.from_predictions(y, y_score)
112111

113112
assert disp.estimator_name == expected_clf_name
114113
assert disp.line_.get_label() == expected_clf_name
114+
115+
116+
# TODO(1.10): remove
117+
def test_y_score_and_y_pred_specified_error(pyplot):
118+
"""1. Check that an error is raised when both y_score and y_pred are specified.
119+
2. Check that a warning is raised when y_pred is specified.
120+
"""
121+
y_true = np.array([0, 0, 1, 1])
122+
y_score = np.array([0.1, 0.4, 0.35, 0.8])
123+
y_pred = np.array([0.2, 0.3, 0.5, 0.1])
124+
125+
with pytest.raises(
126+
ValueError, match="`y_pred` and `y_score` cannot be both specified"
127+
):
128+
DetCurveDisplay.from_predictions(y_true, y_score=y_score, y_pred=y_pred)
129+
130+
with pytest.warns(FutureWarning, match="y_pred was deprecated in 1.8"):
131+
DetCurveDisplay.from_predictions(y_true, y_pred=y_score)

0 commit comments

Comments
 (0)