如何在scikit-learn的管道中对变换参数进行网格搜索

我的目标是使用一个模型来选择最重要的变量,并使用另一个模型利用这些变量进行预测。在下面的示例中,我使用了两个RandomForestClassifier实例,但第二个模型可以是任何其他分类器。

随机森林有一个带有阈值参数的变换方法。我希望对不同的可能阈值参数进行网格搜索。

这是一个简化的代码片段:

# 变换对象和分类器
rf_filter = RandomForestClassifier(n_estimators=200, n_jobs=-1, random_state=42, oob_score=False)
clf = RandomForestClassifier(n_estimators=200, n_jobs=-1, random_state=42, oob_score=False)
pipe = Pipeline([("RFF", rf_filter), ("RF", clf)])
# 网格搜索参数
rf_n_estimators = [10, 20]
rff_transform = ["median", "mean"] # 搜索阈值参数
estimator = GridSearchCV(pipe, 
                         cv = 3, 
                         param_grid = dict(RF__n_estimators = rf_n_estimators, 
                                           RFF__threshold = rff_transform))
estimator.fit(X_train, y_train)

错误是ValueError: Invalid parameter threshold for estimator RandomForestClassifier

我以为这会奏效,因为文档中说:

如果为None且可用,则使用对象属性threshold。

我在网格搜索之前尝试设置阈值属性(rf_filter.threshold = "median"),它确实工作了;然而,我无法弄清楚如何对其进行网格搜索。

有没有办法迭代通常在分类器的变换方法中提供的不同参数?


回答:

按照您描述的方法,即使用两个不同的随机森林分类器进行特征选择和分类,并将它们组合到一个管道中,我遇到了相同的问题。

RandomForestClassifier类的实例没有名为threshold的属性。您确实可以手动添加一个,要么使用您描述的方式,要么使用

setattr(object, 'threshold', 'mean')

但主要问题似乎是get_params方法检查BaseEstimator的任何成员的有效属性的方式:

class BaseEstimator(object):
    """scikit-learn中所有估计器的基类
    注意事项
    -----
    所有估计器都应该在其__init__中以显式关键字参数的形式指定可以在类级别设置的所有参数(没有*args, **kwargs)。"""
    @classmethod
    def _get_param_names(cls):
        """获取估计器的参数名称"""
        try:
            # 获取构造函数或在任何弃用包装之前的原始构造函数
            init = getattr(cls.__init__, 'deprecated_original', cls.__init__)
            # 内省构造函数参数以查找模型参数
            # 以表示
            args, varargs, kw, default = inspect.getargspec(init)
            if not varargs is None:
                raise RuntimeError("scikit-learn估计器应始终"
                                   "在其__init__的签名中指定其参数"
                                   "(没有varargs)。"
                                   "%s不遵循此约定。"
                                   % (cls, ))
            # 移除'self'
            # XXX: 如果init是一个静态方法,这将失败,但
            # 谁会这样做呢?
            args.pop(0)
        except TypeError:
            # 没有显式的__init__
            args = []
        args.sort()
        return args

事实上,正如明确指定的,所有估计器都应该在其__init__中以显式关键字参数的形式指定可以在类级别设置的所有参数。

所以我尝试在__init__函数中将threshold指定为一个参数,并将其默认值设置为’mean’(这无论如何都是当前实现中的默认值)

    def __init__(self,
                 n_estimators=10,
                 criterion="gini",
                 max_depth=None,
                 min_samples_split=2,
                 min_samples_leaf=1,
                 max_features="auto",
                 bootstrap=True,
                 oob_score=False,
                 n_jobs=1,
                 random_state=None,
                 verbose=0,
                 min_density=None,
                 compute_importances=None,
                 threshold="mean"): # 添加这一行!

然后将此参数的值分配给类的参数。

    self.threshold = threshold # 在__INIT__函数中的某个地方添加这一行

当然,这意味着要修改RandomForestClassifier类(在/python2.7/site-packages/sklearn/ensemble/forest.py中),这可能不是最好的方法…但对我来说它有效!我现在能够对不同的阈值参数进行网格搜索(和交叉验证),从而选择不同数量的特征。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注