【问题标题】:How to include SimpleImputer before CountVectorizer in a scikit-learn Pipeline?如何在 scikit-learn 管道中的 CountVectorizer 之前包含 SimpleImputer?
【发布时间】:2020-11-09 23:59:47
【问题描述】:

我有一个包含一列文本的 pandas DataFrame,我想使用 scikit-learn 的 CountVectorizer 对文本进行矢量化。但是,文本包含缺失值,因此我想在矢量化之前估算一个常量值。

我最初的想法是创建一个PipelineSimpleImputerCountVectorizer

import pandas as pd
import numpy as np
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})

from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='constant')

from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()

from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, vect)

pipe.fit_transform(df[['text']]).toarray()

但是,fit_transform 会出错,因为SimpleImputer 输出二维数组,而CountVectorizer 需要一维输入。这是错误消息:

AttributeError: 'numpy.ndarray' object has no attribute 'lower'

问题:如何修改此Pipeline 以使其正常工作?

注意:我知道我可以在 pandas 中估算缺失值。但是,我想在 scikit-learn 中完成所有预处理,以便可以使用 Pipeline 将相同的预处理应用于新数据。

【问题讨论】:

  • 为什么不在原始数据框中估算缺失值:df.fillna("")
  • @DYZ 正如我在问题底部提到的,我想在 scikit-learn 中完成所有预处理,以便我可以使用 Pipeline 对新数据应用相同的预处理。

标签: python machine-learning scikit-learn imputation countvectorizer


【解决方案1】:

我发现的最佳解决方案是将自定义转换器插入Pipeline,将SimpleImputer 的输出从2D 重塑为1D,然后再传递给CountVectorizer。 p>

完整代码如下:

import pandas as pd
import numpy as np
df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})

from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='constant')

from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()

# CREATE TRANSFORMER
from sklearn.preprocessing import FunctionTransformer
one_dim = FunctionTransformer(np.reshape, kw_args={'newshape':-1})

# INCLUDE TRANSFORMER IN PIPELINE
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(imp, one_dim, vect)

pipe.fit_transform(df[['text']]).toarray()

proposed on GitHub 一直认为CountVectorizer 应该允许二维输入,只要第二维为 1(意思是:单列数据)。对CountVectorizer 的修改将是解决这个问题的好方法!

【讨论】:

    【解决方案2】:

    一种解决方案是在 SimpleImputer 之外创建一个类并覆盖其 transform() 方法:

    import pandas as pd
    import numpy as np
    from sklearn.impute import SimpleImputer
    
    
    class ModifiedSimpleImputer(SimpleImputer):
        def transform(self, X):
            return super().transform(X).flatten()
    
    
    df = pd.DataFrame({'text':['abc def', 'abc ghi', np.nan]})
    
    imp = ModifiedSimpleImputer(strategy='constant')
    
    from sklearn.feature_extraction.text import CountVectorizer
    vect = CountVectorizer()
    
    from sklearn.pipeline import make_pipeline
    pipe = make_pipeline(imp, vect)
    
    pipe.fit_transform(df[['text']]).toarray()
    

    【讨论】:

    • 反之亦然:class ModifiedCountVectorizer(CountVectorizer): def fit_transform(self, X, y=None): return super().fit_transform(X.flatten())
    【解决方案3】:

    当我有一维数据时,我将这个一维包装器用于 sklearn Transformer。我认为,在您的情况下,此包装器可用于为一维数据(带有字符串值的熊猫系列)包装 simpleImputer。

    class OneDWrapper:
        """One dimensional wrapper for sklearn Transformers"""
    
        def __init__(self, transformer):
            self.transformer = transformer
    
        def fit(self, X, y=None):
            self.transformer.fit(np.array(X).reshape(-1, 1))
            return self
    
        def transform(self, X, y=None):
            return self.transformer.transform(
                np.array(X).reshape(-1, 1)).ravel()
    
        def inverse_transform(self, X, y=None):
            return self.transformer.inverse_transform(
                np.expand_dims(X, axis=1)).ravel()
    

    现在,您不需要在管道中执行额外的步骤。

    one_d_imputer = OneDWrapper(SimpleImputer(strategy='constant'))
    pipe = make_pipeline(one_d_imputer, vect)
    pipe.fit_transform(df['text']).toarray() 
    # note we are feeding a pd.Series here!
    
    

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 2020-05-05
      • 2021-06-30
      • 2017-02-25
      • 1970-01-01
      • 2015-08-14
      • 2020-01-15
      • 2016-02-09
      • 2014-07-13
      相关资源
      最近更新 更多