【问题标题】:Combine CountVectorizer and SelectKBest causes labels to disappear结合 CountVectorizer 和 SelectKBest 会导致标签消失
【发布时间】:2020-02-09 08:51:40
【问题描述】:

我有一个类可以创建特征提取管道并拟合逻辑回归模型。输入是 DF 结构中的一组字符串数据。 ItemSelector 类只返回具有来自原始数据帧的干净数据的列,然后将其传递给 CountVectorizer 和 Kbest 选择器。如果我删除 Kbest,则此管道有效:

from sklearn.base import BaseEstimator, TransformerMixin


class ItemSelector(BaseEstimator, TransformerMixin):
    # returns a single column from a DF
    def __init__(self, key):
        self.key = key

    def fit(self, x, y=None):
        return self

    def transform(self, data_dict):
        return data_dict[self.key]

class LogisticRegressionWithWordFeatures(object):

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

    def fit(self, df, labels):
        self.pipeline = self.get_preprocessing_pipeline(df)
        fitted_df = self.pipeline.fit_transform(df)
        self.model.fit(fitted_df, labels)
        return self

    def predict(self, df):
        fitted_df = self.pipeline.transform(df)
        y = self.model.predict(fitted_df)
        return y


    def get_preprocessing_pipeline(self, data_frame):
        """
        Get data frame containing features and labels from raw feature input DF.
        :param input_file: input DF
        """

        process_and_join_features = Pipeline([
            ('features', FeatureUnion([
            ('count_lemma_features', Pipeline([
                ('selector', ItemSelector(key='clean_Invoice_Description')),
                ('counts', CountVectorizer(analyzer="word", stop_words='english'))]))])),
            ('reducer', SelectKBest(chi2, k=1000))
        ])
        return process_and_join_features

如果我尝试基于此管道进行拟合/转换,则会收到此错误:

    model = LogisticRegressionWithWordFeatures()
    model.fit(train_data, train_labels)
    test_y = model.predict(test_data)

>>>

    TypeError                                 Traceback (most recent call last)
<ipython-input-183-536a1c9c0a09> in <module>
      1 b_logistic_regression_with_hypers_bow_clean = LogisticRegressionWithWordFeatures()
----> 2 b_logistic_regression_with_hypers_bow_clean = b_logistic_regression_with_hypers_bow_clean.fit(b_ebay_train_data, b_ebay_train_labels)
      3 b_ebay_y_with_hypers_bow_clean = b_logistic_regression_with_hypers_bow_clean.predict(b_ebay_test_data)
      4 b_gold_y_with_hypers_bow_clean = b_logistic_regression_with_hypers_bow_clean.predict(gold_df)

<ipython-input-181-6974b6ea2a5b> in fit(self, df, labels)
      6     def fit(self, df, labels):
      7         self.pipeline = self.get_preprocessing_pipeline(df)
----> 8         fitted_df = self.pipeline.fit_transform(df)
      9         self.model.fit(fitted_df, labels)
     10         return self

~/anaconda3/lib/python3.7/site-packages/sklearn/pipeline.py in fit_transform(self, X, y, **fit_params)
    391                 return Xt
    392             if hasattr(last_step, 'fit_transform'):
--> 393                 return last_step.fit_transform(Xt, y, **fit_params)
    394             else:
    395                 return last_step.fit(Xt, y, **fit_params).transform(Xt)

~/anaconda3/lib/python3.7/site-packages/sklearn/base.py in fit_transform(self, X, y, **fit_params)
    551         if y is None:
    552             # fit method of arity 1 (unsupervised transformation)
--> 553             return self.fit(X, **fit_params).transform(X)
    554         else:
    555             # fit method of arity 2 (supervised transformation)

TypeError: fit() missing 1 required positional argument: 'y'

很明显,问题在于训练标签没有进入管道。我尝试为训练标签添加另一个项目选择器:

        process_and_join_features = Pipeline([
            ('features', FeatureUnion([
                ('count_lemma_features', Pipeline([
                    ('selector', ItemSelector(key='clean_Invoice_Description')),
                    ('counts', CountVectorizer(analyzer="word", stop_words='english'))])),
                ('labels', ItemSelector(key='Expense_Category'))])),
            ('reducer', SelectKBest(chi2, k=1000))
        ])
        return process_and_join_features

但这会导致标签 (Expense_Category) 出现关键错误,即使该列存在于训练数据中。

如果我一步一步地做,这是可行的:

item_selector = ItemSelector(key='clean_Invoice_Description').fit(train_data)
count_selector = CountVectorizer(analyzer="word", stop_words='english')
k_best = SelectKBest(chi2, k=1000)

invoice_desc = item_selector.transform(train_data)
invoice_desc = count_selector.fit_transform(invoice_desc)
reduced_desc = k_best.fit_transform(invoice_desc, train_labels)
print(reduced_desc.shape)
>>> (6130, 1000)

逐步进行的问题在于,我想在其他列中使用其他功能,而管道提供了一种很好的方法,无需手动组合它们。

【问题讨论】:

    标签: python scikit-learn


    【解决方案1】:

    解决了。主要问题是每个功能的嵌套。 Pipelines() 需要一个元组列表,其中元组中的第一项是特征/管道名称,第二项是实际类。当您添加更多功能时,很容易忘记嵌套。这是最终代码:

       def get_preprocessing_pipeline(self, data_frame):
            """
            Get data frame containing features and labels from raw feature input csv file"""
    
            process_and_join_features = Pipeline([
                ('features', 
                 FeatureUnion([
                    ('tokens',
                        Pipeline([
                            ('selector', ItemSelector(key='clean_Invoice_Description')),
                            ('vec', CountVectorizer(analyzer="word", stop_words='english')),
                            ('dim_red', SelectKBest(chi2, k=5000))
                        ])),
                    ('hypernyms',
                        Pipeline([
                            ('selector', ItemSelector(key='hypernyms_combined')),
                            ('vec', TfidfVectorizer(analyzer="word")),
                            ('dim_red', SelectKBest(chi2, k=5000))
                    ]))]))])
            return process_and_join_features
    

    【讨论】:

      猜你喜欢
      • 2019-02-09
      • 2016-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-15
      • 2016-04-10
      • 1970-01-01
      相关资源
      最近更新 更多