@@ -63,7 +63,7 @@ class Pipeline(pipeline.Pipeline):
63
63
64
64
Attributes
65
65
----------
66
- named_steps : bunch object, a dictionary with attribute access
66
+ named_steps : :class:`~sklearn.utils.Bunch`
67
67
Read-only attribute to access any step parameter by user given name.
68
68
Keys are step names and values are steps parameters.
69
69
@@ -179,7 +179,7 @@ def _iter(self, with_final=True, filter_passthrough=True, filter_resample=True):
179
179
180
180
# Estimator interface
181
181
182
- def _fit (self , X , y = None , ** fit_params ):
182
+ def _fit (self , X , y = None , ** fit_params_steps ):
183
183
self .steps = list (self .steps )
184
184
self ._validate_steps ()
185
185
# Setup the memory
@@ -188,18 +188,6 @@ def _fit(self, X, y=None, **fit_params):
188
188
fit_transform_one_cached = memory .cache (pipeline ._fit_transform_one )
189
189
fit_resample_one_cached = memory .cache (_fit_resample_one )
190
190
191
- fit_params_steps = {name : {} for name , step in self .steps if step is not None }
192
- for pname , pval in fit_params .items ():
193
- if "__" not in pname :
194
- raise ValueError (
195
- f"Pipeline.fit does not accept the { pname } parameter. "
196
- "You can pass parameters to specific steps of your "
197
- "pipeline using the stepname__parameter format, e.g. "
198
- "`Pipeline.fit(X, y, logisticregression__sample_weight"
199
- "=sample_weight)`."
200
- )
201
- step , param = pname .split ("__" , 1 )
202
- fit_params_steps [step ][param ] = pval
203
191
for (step_idx , name , transformer ) in self ._iter (
204
192
with_final = False , filter_passthrough = False , filter_resample = False
205
193
):
@@ -241,9 +229,7 @@ def _fit(self, X, y=None, **fit_params):
241
229
# transformer. This is necessary when loading the transformer
242
230
# from the cache.
243
231
self .steps [step_idx ] = (name , fitted_transformer )
244
- if self ._final_estimator == "passthrough" :
245
- return X , y , {}
246
- return X , y , fit_params_steps [self .steps [- 1 ][0 ]]
232
+ return X , y
247
233
248
234
def fit (self , X , y = None , ** fit_params ):
249
235
"""Fit the model.
@@ -272,10 +258,12 @@ def fit(self, X, y=None, **fit_params):
272
258
self : Pipeline
273
259
This estimator.
274
260
"""
275
- Xt , yt , fit_params = self ._fit (X , y , ** fit_params )
261
+ fit_params_steps = self ._check_fit_params (** fit_params )
262
+ Xt , yt = self ._fit (X , y , ** fit_params_steps )
276
263
with _print_elapsed_time ("Pipeline" , self ._log_message (len (self .steps ) - 1 )):
277
264
if self ._final_estimator != "passthrough" :
278
- self ._final_estimator .fit (Xt , yt , ** fit_params )
265
+ fit_params_last_step = fit_params_steps [self .steps [- 1 ][0 ]]
266
+ self ._final_estimator .fit (Xt , yt , ** fit_params_last_step )
279
267
return self
280
268
281
269
def fit_transform (self , X , y = None , ** fit_params ):
@@ -305,15 +293,18 @@ def fit_transform(self, X, y=None, **fit_params):
305
293
Xt : array-like of shape (n_samples, n_transformed_features)
306
294
Transformed samples.
307
295
"""
296
+ fit_params_steps = self ._check_fit_params (** fit_params )
297
+ Xt , yt = self ._fit (X , y , ** fit_params_steps )
298
+
308
299
last_step = self ._final_estimator
309
- Xt , yt , fit_params = self ._fit (X , y , ** fit_params )
310
300
with _print_elapsed_time ("Pipeline" , self ._log_message (len (self .steps ) - 1 )):
311
301
if last_step == "passthrough" :
312
302
return Xt
313
- elif hasattr (last_step , "fit_transform" ):
314
- return last_step .fit_transform (Xt , yt , ** fit_params )
303
+ fit_params_last_step = fit_params_steps [self .steps [- 1 ][0 ]]
304
+ if hasattr (last_step , "fit_transform" ):
305
+ return last_step .fit_transform (Xt , yt , ** fit_params_last_step )
315
306
else :
316
- return last_step .fit (Xt , yt , ** fit_params ).transform (Xt )
307
+ return last_step .fit (Xt , yt , ** fit_params_last_step ).transform (Xt )
317
308
318
309
def fit_resample (self , X , y = None , ** fit_params ):
319
310
"""Fit the model and sample with the final estimator.
@@ -345,13 +336,15 @@ def fit_resample(self, X, y=None, **fit_params):
345
336
yt : array-like of shape (n_samples, n_transformed_features)
346
337
Transformed target.
347
338
"""
339
+ fit_params_steps = self ._check_fit_params (** fit_params )
340
+ Xt , yt = self ._fit (X , y , ** fit_params_steps )
348
341
last_step = self ._final_estimator
349
- Xt , yt , fit_params = self ._fit (X , y , ** fit_params )
350
342
with _print_elapsed_time ("Pipeline" , self ._log_message (len (self .steps ) - 1 )):
351
343
if last_step == "passthrough" :
352
344
return Xt
353
- elif hasattr (last_step , "fit_resample" ):
354
- return last_step .fit_resample (Xt , yt , ** fit_params )
345
+ fit_params_last_step = fit_params_steps [self .steps [- 1 ][0 ]]
346
+ if hasattr (last_step , "fit_resample" ):
347
+ return last_step .fit_resample (Xt , yt , ** fit_params_last_step )
355
348
356
349
@if_delegate_has_method (delegate = "_final_estimator" )
357
350
def fit_predict (self , X , y = None , ** fit_params ):
@@ -381,9 +374,12 @@ def fit_predict(self, X, y=None, **fit_params):
381
374
y_pred : ndarray of shape (n_samples,)
382
375
The predicted target.
383
376
"""
384
- Xt , yt , fit_params = self ._fit (X , y , ** fit_params )
377
+ fit_params_steps = self ._check_fit_params (** fit_params )
378
+ Xt , yt = self ._fit (X , y , ** fit_params_steps )
379
+
380
+ fit_params_last_step = fit_params_steps [self .steps [- 1 ][0 ]]
385
381
with _print_elapsed_time ("Pipeline" , self ._log_message (len (self .steps ) - 1 )):
386
- y_pred = self .steps [- 1 ][- 1 ].fit_predict (Xt , yt , ** fit_params )
382
+ y_pred = self .steps [- 1 ][- 1 ].fit_predict (Xt , yt , ** fit_params_last_step )
387
383
return y_pred
388
384
389
385
@@ -394,7 +390,7 @@ def _fit_resample_one(sampler, X, y, message_clsname="", message=None, **fit_par
394
390
return X_res , y_res , sampler
395
391
396
392
397
- def make_pipeline (* steps , ** kwargs ):
393
+ def make_pipeline (* steps , memory = None , verbose = False ):
398
394
"""Construct a Pipeline from the given estimators.
399
395
400
396
This is a shorthand for the Pipeline constructor; it does not require, and
@@ -438,8 +434,4 @@ def make_pipeline(*steps, **kwargs):
438
434
Pipeline(steps=[('standardscaler', StandardScaler()),
439
435
('gaussiannb', GaussianNB())])
440
436
"""
441
- memory = kwargs .pop ("memory" , None )
442
- verbose = kwargs .pop ("verbose" , False )
443
- if kwargs :
444
- raise TypeError (f'Unknown keyword arguments: "{ list (kwargs .keys ())[0 ]} "' )
445
437
return Pipeline (pipeline ._name_estimators (steps ), memory = memory , verbose = verbose )
0 commit comments