|
17 | 17 | from sklearn.utils import shuffle
|
18 | 18 | from sklearn.utils._mocking import NoSampleWeightWrapper
|
19 | 19 | from sklearn.utils._testing import (
|
| 20 | + assert_allclose, |
20 | 21 | assert_array_almost_equal,
|
21 | 22 | assert_array_equal,
|
22 | 23 | assert_array_less,
|
@@ -693,3 +694,45 @@ def test_deprecated_base_estimator_parameters_can_be_set():
|
693 | 694 |
|
694 | 695 | with pytest.warns(FutureWarning, match="Parameter 'base_estimator' of"):
|
695 | 696 | clf.set_params(base_estimator__max_depth=2)
|
| 697 | + |
| 698 | + |
| 699 | +@pytest.mark.parametrize("algorithm", ["SAMME", "SAMME.R"]) |
| 700 | +def test_adaboost_decision_function(algorithm, global_random_seed): |
| 701 | + """Check that the decision function respects the symmetric constraint for weak |
| 702 | + learners. |
| 703 | +
|
| 704 | + Non-regression test for: |
| 705 | + https://github.com/scikit-learn/scikit-learn/issues/26520 |
| 706 | + """ |
| 707 | + n_classes = 3 |
| 708 | + X, y = datasets.make_classification( |
| 709 | + n_classes=n_classes, n_clusters_per_class=1, random_state=global_random_seed |
| 710 | + ) |
| 711 | + clf = AdaBoostClassifier( |
| 712 | + n_estimators=1, random_state=global_random_seed, algorithm=algorithm |
| 713 | + ).fit(X, y) |
| 714 | + |
| 715 | + y_score = clf.decision_function(X) |
| 716 | + assert_allclose(y_score.sum(axis=1), 0, atol=1e-8) |
| 717 | + |
| 718 | + if algorithm == "SAMME": |
| 719 | + # With a single learner, we expect to have a decision function in |
| 720 | + # {1, - 1 / (n_classes - 1)}. |
| 721 | + assert set(np.unique(y_score)) == {1, -1 / (n_classes - 1)} |
| 722 | + |
| 723 | + # We can assert the same for staged_decision_function since we have a single learner |
| 724 | + for y_score in clf.staged_decision_function(X): |
| 725 | + assert_allclose(y_score.sum(axis=1), 0, atol=1e-8) |
| 726 | + |
| 727 | + if algorithm == "SAMME": |
| 728 | + # With a single learner, we expect to have a decision function in |
| 729 | + # {1, - 1 / (n_classes - 1)}. |
| 730 | + assert set(np.unique(y_score)) == {1, -1 / (n_classes - 1)} |
| 731 | + |
| 732 | + clf.set_params(n_estimators=5).fit(X, y) |
| 733 | + |
| 734 | + y_score = clf.decision_function(X) |
| 735 | + assert_allclose(y_score.sum(axis=1), 0, atol=1e-8) |
| 736 | + |
| 737 | + for y_score in clf.staged_decision_function(X): |
| 738 | + assert_allclose(y_score.sum(axis=1), 0, atol=1e-8) |
0 commit comments