代码之家  ›  专栏  ›  技术社区  ›  user7721335

如何将两个估计器对象传递给sklearn的GridSearchCV,以便它们在每个步骤中具有相同的参数?

  •  3
  • user7721335  · 技术社区  · 6 年前

    我正在尝试使用SKlearn的GridSearchCV为我的估计器调整超参数。

    1. 在第一步中,估计量用于 SequentialFeatureSelection ,这是一个执行 wrapper based feature selection . 这意味着迭代添加新特征,并确定估计器性能最佳的特征。因此,序列特征选择方法需要我的估计器。这个库是经过编程的,因此可以很好地与SKlearn一起使用,所以我在GridSearchCV管道的第一步中集成了它,以将特征转换为所选的特征。

    2. 在第二步中,我想使用完全相同的分类器,使用完全相同的参数进行拟合,并预测结果。然而,对于参数网格,我只能将参数设置为传递给SequentialFeatureSelector的分类器,或者设置为“clf”中的参数,我不能保证它们总是相同的。

    3. 最后,通过选择的特征和选择的参数,我想在之前进行的测试集上进行预测。

    On the bottom of the page of the SFS library ,他们展示了如何将SFS与GridSearchCV结合使用,但用于选择特征的KNN算法和用于预测的KNN算法也使用了不同的参数。当我在traininf SFS和GridSearchCV之后检查自己时,参数从来都不一样,即使我使用 clf。克隆() 按照提议。这是我的代码:

    import sklearn.pipeline
    import sklearn.tree
    import sklearn.model_selection
    import mlxtend.feature_selection
    
    
    def sfs(x, y):
        x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(x, y, test_size=0.2, random_state=0)
    
        clf = sklearn.tree.DecisionTreeClassifier()
    
        param_grid = {
            "sfs__estimator__max_depth": [5]
        }
    
        sfs = mlxtend.feature_selection.SequentialFeatureSelector(clone_estimator=True,  # Clone like in Tutorial
                                                                  estimator=clf,
                                                                  k_features=10,
                                                                  forward=True,
                                                                  floating=False,
                                                                  scoring='accuracy',
                                                                  cv=3,
                                                                  n_jobs=1)
    
        pipe = sklearn.pipeline.Pipeline([('sfs', sfs), ("clf", clf)])
    
        gs = sklearn.model_selection.GridSearchCV(estimator=pipe,
                                                  param_grid=param_grid,
                                                  scoring='accuracy',
                                                  n_jobs=1,
                                                  cv=3,
                                                  refit=True)
    
        gs = gs.fit(x_train, y_train)
    
        # Both estimators should have depth 5!
        print("SFS Final Estimator Depth: " + str(gs.best_estimator_.named_steps.sfs.estimator.max_depth))
        print("CLF Final Estimator Depth: " + str(gs.best_estimator_._final_estimator.max_depth))
    
        # Evaluate...
        y_test_pred = gs.predict(x_test)
        # Accuracy etc...
    

    问题是,我如何确保在同一管道中始终设置相同的参数?

    谢谢

    1 回复  |  直到 6 年前
        1
  •  2
  •   user7721335 user7721335    6 年前

    我找到了一个解决方案,在这里我覆盖了SequentialFeatureSelector(SFS)类的一些方法,以便在转换后也使用其估计器进行预测。这是通过引入自定义SFS类“CSequentialFeatureSelector”来实现的,该类覆盖SFS中的以下方法:

    1. 在拟合(self,X,y)方法中,不仅执行正常拟合,还执行self。估计器是对转换后的数据进行拟合的,因此可以为SFS类实现predict和predict\u proba方法。

    2. 我为SFS类实现了predict and predict\u probba方法,该方法称为拟合自我的predict and predict\u probba方法。估计员。

    因此,我只剩下一个用于SFS和预测的估计量。

    以下是一些代码:

    import sklearn.pipeline
    import sklearn.tree
    import sklearn.model_selection
    import mlxtend.feature_selection
    
    
    class CSequentialFeatureSelector(mlxtend.feature_selection.SequentialFeatureSelector):
        def predict(self, X):
            X = self.transform(X)
            return self.estimator.predict(X)
    
        def predict_proba(self, X):
            X = self.transform(X)
            return self.estimator.predict_proba(X)
    
        def fit(self, X, y):
            self.fit_helper(X, y) # fit helper is the 'old' fit method, which I copied and renamed to fit_helper
            self.estimator.fit(self.transform(X), y)
            return self
    
    
    def sfs(x, y):
        x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(x, y, test_size=0.2, random_state=0)
    
        clf = sklearn.tree.DecisionTreeClassifier()
    
        param_grid = {
            "sfs__estimator__max_depth": [3, 4, 5]
        }
    
        sfs = mlxtend.feature_selection.SequentialFeatureSelector(clone_estimator=True,
                                                                  estimator=clf,
                                                                  k_features=10,
                                                                  forward=True,
                                                                  floating=False,
                                                                  scoring='accuracy',
                                                                  cv=3,
                                                                  n_jobs=1)
    
        # Now only one object in the pipeline (in fact this is not even needed anymore)
        pipe = sklearn.pipeline.Pipeline([('sfs', sfs)])
    
        gs = sklearn.model_selection.GridSearchCV(estimator=pipe,
                                                  param_grid=param_grid,
                                                  scoring='accuracy',
                                                  n_jobs=1,
                                                  cv=3,
                                                  refit=True)
    
        gs = gs.fit(x_train, y_train)
    
        print("SFS Final Estimator Depth: " + str(gs.best_estimator_.named_steps.sfs.estimator.max_depth))
    
        y_test_pred = gs.predict(x_test)
        # Evaluate performance of y_test_pred