我正在尝试为一个涉及包含pipeline
作为其构造函数输入之一的估计器的自定义案例运行网格搜索。
class DefaultEstimator(BaseEstimator, TransformerMixin): def __init__(self, preprocessor, pipelines): self.pipelines = pipelines def fit(self, X, y=None): for idx, each_pipeline in enumerate(self.pipelines): each_pipeline.fit(X[idx], y) return self def transform(self, X): transformed_data = [] for idx, each_pipeline in enumerate(self.pipelines): transformed_data.append(each_pipeline.transform(X[idx])) return sp.hstack(transformed_data)
我的管道看起来像这样:
pipeline1 = trainer.create_pipeline(num_features=100)pipeline2 = trainer.create_pipeline(num_features=50)
复合管道看起来像这样:
aggregated_pipeline = Pipeline([('contextual', DefaultEstimator([pipeline1, pipeline2])), ('classifier', Pipeline([('clf', SVM(random_state=1234, probability=True)])) ])
输入数据有两列,每列分别对应一个管道(pipeline1
和 pipeline2
)。
对于clf
的grid_params
的键可以写成classifier__clf__C
,classifier__clf__gamma
等。
问题是:如何为GridSearchCV(...)
编写grid_params
,因为管道步骤之一不是管道对象,而是一个自定义估计器对象?
回答:
GridSearchCV
和Pipeline
使用估计器的set_params
方法来设置要测试的参数。因此,您需要在DefaultEstimator
中实现这个方法,并适当设置管道参数。在scikit-learn中,常见的做法是使用双下划线来分隔嵌套对象的参数,例如:
class DefaultEstimator: def set_params(self, **kwargs): for k, v in kwargs.items(): parts = k.split('__') if parts[0].startswith('pipeline'): pipe_num = int(parts[0].split('_')[1]) param_name = '__'.join(parts[1:]) self.pipelines[pipe_num].set_params(*{param_name: v}) else: # 其他逻辑
这样,您就可以使用诸如contextual__pipeline_1__num_features
这样的参数(contextual__
会被网格搜索自动去掉,因此无需处理)。