如何在scikit learn中向管道对象的单个部分传递参数?

22

我需要向我的RandomForestClassifier传递一个sample_weight参数,方法如下:

X = np.array([[2.0, 2.0, 1.0, 0.0, 1.0, 3.0, 3.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 5.0, 3.0,
        2.0, '0'],
       [15.0, 2.0, 5.0, 5.0, 0.466666666667, 4.0, 3.0, 2.0, 0.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
        7.0, 14.0, 2.0, '0'],
       [3.0, 4.0, 3.0, 1.0, 1.33333333333, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
        9.0, 8.0, 2.0, '0'],
       [3.0, 2.0, 3.0, 0.0, 0.666666666667, 2.0, 2.0, 1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
        5.0, 3.0, 1.0, '0']], dtype=object)

y = np.array([ 0.,  0.,  1.,  0.])

m = sklearn.ensemble.RandomForestClassifier(
        random_state=0, 
        oob_score=True, 
        n_estimators=100,
        min_samples_leaf=5, 
        max_depth=10)

m.fit(X, y, sample_weight=np.array([3,4,2,3]))

以上代码运行完美无误。接下来,我尝试将其放入管道对象中,使用管道对象而不仅限于随机森林:

m = sklearn.pipeline.Pipeline([
    ('feature_selection', sklearn.feature_selection.SelectKBest(
        score_func=sklearn.feature_selection.f_regression,
        k=25)),
    ('model', sklearn.ensemble.RandomForestClassifier(
        random_state=0, 
        oob_score=True, 
        n_estimators=500,
        min_samples_leaf=5, 
        max_depth=10))])

m.fit(X, y, sample_weight=np.array([3,4,2,3]))

现在这个问题出现在fit方法中,报错信息为"ValueError: need more than 1 value to unpack"。

ValueError                                Traceback (most recent call last)
<ipython-input-212-c4299f5b3008> in <module>()
     25         max_depth=10))])
     26 
---> 27 m.fit(X, y, sample_weights=np.array([3,4,2,3]))

/usr/local/lib/python2.7/dist-packages/sklearn/pipeline.pyc in fit(self, X, y, **fit_params)
    128         data, then fit the transformed data using the final estimator.
    129         """
--> 130         Xt, fit_params = self._pre_transform(X, y, **fit_params)
    131         self.steps[-1][-1].fit(Xt, y, **fit_params)
    132         return self

/usr/local/lib/python2.7/dist-packages/sklearn/pipeline.pyc in _pre_transform(self, X, y, **fit_params)
    113         fit_params_steps = dict((step, {}) for step, _ in self.steps)
    114         for pname, pval in six.iteritems(fit_params):
--> 115             step, param = pname.split('__', 1)
    116             fit_params_steps[step][param] = pval
    117         Xt = X

ValueError: need more than 1 value to unpack

我正在使用sklearn版本0.14
我认为问题在于管道中的F选择步骤没有接受样本权重的参数。我该如何在运行"fit"时将此参数传递给管道中的一个步骤?谢谢。


你的第二个代码示例中,m 是如何定义的?general_pipeline 有什么用途(它被定义了但似乎从未被使用)?此外,如果您能提供一些数据将会很有帮助。 - Cleb
抱歉,那是一个复制粘贴错误。 - makansij
1
好的,您能展示一下您的输入数据吗? - Cleb
我提供了更多的信息,希望这已经足够重现错误。如果还不清楚,请告诉我。这是比较紧急的!谢谢。 - makansij
为什么X是一个对象数组,每行的最后一项都是一个字符串? - ali_m
显示剩余2条评论
3个回答

32

文档中的描述:

管道(Pipeline)的目的是组装几个步骤,这些步骤可以一起进行交叉验证,同时设置不同的参数。为此,它允许使用各个步骤的名称和用“__”分隔的参数名称来设置各个步骤的参数,如下面的示例所示。

因此,您可以在要传递给“model”步骤的任何拟合参数 kwargs 前面插入 model__ 即可:

m.fit(X, y, model__sample_weight=np.array([3,4,2,3]))

1
你稍微快了一点。第二行确实是推荐的,看起来是这样的。你也可以查看此链接:https://sourceforge.net/p/scikit-learn/mailman/message/30266127/。 - Cleb
嗯,这对我不起作用,并且会给出相同的错误? - makansij
它在我的情况下运行得非常好(两种情况下都返回[0, 0, 0, 0]m.predict(X))。 - Cleb
2
@Sother:你确定使用两个下划线而不是一个吗?如果只使用一个下划线,确实会出现相同的错误。我正在使用0.17版本;你可能需要更新一下... - Cleb
直到找到这个答案,才发现之前有一些误导我去使用 pipeline.fit(X_train, y_train, fit_params={'sample_weight': sample_weight})。谢谢。 - Mithril

5
您也可以使用方法 set_params 并附加步骤名称来设置参数。
m = sklearn.pipeline.Pipeline([
    ('feature_selection', sklearn.feature_selection.SelectKBest(
        score_func=sklearn.feature_selection.f_regression,
        k=25)),
    ('model', sklearn.ensemble.RandomForestClassifier(
        random_state=0, 
        oob_score=True, 
        n_estimators=500,
        min_samples_leaf=5, 
        max_depth=10))])

m.set_params(model__sample_weight=np.array([3,4,2,3]))

1
这不正确。set_params 用于数据无关的超参数(例如 max_depth)。sample_weight 是数据相关的,也就是说,对于传递给 fit 的每个不同的 X,它都会有所不同。因此,在 fit() 中需要像 @ali_m 的答案中那样传递 sample_weight: https://dev59.com/6lsV5IYBdhLWcg3w6yYh#35634198 - Nick Crews

2
希望我能在@rovyko的帖子上留下评论,而不是单独回答,但我还没有足够的stackoverflow声望来留下评论,所以我在这里回答。您不能使用:Pipeline.set_params(model__sample_weight=np.array([3,4,2,3])来设置RandomForestClassifier.fit()方法的参数。正如代码(此处)中指出的那样,Pipeline.set_params()仅用于Pipeline中各个步骤的初始化参数。 RandomForestClassifier没有名为sample_weight的初始化参数(请参见其__init __()方法)。实际上,sample_weightRandomForestClassifierfit()方法的输入参数,因此只能通过由@ali_m正确标记的答案中提供的方法进行设置,即:m.fit(X, y, model__sample_weight=np.array([3,4,2,3]))

1
如果您认为有错误,请请求回答的编辑。提交编辑并我将接受编辑。 - rovyko
我尝试使用我的流程(标准化后跟随一个正则化的逻辑回归分类器),使用mypipeline.fit(X_train, y_train, classifier__C=0.5)。但是它给了我这个错误:LogisticRegression.fit()得到了一个意外的关键字参数'C'。 - skan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接