我的目标是使用一个模型来选择最重要的变量,并使用另一个模型利用这些变量进行预测。在下面的示例中,我使用了两个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中),这可能不是最好的方法…但对我来说它有效!我现在能够对不同的阈值参数进行网格搜索(和交叉验证),从而选择不同数量的特征。