如何在 python sklearn 中正确使用 featureUnion 数字和文本特征

how to featureUnion numerical and text features in python sklearn properly

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

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()))
            ]))
         ]
    )

在此代码中,'text' 是文本列,'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

我错过了什么步骤吗?

A 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 网站上执行此类操作的一个很好的示例。

虽然我相信@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)。