Prompt48 commited on
Commit
b430ed5
·
verified ·
1 Parent(s): 1bb0e8c

Upload edit\Qwen3-TTS-test\.venv\Lib\site-packages\sklearn\ensemble\tests\test_voting.py with huggingface_hub

Browse files
edit//Qwen3-TTS-test//.venv//Lib//site-packages//sklearn//ensemble//tests//test_voting.py ADDED
@@ -0,0 +1,795 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Testing for the VotingClassifier and VotingRegressor"""
2
+
3
+ import re
4
+
5
+ import numpy as np
6
+ import pytest
7
+
8
+ from sklearn import config_context, datasets
9
+ from sklearn.base import BaseEstimator, ClassifierMixin, clone
10
+ from sklearn.calibration import CalibratedClassifierCV
11
+ from sklearn.datasets import make_multilabel_classification
12
+ from sklearn.dummy import DummyRegressor
13
+ from sklearn.ensemble import (
14
+ RandomForestClassifier,
15
+ RandomForestRegressor,
16
+ VotingClassifier,
17
+ VotingRegressor,
18
+ )
19
+ from sklearn.exceptions import NotFittedError
20
+ from sklearn.linear_model import LinearRegression, LogisticRegression
21
+ from sklearn.model_selection import GridSearchCV, cross_val_score, train_test_split
22
+ from sklearn.multiclass import OneVsRestClassifier
23
+ from sklearn.naive_bayes import GaussianNB
24
+ from sklearn.neighbors import KNeighborsClassifier
25
+ from sklearn.preprocessing import StandardScaler
26
+ from sklearn.svm import SVC
27
+ from sklearn.tests.metadata_routing_common import (
28
+ ConsumingClassifier,
29
+ ConsumingRegressor,
30
+ _Registry,
31
+ check_recorded_metadata,
32
+ )
33
+ from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
34
+ from sklearn.utils._testing import (
35
+ assert_almost_equal,
36
+ assert_array_almost_equal,
37
+ assert_array_equal,
38
+ )
39
+
40
+ # Load datasets
41
+ iris = datasets.load_iris()
42
+ X, y = iris.data[:, 1:3], iris.target
43
+ # Scaled to solve ConvergenceWarning throw by Logistic Regression
44
+ X_scaled = StandardScaler().fit_transform(X)
45
+
46
+ X_r, y_r = datasets.load_diabetes(return_X_y=True)
47
+
48
+
49
+ @pytest.mark.parametrize(
50
+ "params, err_msg",
51
+ [
52
+ (
53
+ {"estimators": []},
54
+ "Invalid 'estimators' attribute, 'estimators' should be a non-empty list",
55
+ ),
56
+ (
57
+ {"estimators": [LogisticRegression()]},
58
+ "Invalid 'estimators' attribute, 'estimators' should be a non-empty list",
59
+ ),
60
+ (
61
+ {"estimators": [(213, LogisticRegression())]},
62
+ "Invalid 'estimators' attribute, 'estimators' should be a non-empty list",
63
+ ),
64
+ (
65
+ {"estimators": [("lr", LogisticRegression())], "weights": [1, 2]},
66
+ "Number of `estimators` and weights must be equal",
67
+ ),
68
+ ],
69
+ )
70
+ def test_voting_classifier_estimator_init(params, err_msg):
71
+ ensemble = VotingClassifier(**params)
72
+ with pytest.raises(ValueError, match=err_msg):
73
+ ensemble.fit(X, y)
74
+
75
+
76
+ def test_predictproba_hardvoting():
77
+ eclf = VotingClassifier(
78
+ estimators=[("lr1", LogisticRegression()), ("lr2", LogisticRegression())],
79
+ voting="hard",
80
+ )
81
+
82
+ inner_msg = "predict_proba is not available when voting='hard'"
83
+ outer_msg = "'VotingClassifier' has no attribute 'predict_proba'"
84
+ with pytest.raises(AttributeError, match=outer_msg) as exec_info:
85
+ eclf.predict_proba
86
+ assert isinstance(exec_info.value.__cause__, AttributeError)
87
+ assert inner_msg in str(exec_info.value.__cause__)
88
+
89
+ assert not hasattr(eclf, "predict_proba")
90
+ eclf.fit(X_scaled, y)
91
+ assert not hasattr(eclf, "predict_proba")
92
+
93
+
94
+ def test_notfitted():
95
+ eclf = VotingClassifier(
96
+ estimators=[("lr1", LogisticRegression()), ("lr2", LogisticRegression())],
97
+ voting="soft",
98
+ )
99
+ ereg = VotingRegressor([("dr", DummyRegressor())])
100
+ msg = (
101
+ "This %s instance is not fitted yet. Call 'fit'"
102
+ " with appropriate arguments before using this estimator."
103
+ )
104
+ with pytest.raises(NotFittedError, match=msg % "VotingClassifier"):
105
+ eclf.predict(X)
106
+ with pytest.raises(NotFittedError, match=msg % "VotingClassifier"):
107
+ eclf.predict_proba(X)
108
+ with pytest.raises(NotFittedError, match=msg % "VotingClassifier"):
109
+ eclf.transform(X)
110
+ with pytest.raises(NotFittedError, match=msg % "VotingRegressor"):
111
+ ereg.predict(X_r)
112
+ with pytest.raises(NotFittedError, match=msg % "VotingRegressor"):
113
+ ereg.transform(X_r)
114
+
115
+
116
+ def test_majority_label_iris(global_random_seed):
117
+ """Check classification by majority label on dataset iris."""
118
+ clf1 = LogisticRegression(random_state=global_random_seed)
119
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
120
+ clf3 = GaussianNB()
121
+ eclf = VotingClassifier(
122
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)], voting="hard"
123
+ )
124
+ scores = cross_val_score(eclf, X, y, scoring="accuracy")
125
+
126
+ assert scores.mean() >= 0.9
127
+
128
+
129
+ def test_tie_situation():
130
+ """Check voting classifier selects smaller class label in tie situation."""
131
+ clf1 = LogisticRegression(random_state=123)
132
+ clf2 = RandomForestClassifier(random_state=123)
133
+ eclf = VotingClassifier(estimators=[("lr", clf1), ("rf", clf2)], voting="hard")
134
+ assert clf1.fit(X, y).predict(X)[52] == 2
135
+ assert clf2.fit(X, y).predict(X)[52] == 1
136
+ assert eclf.fit(X, y).predict(X)[52] == 1
137
+
138
+
139
+ def test_weights_iris(global_random_seed):
140
+ """Check classification by average probabilities on dataset iris."""
141
+ clf1 = LogisticRegression(random_state=global_random_seed)
142
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
143
+ clf3 = GaussianNB()
144
+ eclf = VotingClassifier(
145
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)],
146
+ voting="soft",
147
+ weights=[1, 2, 10],
148
+ )
149
+ scores = cross_val_score(eclf, X_scaled, y, scoring="accuracy")
150
+ assert scores.mean() >= 0.9
151
+
152
+
153
+ def test_weights_regressor():
154
+ """Check weighted average regression prediction on diabetes dataset."""
155
+ reg1 = DummyRegressor(strategy="mean")
156
+ reg2 = DummyRegressor(strategy="median")
157
+ reg3 = DummyRegressor(strategy="quantile", quantile=0.2)
158
+ ereg = VotingRegressor(
159
+ [("mean", reg1), ("median", reg2), ("quantile", reg3)], weights=[1, 2, 10]
160
+ )
161
+
162
+ X_r_train, X_r_test, y_r_train, y_r_test = train_test_split(
163
+ X_r, y_r, test_size=0.25
164
+ )
165
+
166
+ reg1_pred = reg1.fit(X_r_train, y_r_train).predict(X_r_test)
167
+ reg2_pred = reg2.fit(X_r_train, y_r_train).predict(X_r_test)
168
+ reg3_pred = reg3.fit(X_r_train, y_r_train).predict(X_r_test)
169
+ ereg_pred = ereg.fit(X_r_train, y_r_train).predict(X_r_test)
170
+
171
+ avg = np.average(
172
+ np.asarray([reg1_pred, reg2_pred, reg3_pred]), axis=0, weights=[1, 2, 10]
173
+ )
174
+ assert_almost_equal(ereg_pred, avg, decimal=2)
175
+
176
+ ereg_weights_none = VotingRegressor(
177
+ [("mean", reg1), ("median", reg2), ("quantile", reg3)], weights=None
178
+ )
179
+ ereg_weights_equal = VotingRegressor(
180
+ [("mean", reg1), ("median", reg2), ("quantile", reg3)], weights=[1, 1, 1]
181
+ )
182
+ ereg_weights_none.fit(X_r_train, y_r_train)
183
+ ereg_weights_equal.fit(X_r_train, y_r_train)
184
+ ereg_none_pred = ereg_weights_none.predict(X_r_test)
185
+ ereg_equal_pred = ereg_weights_equal.predict(X_r_test)
186
+ assert_almost_equal(ereg_none_pred, ereg_equal_pred, decimal=2)
187
+
188
+
189
+ def test_predict_on_toy_problem(global_random_seed):
190
+ """Manually check predicted class labels for toy dataset."""
191
+ clf1 = LogisticRegression(random_state=global_random_seed)
192
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
193
+ clf3 = GaussianNB()
194
+
195
+ X = np.array(
196
+ [[-1.1, -1.5], [-1.2, -1.4], [-3.4, -2.2], [1.1, 1.2], [2.1, 1.4], [3.1, 2.3]]
197
+ )
198
+
199
+ y = np.array([1, 1, 1, 2, 2, 2])
200
+
201
+ assert_array_equal(clf1.fit(X, y).predict(X), [1, 1, 1, 2, 2, 2])
202
+ assert_array_equal(clf2.fit(X, y).predict(X), [1, 1, 1, 2, 2, 2])
203
+ assert_array_equal(clf3.fit(X, y).predict(X), [1, 1, 1, 2, 2, 2])
204
+
205
+ eclf = VotingClassifier(
206
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)],
207
+ voting="hard",
208
+ weights=[1, 1, 1],
209
+ )
210
+ assert_array_equal(eclf.fit(X, y).predict(X), [1, 1, 1, 2, 2, 2])
211
+
212
+ eclf = VotingClassifier(
213
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)],
214
+ voting="soft",
215
+ weights=[1, 1, 1],
216
+ )
217
+ assert_array_equal(eclf.fit(X, y).predict(X), [1, 1, 1, 2, 2, 2])
218
+
219
+
220
+ def test_predict_proba_on_toy_problem():
221
+ """Calculate predicted probabilities on toy dataset."""
222
+ clf1 = LogisticRegression(random_state=123)
223
+ clf2 = RandomForestClassifier(random_state=123)
224
+ clf3 = GaussianNB()
225
+ X = np.array([[-1.1, -1.5], [-1.2, -1.4], [-3.4, -2.2], [1.1, 1.2]])
226
+ y = np.array([1, 1, 2, 2])
227
+
228
+ clf1_res = np.array(
229
+ [
230
+ [0.59790391, 0.40209609],
231
+ [0.57622162, 0.42377838],
232
+ [0.50728456, 0.49271544],
233
+ [0.40241774, 0.59758226],
234
+ ]
235
+ )
236
+
237
+ clf2_res = np.array([[0.8, 0.2], [0.8, 0.2], [0.2, 0.8], [0.3, 0.7]])
238
+
239
+ clf3_res = np.array(
240
+ [[0.9985082, 0.0014918], [0.99845843, 0.00154157], [0.0, 1.0], [0.0, 1.0]]
241
+ )
242
+
243
+ t00 = (2 * clf1_res[0][0] + clf2_res[0][0] + clf3_res[0][0]) / 4
244
+ t11 = (2 * clf1_res[1][1] + clf2_res[1][1] + clf3_res[1][1]) / 4
245
+ t21 = (2 * clf1_res[2][1] + clf2_res[2][1] + clf3_res[2][1]) / 4
246
+ t31 = (2 * clf1_res[3][1] + clf2_res[3][1] + clf3_res[3][1]) / 4
247
+
248
+ eclf = VotingClassifier(
249
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)],
250
+ voting="soft",
251
+ weights=[2, 1, 1],
252
+ )
253
+ eclf_res = eclf.fit(X, y).predict_proba(X)
254
+
255
+ assert_almost_equal(t00, eclf_res[0][0], decimal=1)
256
+ assert_almost_equal(t11, eclf_res[1][1], decimal=1)
257
+ assert_almost_equal(t21, eclf_res[2][1], decimal=1)
258
+ assert_almost_equal(t31, eclf_res[3][1], decimal=1)
259
+
260
+ inner_msg = "predict_proba is not available when voting='hard'"
261
+ outer_msg = "'VotingClassifier' has no attribute 'predict_proba'"
262
+ with pytest.raises(AttributeError, match=outer_msg) as exec_info:
263
+ eclf = VotingClassifier(
264
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)], voting="hard"
265
+ )
266
+ eclf.fit(X, y).predict_proba(X)
267
+
268
+ assert isinstance(exec_info.value.__cause__, AttributeError)
269
+ assert inner_msg in str(exec_info.value.__cause__)
270
+
271
+
272
+ def test_multilabel():
273
+ """Check if error is raised for multilabel classification."""
274
+ X, y = make_multilabel_classification(
275
+ n_classes=2, n_labels=1, allow_unlabeled=False, random_state=123
276
+ )
277
+ clf = OneVsRestClassifier(SVC(kernel="linear"))
278
+
279
+ eclf = VotingClassifier(estimators=[("ovr", clf)], voting="hard")
280
+
281
+ try:
282
+ eclf.fit(X, y)
283
+ except NotImplementedError:
284
+ return
285
+
286
+
287
+ def test_gridsearch():
288
+ """Check GridSearch support."""
289
+ clf1 = LogisticRegression(random_state=1)
290
+ clf2 = RandomForestClassifier(random_state=1, n_estimators=3)
291
+ clf3 = GaussianNB()
292
+ eclf = VotingClassifier(
293
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)], voting="soft"
294
+ )
295
+
296
+ params = {
297
+ "lr__C": [1.0, 100.0],
298
+ "voting": ["soft", "hard"],
299
+ "weights": [[0.5, 0.5, 0.5], [1.0, 0.5, 0.5]],
300
+ }
301
+
302
+ grid = GridSearchCV(estimator=eclf, param_grid=params, cv=2)
303
+ grid.fit(X_scaled, y)
304
+
305
+
306
+ def test_parallel_fit(global_random_seed):
307
+ """Check parallel backend of VotingClassifier on toy dataset."""
308
+ clf1 = LogisticRegression(random_state=global_random_seed)
309
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
310
+ clf3 = GaussianNB()
311
+ X = np.array([[-1.1, -1.5], [-1.2, -1.4], [-3.4, -2.2], [1.1, 1.2]])
312
+ y = np.array([1, 1, 2, 2])
313
+
314
+ eclf1 = VotingClassifier(
315
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)], voting="soft", n_jobs=1
316
+ ).fit(X, y)
317
+ eclf2 = VotingClassifier(
318
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)], voting="soft", n_jobs=2
319
+ ).fit(X, y)
320
+
321
+ assert_array_equal(eclf1.predict(X), eclf2.predict(X))
322
+ assert_array_almost_equal(eclf1.predict_proba(X), eclf2.predict_proba(X))
323
+
324
+
325
+ def test_sample_weight(global_random_seed):
326
+ """Tests sample_weight parameter of VotingClassifier"""
327
+ clf1 = LogisticRegression(random_state=global_random_seed)
328
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
329
+ clf3 = CalibratedClassifierCV(SVC(random_state=global_random_seed), ensemble=False)
330
+ eclf1 = VotingClassifier(
331
+ estimators=[("lr", clf1), ("rf", clf2), ("svc", clf3)], voting="soft"
332
+ ).fit(X_scaled, y, sample_weight=np.ones((len(y),)))
333
+ eclf2 = VotingClassifier(
334
+ estimators=[("lr", clf1), ("rf", clf2), ("svc", clf3)], voting="soft"
335
+ ).fit(X_scaled, y)
336
+ assert_array_equal(eclf1.predict(X_scaled), eclf2.predict(X_scaled))
337
+ assert_array_almost_equal(
338
+ eclf1.predict_proba(X_scaled), eclf2.predict_proba(X_scaled)
339
+ )
340
+ sample_weight = np.random.RandomState(global_random_seed).uniform(size=(len(y),))
341
+ eclf3 = VotingClassifier(estimators=[("lr", clf1)], voting="soft")
342
+ eclf3.fit(X_scaled, y, sample_weight=sample_weight)
343
+ clf1.fit(X_scaled, y, sample_weight)
344
+ assert_array_equal(eclf3.predict(X_scaled), clf1.predict(X_scaled))
345
+ assert_array_almost_equal(
346
+ eclf3.predict_proba(X_scaled), clf1.predict_proba(X_scaled)
347
+ )
348
+
349
+ # check that an error is raised and indicative if sample_weight is not
350
+ # supported.
351
+ clf4 = KNeighborsClassifier()
352
+ eclf3 = VotingClassifier(
353
+ estimators=[("lr", clf1), ("svc", clf3), ("knn", clf4)], voting="soft"
354
+ )
355
+ msg = "Underlying estimator KNeighborsClassifier does not support sample weights."
356
+ with pytest.raises(TypeError, match=msg):
357
+ eclf3.fit(X_scaled, y, sample_weight=sample_weight)
358
+
359
+ # check that _fit_single_estimator will raise the right error
360
+ # it should raise the original error if this is not linked to sample_weight
361
+ class ClassifierErrorFit(ClassifierMixin, BaseEstimator):
362
+ def fit(self, X_scaled, y, sample_weight):
363
+ raise TypeError("Error unrelated to sample_weight.")
364
+
365
+ clf = ClassifierErrorFit()
366
+ with pytest.raises(TypeError, match="Error unrelated to sample_weight"):
367
+ clf.fit(X_scaled, y, sample_weight=sample_weight)
368
+
369
+
370
+ def test_sample_weight_kwargs():
371
+ """Check that VotingClassifier passes sample_weight as kwargs"""
372
+
373
+ class MockClassifier(ClassifierMixin, BaseEstimator):
374
+ """Mock Classifier to check that sample_weight is received as kwargs"""
375
+
376
+ def fit(self, X, y, *args, **sample_weight):
377
+ assert "sample_weight" in sample_weight
378
+
379
+ clf = MockClassifier()
380
+ eclf = VotingClassifier(estimators=[("mock", clf)], voting="soft")
381
+
382
+ # Should not raise an error.
383
+ eclf.fit(X, y, sample_weight=np.ones((len(y),)))
384
+
385
+
386
+ def test_voting_classifier_set_params(global_random_seed):
387
+ # check equivalence in the output when setting underlying estimators
388
+ clf1 = LogisticRegression(random_state=global_random_seed)
389
+ clf2 = RandomForestClassifier(
390
+ n_estimators=10, random_state=global_random_seed, max_depth=None
391
+ )
392
+ clf3 = GaussianNB()
393
+
394
+ eclf1 = VotingClassifier(
395
+ [("lr", clf1), ("rf", clf2)], voting="soft", weights=[1, 2]
396
+ ).fit(X_scaled, y)
397
+ eclf2 = VotingClassifier(
398
+ [("lr", clf1), ("nb", clf3)], voting="soft", weights=[1, 2]
399
+ )
400
+ eclf2.set_params(nb=clf2).fit(X_scaled, y)
401
+
402
+ assert_array_equal(eclf1.predict(X_scaled), eclf2.predict(X_scaled))
403
+ assert_array_almost_equal(
404
+ eclf1.predict_proba(X_scaled), eclf2.predict_proba(X_scaled)
405
+ )
406
+ assert eclf2.estimators[0][1].get_params() == clf1.get_params()
407
+ assert eclf2.estimators[1][1].get_params() == clf2.get_params()
408
+
409
+
410
+ def test_set_estimator_drop():
411
+ # VotingClassifier set_params should be able to set estimators as drop
412
+ # Test predict
413
+ clf1 = LogisticRegression(random_state=123)
414
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=123)
415
+ clf3 = GaussianNB()
416
+ eclf1 = VotingClassifier(
417
+ estimators=[("lr", clf1), ("rf", clf2), ("nb", clf3)],
418
+ voting="hard",
419
+ weights=[1, 0, 0.5],
420
+ ).fit(X, y)
421
+
422
+ eclf2 = VotingClassifier(
423
+ estimators=[("lr", clf1), ("rf", clf2), ("nb", clf3)],
424
+ voting="hard",
425
+ weights=[1, 1, 0.5],
426
+ )
427
+ eclf2.set_params(rf="drop").fit(X, y)
428
+
429
+ assert_array_equal(eclf1.predict(X), eclf2.predict(X))
430
+
431
+ assert dict(eclf2.estimators)["rf"] == "drop"
432
+ assert len(eclf2.estimators_) == 2
433
+ assert all(
434
+ isinstance(est, (LogisticRegression, GaussianNB)) for est in eclf2.estimators_
435
+ )
436
+ assert eclf2.get_params()["rf"] == "drop"
437
+
438
+ eclf1.set_params(voting="soft").fit(X, y)
439
+ eclf2.set_params(voting="soft").fit(X, y)
440
+
441
+ assert_array_equal(eclf1.predict(X), eclf2.predict(X))
442
+ assert_array_almost_equal(eclf1.predict_proba(X), eclf2.predict_proba(X))
443
+ msg = "All estimators are dropped. At least one is required"
444
+ with pytest.raises(ValueError, match=msg):
445
+ eclf2.set_params(lr="drop", rf="drop", nb="drop").fit(X, y)
446
+
447
+ # Test soft voting transform
448
+ X1 = np.array([[1], [2]])
449
+ y1 = np.array([1, 2])
450
+ eclf1 = VotingClassifier(
451
+ estimators=[("rf", clf2), ("nb", clf3)],
452
+ voting="soft",
453
+ weights=[0, 0.5],
454
+ flatten_transform=False,
455
+ ).fit(X1, y1)
456
+
457
+ eclf2 = VotingClassifier(
458
+ estimators=[("rf", clf2), ("nb", clf3)],
459
+ voting="soft",
460
+ weights=[1, 0.5],
461
+ flatten_transform=False,
462
+ )
463
+ eclf2.set_params(rf="drop").fit(X1, y1)
464
+ assert_array_almost_equal(
465
+ eclf1.transform(X1),
466
+ np.array([[[0.7, 0.3], [0.3, 0.7]], [[1.0, 0.0], [0.0, 1.0]]]),
467
+ )
468
+ assert_array_almost_equal(eclf2.transform(X1), np.array([[[1.0, 0.0], [0.0, 1.0]]]))
469
+ eclf1.set_params(voting="hard")
470
+ eclf2.set_params(voting="hard")
471
+ assert_array_equal(eclf1.transform(X1), np.array([[0, 0], [1, 1]]))
472
+ assert_array_equal(eclf2.transform(X1), np.array([[0], [1]]))
473
+
474
+
475
+ def test_estimator_weights_format(global_random_seed):
476
+ # Test estimator weights inputs as list and array
477
+ clf1 = LogisticRegression(random_state=global_random_seed)
478
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
479
+ eclf1 = VotingClassifier(
480
+ estimators=[("lr", clf1), ("rf", clf2)], weights=[1, 2], voting="soft"
481
+ )
482
+ eclf2 = VotingClassifier(
483
+ estimators=[("lr", clf1), ("rf", clf2)], weights=np.array((1, 2)), voting="soft"
484
+ )
485
+ eclf1.fit(X_scaled, y)
486
+ eclf2.fit(X_scaled, y)
487
+ assert_array_almost_equal(
488
+ eclf1.predict_proba(X_scaled), eclf2.predict_proba(X_scaled)
489
+ )
490
+
491
+
492
+ def test_transform(global_random_seed):
493
+ """Check transform method of VotingClassifier on toy dataset."""
494
+ clf1 = LogisticRegression(random_state=global_random_seed)
495
+ clf2 = RandomForestClassifier(n_estimators=10, random_state=global_random_seed)
496
+ clf3 = GaussianNB()
497
+ X = np.array([[-1.1, -1.5], [-1.2, -1.4], [-3.4, -2.2], [1.1, 1.2]])
498
+ y = np.array([1, 1, 2, 2])
499
+
500
+ eclf1 = VotingClassifier(
501
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)], voting="soft"
502
+ ).fit(X, y)
503
+ eclf2 = VotingClassifier(
504
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)],
505
+ voting="soft",
506
+ flatten_transform=True,
507
+ ).fit(X, y)
508
+ eclf3 = VotingClassifier(
509
+ estimators=[("lr", clf1), ("rf", clf2), ("gnb", clf3)],
510
+ voting="soft",
511
+ flatten_transform=False,
512
+ ).fit(X, y)
513
+
514
+ assert_array_equal(eclf1.transform(X).shape, (4, 6))
515
+ assert_array_equal(eclf2.transform(X).shape, (4, 6))
516
+ assert_array_equal(eclf3.transform(X).shape, (3, 4, 2))
517
+ assert_array_almost_equal(eclf1.transform(X), eclf2.transform(X))
518
+ assert_array_almost_equal(
519
+ eclf3.transform(X).swapaxes(0, 1).reshape((4, 6)), eclf2.transform(X)
520
+ )
521
+
522
+
523
+ @pytest.mark.parametrize(
524
+ "X, y, voter",
525
+ [
526
+ (
527
+ X,
528
+ y,
529
+ VotingClassifier(
530
+ [
531
+ ("lr", LogisticRegression()),
532
+ ("rf", RandomForestClassifier(n_estimators=5)),
533
+ ]
534
+ ),
535
+ ),
536
+ (
537
+ X_r,
538
+ y_r,
539
+ VotingRegressor(
540
+ [
541
+ ("lr", LinearRegression()),
542
+ ("rf", RandomForestRegressor(n_estimators=5)),
543
+ ]
544
+ ),
545
+ ),
546
+ ],
547
+ )
548
+ def test_none_estimator_with_weights(X, y, voter):
549
+ # check that an estimator can be set to 'drop' and passing some weight
550
+ # regression test for
551
+ # https://github.com/scikit-learn/scikit-learn/issues/13777
552
+ voter = clone(voter)
553
+ # Scaled to solve ConvergenceWarning throw by Logistic Regression
554
+ X_scaled = StandardScaler().fit_transform(X)
555
+ voter.fit(X_scaled, y, sample_weight=np.ones(y.shape))
556
+ voter.set_params(lr="drop")
557
+ voter.fit(X_scaled, y, sample_weight=np.ones(y.shape))
558
+ y_pred = voter.predict(X_scaled)
559
+ assert y_pred.shape == y.shape
560
+
561
+
562
+ @pytest.mark.parametrize(
563
+ "est",
564
+ [
565
+ VotingRegressor(
566
+ estimators=[
567
+ ("lr", LinearRegression()),
568
+ ("tree", DecisionTreeRegressor(random_state=0)),
569
+ ]
570
+ ),
571
+ VotingClassifier(
572
+ estimators=[
573
+ ("lr", LogisticRegression(random_state=0)),
574
+ ("tree", DecisionTreeClassifier(random_state=0)),
575
+ ]
576
+ ),
577
+ ],
578
+ ids=["VotingRegressor", "VotingClassifier"],
579
+ )
580
+ def test_n_features_in(est):
581
+ est = clone(est)
582
+ X = [[1, 2], [3, 4], [5, 6]]
583
+ y = [0, 1, 2]
584
+
585
+ assert not hasattr(est, "n_features_in_")
586
+ est.fit(X, y)
587
+ assert est.n_features_in_ == 2
588
+
589
+
590
+ @pytest.mark.parametrize(
591
+ "estimator",
592
+ [
593
+ VotingRegressor(
594
+ estimators=[
595
+ ("lr", LinearRegression()),
596
+ ("rf", RandomForestRegressor(random_state=123)),
597
+ ],
598
+ verbose=True,
599
+ ),
600
+ VotingClassifier(
601
+ estimators=[
602
+ ("lr", LogisticRegression(random_state=123)),
603
+ ("rf", RandomForestClassifier(random_state=123)),
604
+ ],
605
+ verbose=True,
606
+ ),
607
+ ],
608
+ )
609
+ def test_voting_verbose(estimator, capsys):
610
+ X = np.array([[-1.1, -1.5], [-1.2, -1.4], [-3.4, -2.2], [1.1, 1.2]])
611
+ y = np.array([1, 1, 2, 2])
612
+
613
+ pattern = (
614
+ r"\[Voting\].*\(1 of 2\) Processing lr, total=.*\n"
615
+ r"\[Voting\].*\(2 of 2\) Processing rf, total=.*\n$"
616
+ )
617
+ clone(estimator).fit(X, y)
618
+ assert re.match(pattern, capsys.readouterr()[0])
619
+
620
+
621
+ def test_get_features_names_out_regressor():
622
+ """Check get_feature_names_out output for regressor."""
623
+
624
+ X = [[1, 2], [3, 4], [5, 6]]
625
+ y = [0, 1, 2]
626
+
627
+ voting = VotingRegressor(
628
+ estimators=[
629
+ ("lr", LinearRegression()),
630
+ ("tree", DecisionTreeRegressor(random_state=0)),
631
+ ("ignore", "drop"),
632
+ ]
633
+ )
634
+ voting.fit(X, y)
635
+
636
+ names_out = voting.get_feature_names_out()
637
+ expected_names = ["votingregressor_lr", "votingregressor_tree"]
638
+ assert_array_equal(names_out, expected_names)
639
+
640
+
641
+ @pytest.mark.parametrize(
642
+ "kwargs, expected_names",
643
+ [
644
+ (
645
+ {"voting": "soft", "flatten_transform": True},
646
+ [
647
+ "votingclassifier_lr0",
648
+ "votingclassifier_lr1",
649
+ "votingclassifier_lr2",
650
+ "votingclassifier_tree0",
651
+ "votingclassifier_tree1",
652
+ "votingclassifier_tree2",
653
+ ],
654
+ ),
655
+ ({"voting": "hard"}, ["votingclassifier_lr", "votingclassifier_tree"]),
656
+ ],
657
+ )
658
+ def test_get_features_names_out_classifier(kwargs, expected_names):
659
+ """Check get_feature_names_out for classifier for different settings."""
660
+ X = [[1, 2], [3, 4], [5, 6], [1, 1.2]]
661
+ y = [0, 1, 2, 0]
662
+
663
+ voting = VotingClassifier(
664
+ estimators=[
665
+ ("lr", LogisticRegression(random_state=0)),
666
+ ("tree", DecisionTreeClassifier(random_state=0)),
667
+ ],
668
+ **kwargs,
669
+ )
670
+ voting.fit(X, y)
671
+ X_trans = voting.transform(X)
672
+ names_out = voting.get_feature_names_out()
673
+
674
+ assert X_trans.shape[1] == len(expected_names)
675
+ assert_array_equal(names_out, expected_names)
676
+
677
+
678
+ def test_get_features_names_out_classifier_error():
679
+ """Check that error is raised when voting="soft" and flatten_transform=False."""
680
+ X = [[1, 2], [3, 4], [5, 6]]
681
+ y = [0, 1, 2]
682
+
683
+ voting = VotingClassifier(
684
+ estimators=[
685
+ ("lr", LogisticRegression(random_state=0)),
686
+ ("tree", DecisionTreeClassifier(random_state=0)),
687
+ ],
688
+ voting="soft",
689
+ flatten_transform=False,
690
+ )
691
+ voting.fit(X, y)
692
+
693
+ msg = (
694
+ "get_feature_names_out is not supported when `voting='soft'` and "
695
+ "`flatten_transform=False`"
696
+ )
697
+ with pytest.raises(ValueError, match=msg):
698
+ voting.get_feature_names_out()
699
+
700
+
701
+ # Metadata Routing Tests
702
+ # ======================
703
+
704
+
705
+ @pytest.mark.parametrize(
706
+ "Estimator, Child",
707
+ [(VotingClassifier, ConsumingClassifier), (VotingRegressor, ConsumingRegressor)],
708
+ )
709
+ def test_routing_passed_metadata_not_supported(Estimator, Child):
710
+ """Test that the right error message is raised when metadata is passed while
711
+ not supported when `enable_metadata_routing=False`."""
712
+
713
+ X = np.array([[0, 1], [2, 2], [4, 6]])
714
+ y = [1, 2, 3]
715
+
716
+ with pytest.raises(
717
+ ValueError, match="is only supported if enable_metadata_routing=True"
718
+ ):
719
+ Estimator(["clf", Child()]).fit(X, y, sample_weight=[1, 1, 1], metadata="a")
720
+
721
+
722
+ @pytest.mark.parametrize(
723
+ "Estimator, Child",
724
+ [(VotingClassifier, ConsumingClassifier), (VotingRegressor, ConsumingRegressor)],
725
+ )
726
+ @config_context(enable_metadata_routing=True)
727
+ def test_get_metadata_routing_without_fit(Estimator, Child):
728
+ # Test that metadata_routing() doesn't raise when called before fit.
729
+ est = Estimator([("sub_est", Child())])
730
+ est.get_metadata_routing()
731
+
732
+
733
+ @pytest.mark.parametrize(
734
+ "Estimator, Child",
735
+ [(VotingClassifier, ConsumingClassifier), (VotingRegressor, ConsumingRegressor)],
736
+ )
737
+ @pytest.mark.parametrize("prop", ["sample_weight", "metadata"])
738
+ @config_context(enable_metadata_routing=True)
739
+ def test_metadata_routing_for_voting_estimators(Estimator, Child, prop):
740
+ """Test that metadata is routed correctly for Voting*."""
741
+ X = np.array([[0, 1], [2, 2], [4, 6]])
742
+ y = [1, 2, 3]
743
+ sample_weight, metadata = [1, 1, 1], "a"
744
+
745
+ est = Estimator(
746
+ [
747
+ (
748
+ "sub_est1",
749
+ Child(registry=_Registry()).set_fit_request(**{prop: True}),
750
+ ),
751
+ (
752
+ "sub_est2",
753
+ Child(registry=_Registry()).set_fit_request(**{prop: True}),
754
+ ),
755
+ ]
756
+ )
757
+
758
+ est.fit(X, y, **{prop: sample_weight if prop == "sample_weight" else metadata})
759
+
760
+ for estimator in est.estimators:
761
+ if prop == "sample_weight":
762
+ kwargs = {prop: sample_weight}
763
+ else:
764
+ kwargs = {prop: metadata}
765
+ # access sub-estimator in (name, est) with estimator[1]
766
+ registry = estimator[1].registry
767
+ assert len(registry)
768
+ for sub_est in registry:
769
+ check_recorded_metadata(obj=sub_est, method="fit", parent="fit", **kwargs)
770
+
771
+
772
+ @pytest.mark.parametrize(
773
+ "Estimator, Child",
774
+ [(VotingClassifier, ConsumingClassifier), (VotingRegressor, ConsumingRegressor)],
775
+ )
776
+ @config_context(enable_metadata_routing=True)
777
+ def test_metadata_routing_error_for_voting_estimators(Estimator, Child):
778
+ """Test that the right error is raised when metadata is not requested."""
779
+ X = np.array([[0, 1], [2, 2], [4, 6]])
780
+ y = [1, 2, 3]
781
+ sample_weight, metadata = [1, 1, 1], "a"
782
+
783
+ est = Estimator([("sub_est", Child())])
784
+
785
+ error_message = (
786
+ "[sample_weight, metadata] are passed but are not explicitly set as requested"
787
+ f" or not requested for {Child.__name__}.fit"
788
+ )
789
+
790
+ with pytest.raises(ValueError, match=re.escape(error_message)):
791
+ est.fit(X, y, sample_weight=sample_weight, metadata=metadata)
792
+
793
+
794
+ # End of Metadata Routing Tests
795
+ # =============================