diff --git a/doc/whats_new/v0.22.rst b/doc/whats_new/v0.22.rst index d123855c1ece8..448b7789e175f 100644 --- a/doc/whats_new/v0.22.rst +++ b/doc/whats_new/v0.22.rst @@ -69,15 +69,18 @@ Changelog :mod:`sklearn.ensemble` ....................... +- |Feature| :class:`ensemble.HistGradientBoostingClassifier` and + :class:`ensemble.HistGradientBoostingRegressor` have an additional + parameter called `warm_start` that enables warm starting. :pr:`14012` by + :user:`Johann Faouzi `. + - |Fix| :class:`ensemble.HistGradientBoostingClassifier` and :class:`ensemble.HistGradientBoostingRegressor` now bin the training and validation data separately to avoid any data leak. :pr:`13933` by `Nicolas Hug`_. -- |Feature| :class:`ensemble.HistGradientBoostingClassifier` and - :class:`ensemble.HistGradientBoostingRegressor` have an additional - parameter called `warm_start` that enables warm starting. :pr:`14012` by - :user:`Johann Faouzi `. +- |Fix| :func:`ensemble.VotingClassifier.predict_proba` will no longer be + present when `voting='hard'`. :pr:`14287` by `Thomas Fan`_. - |Enhancement| :class:`ensemble.HistGradientBoostingClassifier` the training loss or score is now monitored on a class-wise stratified subsample to diff --git a/sklearn/ensemble/tests/test_voting.py b/sklearn/ensemble/tests/test_voting.py index 767755c23f460..5cd971934abf2 100644 --- a/sklearn/ensemble/tests/test_voting.py +++ b/sklearn/ensemble/tests/test_voting.py @@ -68,7 +68,12 @@ def test_predictproba_hardvoting(): ('lr2', LogisticRegression())], voting='hard') msg = "predict_proba is not available when voting='hard'" - assert_raise_message(AttributeError, msg, eclf.predict_proba, X) + with pytest.raises(AttributeError, match=msg): + eclf.predict_proba + + assert not hasattr(eclf, "predict_proba") + eclf.fit(X, y) + assert not hasattr(eclf, "predict_proba") def test_notfitted(): diff --git a/sklearn/ensemble/voting.py b/sklearn/ensemble/voting.py index 0b01340d4f1af..b29ad46c238f5 100644 --- a/sklearn/ensemble/voting.py +++ b/sklearn/ensemble/voting.py @@ -313,9 +313,6 @@ def _collect_probas(self, X): def _predict_proba(self, X): """Predict class probabilities for X in 'soft' voting """ - if self.voting == 'hard': - raise AttributeError("predict_proba is not available when" - " voting=%r" % self.voting) check_is_fitted(self, 'estimators_') avg = np.average(self._collect_probas(X), axis=0, weights=self._weights_not_none) @@ -335,6 +332,9 @@ def predict_proba(self): avg : array-like, shape (n_samples, n_classes) Weighted average probability for each class per sample. """ + if self.voting == 'hard': + raise AttributeError("predict_proba is not available when" + " voting=%r" % self.voting) return self._predict_proba def transform(self, X):