Aluode/PerceptionLabPortable
0
1import numpy as np
2import pytest
3from numpy.testing import assert_array_equal
4from scipy import sparse
5
6from sklearn.datasets import load_iris
7from sklearn.utils import _safe_indexing, check_array
8from sklearn.utils._mocking import (
9 CheckingClassifier,
10 _MockEstimatorOnOffPrediction,
11)
12from sklearn.utils._testing import _convert_container
13from sklearn.utils.fixes import CSR_CONTAINERS
14
15
16@pytest.fixture
17def iris():
18 return load_iris(return_X_y=True)
19
20
21def _success(x):
22 return True
23
24
25def _fail(x):
26 return False
27
28
29@pytest.mark.parametrize(
30 "kwargs",
31 [
32 {},
33 {"check_X": _success},
34 {"check_y": _success},
35 {"check_X": _success, "check_y": _success},
36 ],
37)
38def test_check_on_fit_success(iris, kwargs):
39 X, y = iris
40 CheckingClassifier(**kwargs).fit(X, y)
41
42
43@pytest.mark.parametrize(
44 "kwargs",
45 [
46 {"check_X": _fail},
47 {"check_y": _fail},
48 {"check_X": _success, "check_y": _fail},
49 {"check_X": _fail, "check_y": _success},
50 {"check_X": _fail, "check_y": _fail},
51 ],
52)
53def test_check_on_fit_fail(iris, kwargs):
54 X, y = iris
55 clf = CheckingClassifier(**kwargs)
56 with pytest.raises(AssertionError):
57 clf.fit(X, y)
58
59
60@pytest.mark.parametrize(
61 "pred_func", ["predict", "predict_proba", "decision_function", "score"]
62)
63def test_check_X_on_predict_success(iris, pred_func):
64 X, y = iris
65 clf = CheckingClassifier(check_X=_success).fit(X, y)
66 getattr(clf, pred_func)(X)
67
68
69@pytest.mark.parametrize(
70 "pred_func", ["predict", "predict_proba", "decision_function", "score"]
71)
72def test_check_X_on_predict_fail(iris, pred_func):
73 X, y = iris
74 clf = CheckingClassifier(check_X=_success).fit(X, y)
75 clf.set_params(check_X=_fail)
76 with pytest.raises(AssertionError):
77 getattr(clf, pred_func)(X)
78
79
80@pytest.mark.parametrize("input_type", ["list", "array", "sparse", "dataframe"])
81def test_checking_classifier(iris, input_type):
82 # Check that the CheckingClassifier outputs what we expect
83 X, y = iris
84 X = _convert_container(X, input_type)
85 clf = CheckingClassifier()
86 clf.fit(X, y)
87
88 assert_array_equal(clf.classes_, np.unique(y))
89 assert len(clf.classes_) == 3
90 assert clf.n_features_in_ == 4
91
92 y_pred = clf.predict(X)
93 assert all(pred in clf.classes_ for pred in y_pred)
94
95 assert clf.score(X) == pytest.approx(0)
96 clf.set_params(foo_param=10)
97 assert clf.fit(X, y).score(X) == pytest.approx(1)
98
99 y_proba = clf.predict_proba(X)
100 assert y_proba.shape == (150, 3)
101 assert np.logical_and(y_proba >= 0, y_proba <= 1).all()
102
103 y_decision = clf.decision_function(X)
104 assert y_decision.shape == (150, 3)
105
106 # check the shape in case of binary classification
107 first_2_classes = np.logical_or(y == 0, y == 1)
108 X = _safe_indexing(X, first_2_classes)
109 y = _safe_indexing(y, first_2_classes)
110 clf.fit(X, y)
111
112 y_proba = clf.predict_proba(X)
113 assert y_proba.shape == (100, 2)
114 assert np.logical_and(y_proba >= 0, y_proba <= 1).all()
115
116 y_decision = clf.decision_function(X)
117 assert y_decision.shape == (100,)
118
119
120@pytest.mark.parametrize("csr_container", CSR_CONTAINERS)
121def test_checking_classifier_with_params(iris, csr_container):
122 X, y = iris
123 X_sparse = csr_container(X)
124
125 clf = CheckingClassifier(check_X=sparse.issparse)
126 with pytest.raises(AssertionError):
127 clf.fit(X, y)
128 clf.fit(X_sparse, y)
129
130 clf = CheckingClassifier(
131 check_X=check_array, check_X_params={"accept_sparse": False}
132 )
133 clf.fit(X, y)
134 with pytest.raises(TypeError, match="Sparse data was passed"):
135 clf.fit(X_sparse, y)
136
137
138def test_checking_classifier_fit_params(iris):
139 # check the error raised when the number of samples is not the one expected
140 X, y = iris
141 clf = CheckingClassifier(expected_sample_weight=True)
142 sample_weight = np.ones(len(X) // 2)
143
144 msg = f"sample_weight.shape == ({len(X) // 2},), expected ({len(X)},)!"
145 with pytest.raises(ValueError) as exc:
146 clf.fit(X, y, sample_weight=sample_weight)
147 assert exc.value.args[0] == msg
148
149
150def test_checking_classifier_missing_fit_params(iris):
151 X, y = iris
152 clf = CheckingClassifier(expected_sample_weight=True)
153 err_msg = "Expected sample_weight to be passed"
154 with pytest.raises(AssertionError, match=err_msg):
155 clf.fit(X, y)
156
157
158@pytest.mark.parametrize(
159 "methods_to_check",
160 [["predict"], ["predict", "predict_proba"]],
161)
162@pytest.mark.parametrize(
163 "predict_method", ["predict", "predict_proba", "decision_function", "score"]
164)
165def test_checking_classifier_methods_to_check(iris, methods_to_check, predict_method):
166 # check that methods_to_check allows to bypass checks
167 X, y = iris
168
169 clf = CheckingClassifier(
170 check_X=sparse.issparse,
171 methods_to_check=methods_to_check,
172 )
173
174 clf.fit(X, y)
175 if predict_method in methods_to_check:
176 with pytest.raises(AssertionError):
177 getattr(clf, predict_method)(X)
178 else:
179 getattr(clf, predict_method)(X)
180
181
182@pytest.mark.parametrize(
183 "response_methods",
184 [
185 ["predict"],
186 ["predict", "predict_proba"],
187 ["predict", "decision_function"],
188 ["predict", "predict_proba", "decision_function"],
189 ],
190)
191def test_mock_estimator_on_off_prediction(iris, response_methods):
192 X, y = iris
193 estimator = _MockEstimatorOnOffPrediction(response_methods=response_methods)
194
195 estimator.fit(X, y)
196 assert hasattr(estimator, "classes_")
197 assert_array_equal(estimator.classes_, np.unique(y))
198
199 possible_responses = ["predict", "predict_proba", "decision_function"]
200 for response in possible_responses:
201 if response in response_methods:
202 assert hasattr(estimator, response)
203 assert getattr(estimator, response)(X) == response
204 else:
205 assert not hasattr(estimator, response)
206 