@@ -152,14 +152,21 @@ def fit(self, X, y, sample_weight=None):
152
152
153
153
stack_method = [self .stack_method ] * len (all_estimators )
154
154
155
- # Fit the base estimators on the whole training data. Those
156
- # base estimators will be used in transform, predict, and
157
- # predict_proba. They are exposed publicly.
158
- self .estimators_ = Parallel (n_jobs = self .n_jobs )(
159
- delayed (_fit_single_estimator )(clone (est ), X , y , sample_weight )
160
- for est in all_estimators
161
- if est != "drop"
162
- )
155
+ if self .cv == "prefit" :
156
+ self .estimators_ = []
157
+ for estimator in all_estimators :
158
+ if estimator != "drop" :
159
+ check_is_fitted (estimator )
160
+ self .estimators_ .append (estimator )
161
+ else :
162
+ # Fit the base estimators on the whole training data. Those
163
+ # base estimators will be used in transform, predict, and
164
+ # predict_proba. They are exposed publicly.
165
+ self .estimators_ = Parallel (n_jobs = self .n_jobs )(
166
+ delayed (_fit_single_estimator )(clone (est ), X , y , sample_weight )
167
+ for est in all_estimators
168
+ if est != "drop"
169
+ )
163
170
164
171
self .named_estimators_ = Bunch ()
165
172
est_fitted_idx = 0
@@ -173,37 +180,45 @@ def fit(self, X, y, sample_weight=None):
173
180
else :
174
181
self .named_estimators_ [name_est ] = "drop"
175
182
176
- # To train the meta-classifier using the most data as possible, we use
177
- # a cross-validation to obtain the output of the stacked estimators.
178
-
179
- # To ensure that the data provided to each estimator are the same, we
180
- # need to set the random state of the cv if there is one and we need to
181
- # take a copy.
182
- cv = check_cv (self .cv , y = y , classifier = is_classifier (self ))
183
- if hasattr (cv , "random_state" ) and cv .random_state is None :
184
- cv .random_state = np .random .RandomState ()
185
-
186
183
self .stack_method_ = [
187
184
self ._method_name (name , est , meth )
188
185
for name , est , meth in zip (names , all_estimators , stack_method )
189
186
]
190
- fit_params = (
191
- {"sample_weight" : sample_weight } if sample_weight is not None else None
192
- )
193
- predictions = Parallel (n_jobs = self .n_jobs )(
194
- delayed (cross_val_predict )(
195
- clone (est ),
196
- X ,
197
- y ,
198
- cv = deepcopy (cv ),
199
- method = meth ,
200
- n_jobs = self .n_jobs ,
201
- fit_params = fit_params ,
202
- verbose = self .verbose ,
187
+
188
+ if self .cv == "prefit" :
189
+ # Generate predictions from prefit models
190
+ predictions = [
191
+ getattr (estimator , predict_method )(X )
192
+ for estimator , predict_method in zip (all_estimators , self .stack_method_ )
193
+ if estimator != "drop"
194
+ ]
195
+ else :
196
+ # To train the meta-classifier using the most data as possible, we use
197
+ # a cross-validation to obtain the output of the stacked estimators.
198
+ # To ensure that the data provided to each estimator are the same,
199
+ # we need to set the random state of the cv if there is one and we
200
+ # need to take a copy.
201
+ cv = check_cv (self .cv , y = y , classifier = is_classifier (self ))
202
+ if hasattr (cv , "random_state" ) and cv .random_state is None :
203
+ cv .random_state = np .random .RandomState ()
204
+
205
+ fit_params = (
206
+ {"sample_weight" : sample_weight } if sample_weight is not None else None
207
+ )
208
+ predictions = Parallel (n_jobs = self .n_jobs )(
209
+ delayed (cross_val_predict )(
210
+ clone (est ),
211
+ X ,
212
+ y ,
213
+ cv = deepcopy (cv ),
214
+ method = meth ,
215
+ n_jobs = self .n_jobs ,
216
+ fit_params = fit_params ,
217
+ verbose = self .verbose ,
218
+ )
219
+ for est , meth in zip (all_estimators , self .stack_method_ )
220
+ if est != "drop"
203
221
)
204
- for est , meth in zip (all_estimators , self .stack_method_ )
205
- if est != "drop"
206
- )
207
222
208
223
# Only not None or not 'drop' estimators will be used in transform.
209
224
# Remove the None from the method as well.
@@ -306,15 +321,17 @@ class StackingClassifier(ClassifierMixin, _BaseStacking):
306
321
The default classifier is a
307
322
:class:`~sklearn.linear_model.LogisticRegression`.
308
323
309
- cv : int, cross-validation generator or an iterable , default=None
324
+ cv : int, cross-validation generator, iterable, or "prefit" , default=None
310
325
Determines the cross-validation splitting strategy used in
311
326
`cross_val_predict` to train `final_estimator`. Possible inputs for
312
327
cv are:
313
328
314
329
* None, to use the default 5-fold cross validation,
315
330
* integer, to specify the number of folds in a (Stratified) KFold,
316
331
* An object to be used as a cross-validation generator,
317
- * An iterable yielding train, test splits.
332
+ * An iterable yielding train, test splits,
333
+ * `"prefit"` to assume the `estimators` are prefit. In this case, the
334
+ estimators will not be refitted.
318
335
319
336
For integer/None inputs, if the estimator is a classifier and y is
320
337
either binary or multiclass,
@@ -326,6 +343,15 @@ class StackingClassifier(ClassifierMixin, _BaseStacking):
326
343
Refer :ref:`User Guide <cross_validation>` for the various
327
344
cross-validation strategies that can be used here.
328
345
346
+ If "prefit" is passed, it is assumed that all `estimators` have
347
+ been fitted already. The `final_estimator_` is trained on the `estimators`
348
+ predictions on the full training set and are **not** cross validated
349
+ predictions. Please note that if the models have been trained on the same
350
+ data to train the stacking model, there is a very high risk of overfitting.
351
+
352
+ .. versionadded:: 1.1
353
+ The 'prefit' option was added in 1.1
354
+
329
355
.. note::
330
356
A larger number of split will provide no benefits if the number
331
357
of training samples is large enough. Indeed, the training time
@@ -363,9 +389,10 @@ class StackingClassifier(ClassifierMixin, _BaseStacking):
363
389
Class labels.
364
390
365
391
estimators_ : list of estimators
366
- The elements of the estimators parameter, having been fitted on the
392
+ The elements of the ` estimators` parameter, having been fitted on the
367
393
training data. If an estimator has been set to `'drop'`, it
368
- will not appear in `estimators_`.
394
+ will not appear in `estimators_`. When `cv="prefit"`, `estimators_`
395
+ is set to `estimators` and is not fitted again.
369
396
370
397
named_estimators_ : :class:`~sklearn.utils.Bunch`
371
398
Attribute to access any fitted sub-estimators by name.
@@ -603,7 +630,7 @@ class StackingRegressor(RegressorMixin, _BaseStacking):
603
630
A regressor which will be used to combine the base estimators.
604
631
The default regressor is a :class:`~sklearn.linear_model.RidgeCV`.
605
632
606
- cv : int, cross-validation generator or an iterable , default=None
633
+ cv : int, cross-validation generator, iterable, or "prefit" , default=None
607
634
Determines the cross-validation splitting strategy used in
608
635
`cross_val_predict` to train `final_estimator`. Possible inputs for
609
636
cv are:
@@ -612,6 +639,7 @@ class StackingRegressor(RegressorMixin, _BaseStacking):
612
639
* integer, to specify the number of folds in a (Stratified) KFold,
613
640
* An object to be used as a cross-validation generator,
614
641
* An iterable yielding train, test splits.
642
+ * "prefit" to assume the `estimators` are prefit, and skip cross validation
615
643
616
644
For integer/None inputs, if the estimator is a classifier and y is
617
645
either binary or multiclass,
@@ -623,6 +651,15 @@ class StackingRegressor(RegressorMixin, _BaseStacking):
623
651
Refer :ref:`User Guide <cross_validation>` for the various
624
652
cross-validation strategies that can be used here.
625
653
654
+ If "prefit" is passed, it is assumed that all `estimators` have
655
+ been fitted already. The `final_estimator_` is trained on the `estimators`
656
+
2851
predictions on the full training set and are **not** cross validated
657
+ predictions. Please note that if the models have been trained on the same
658
+ data to train the stacking model, there is a very high risk of overfitting.
659
+
660
+ .. versionadded:: 1.1
661
+ The 'prefit' option was added in 1.1
662
+
626
663
.. note::
627
664
A larger number of split will provide no benefits if the number
628
665
of training samples is large enough. Indeed, the training time
@@ -646,9 +683,10 @@ class StackingRegressor(RegressorMixin, _BaseStacking):
646
683
Attributes
647
684
----------
648
685
estimators_ : list of estimator
649
- The elements of the estimators parameter, having been fitted on the
686
+ The elements of the ` estimators` parameter, having been fitted on the
650
687
training data. If an estimator has been set to `'drop'`, it
651
- will not appear in `estimators_`.
688
+ will not appear in `estimators_`. When `cv="prefit"`, `estimators_`
689
+ is set to `estimators` and is not fitted again.
652
690
653
691
named_estimators_ : :class:`~sklearn.utils.Bunch`
654
692
Attribute to access any fitted sub-estimators by name.
0 commit comments