Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6489daf

Browse filesBrowse files
authored
TST Fix RuntimeWarning: invalid value encountered in test_calibration.py (#19421)
1 parent f58d1eb commit 6489daf
Copy full SHA for 6489daf

File tree

2 files changed

+32
-5
lines changed
Filter options

2 files changed

+32
-5
lines changed

‎sklearn/calibration.py

Copy file name to clipboardExpand all lines: sklearn/calibration.py
+7-4Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -656,10 +656,13 @@ def predict_proba(self, X):
656656
if n_classes == 2:
657657
proba[:, 0] = 1. - proba[:, 1]
658658
else:
659-
proba /= np.sum(proba, axis=1)[:, np.newaxis]
660-
661-
# XXX : for some reason all probas can be 0
662-
proba[np.isnan(proba)] = 1. / n_classes
659+
denominator = np.sum(proba, axis=1)[:, np.newaxis]
660+
# In the edge case where for each class calibrator returns a null
661+
# probability for a given sample, use the uniform distribution
662+
# instead.
663+
uniform_proba = np.full_like(proba, 1 / n_classes)
664+
proba = np.divide(proba, denominator, out=uniform_proba,
665+
where=denominator != 0)
663666

664667
# Deal with cases where the predicted probability minimally exceeds 1.0
665668
proba[(1.0 < proba) & (proba <= 1.0 + 1e-5)] = 1.0

‎sklearn/tests/test_calibration.py

Copy file name to clipboardExpand all lines: sklearn/tests/test_calibration.py
+25-1Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from scipy import sparse
88

99
from sklearn.base import BaseEstimator
10+
from sklearn.dummy import DummyClassifier
1011
from sklearn.model_selection import LeaveOneOut, train_test_split
1112

1213
from sklearn.utils._testing import (assert_array_almost_equal,
@@ -26,7 +27,7 @@
2627
from sklearn.pipeline import Pipeline
2728
from sklearn.impute import SimpleImputer
2829
from sklearn.metrics import brier_score_loss
29-
from sklearn.calibration import CalibratedClassifierCV
30+
from sklearn.calibration import CalibratedClassifierCV, _CalibratedClassifier
3031
from sklearn.calibration import _sigmoid_calibration, _SigmoidCalibration
3132
from sklearn.calibration import calibration_curve
3233

@@ -275,6 +276,29 @@ def multiclass_brier(y_true, proba_pred, n_classes):
275276
assert calibrated_brier < 1.1 * uncalibrated_brier
276277

277278

279+
def test_calibration_zero_probability():
280+
# Test an edge case where _CalibratedClassifier avoids numerical errors
281+
# in the multiclass normalization step if all the calibrators output
282+
# are zero all at once for a given sample and instead fallback to uniform
283+
# probabilities.
284+
class ZeroCalibrator():
285+
# This function is called from _CalibratedClassifier.predict_proba.
286+
def predict(self, X):
287+
return np.zeros(X.shape[0])
288+
289+
X, y = make_blobs(n_samples=50, n_features=10, random_state=7,
290+
centers=10, cluster_std=15.0)
291+
clf = DummyClassifier().fit(X, y)
292+
calibrator = ZeroCalibrator()
293+
cal_clf = _CalibratedClassifier(
294+
base_estimator=clf, calibrators=[calibrator], classes=clf.classes_)
295+
296+
probas = cal_clf.predict_proba(X)
297+
298+
# Check that all probabilities are uniformly 1. / clf.n_classes_
299+
assert_allclose(probas, 1. / clf.n_classes_)
300+
301+
278302
def test_calibration_prefit():
279303
"""Test calibration for prefitted classifiers"""
280304
n_samples = 50

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.