如何在python sklearn中正确使用featureUnion数值和文本功能

时间:2017-12-11 01:21:56

标签: python scikit-learn

我试图在sklearn管道中第一次使用featureunion来组合数字(2列)和文本特征(1列)以进行多类分类。

from sklearn.preprocessing import FunctionTransformer
from sklearn.pipeline import Pipeline
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import FeatureUnion

get_text_data = FunctionTransformer(lambda x: x['text'], validate=False)
get_numeric_data = FunctionTransformer(lambda x: x[['num1','num2']], validate=False)

process_and_join_features = FeatureUnion(
         [
            ('numeric_features', Pipeline([
                ('selector', get_numeric_data),
                ('clf', OneVsRestClassifier(LogisticRegression()))
            ])),
             ('text_features', Pipeline([
                ('selector', get_text_data),
                ('vec', CountVectorizer()),
                ('clf', OneVsRestClassifier(LogisticRegression()))
            ]))
         ]
    )

在此代码'文字'是文本列和' num1',' num2'是2个数字列。

错误消息是

TypeError: All estimators should implement fit and transform. 'Pipeline(memory=None,
 steps=[('selector', FunctionTransformer(accept_sparse=False,
      func=<function <lambda> at 0x7fefa8efd840>, inv_kw_args=None,
      inverse_func=None, kw_args=None, pass_y='deprecated',
      validate=False)), ('clf', OneVsRestClassifier(estimator=LogisticRegression(C=1.0, class_weigh...=None, solver='liblinear', tol=0.0001,
      verbose=0, warm_start=False),
      n_jobs=1))])' (type <class 'sklearn.pipeline.Pipeline'>) doesn't

我错过了哪一步?

2 个答案:

答案 0 :(得分:8)

FeatureUnion应该用作管道中的一个步骤,而不是管道周围。您得到的错误是因为您没有将分类器作为最后一步 - 联盟尝试在所有变换器上调用fittransform,并且分类器没有transform方法。

简单地返工以使用分类器作为最后一步的外部管道:

process_and_join_features = Pipeline([
    ('features', FeatureUnion([
            ('numeric_features', Pipeline([
                ('selector', get_numeric_data)
            ])),
             ('text_features', Pipeline([
                ('selector', get_text_data),
                ('vec', CountVectorizer())
            ]))
         ])),
    ('clf', OneVsRestClassifier(LogisticRegression()))
])

另请参阅here以获取scikit-learn网站上的一个很好的例子。

答案 1 :(得分:6)

虽然我相信@Ken Syme正确地识别了问题,并为您打算做的事情提供了修复。但是,如果您确实打算将分类器的输出用作更高级别模型的功能,请查看this blog

使用Zac的ModelTransformer,您可以按如下方式管道:

class ModelTransformer(TransformerMixin):

    def __init__(self, model):
        self.model = model

    def fit(self, *args, **kwargs):
        self.model.fit(*args, **kwargs)
        return self

    def transform(self, X, **transform_params):
        return DataFrame(self.model.predict(X))


process_and_join_features = FeatureUnion(
         [
            ('numeric_features', Pipeline([
                ('selector', get_numeric_data),
                ('clf', ModelTransformer(OneVsRestClassifier(LogisticRegression())))
            ])),
             ('text_features', Pipeline([
                ('selector', get_text_data),
                ('vec', CountVectorizer()),
                ('clf', ModelTransformer(OneVsRestClassifier(LogisticRegression())))
            ]))
         ]
)

根据具体的后续步骤,您仍可能需要将FeatureUnion包装在管道中(例如,使用快捷方式make_pipeline)。