在 scikit-learn 中结合异构特征

Posted

技术标签:

【中文标题】在 scikit-learn 中结合异构特征【英文标题】:Combining heterogenous features in scikit-learn 【发布时间】:2017-06-20 17:18:12 【问题描述】:

我正在对一些已提取特征并在文本文件中给出的文档进行二进制分类。我的问题是存在文本特征和数字特征,例如年份等。 以这种格式给出了一个示例:

label |title text |otherText text |numFeature1 number |numFeature2 number

我正在关注有关 feature unions 的文档,但它们的用例有点不同。我没有从另一个特征中提取特征,因为这些数字特征已经给出。

目前我正在通过以下方式使用设置:

pipeline = Pipeline([
('features', Features()),

('union', FeatureUnion(
    transformer_list=[
        ('title', Pipeline([
            ('selector', ItemSelector(key='title')),
            ('tfidf', TfidfVectorizer()),
        ])),
        ('otherText', Pipeline([
            ('selector', ItemSelector(key='otherText')),
            ('tfidf', TfidfVectorizer()),
        ])),
        ('numFeature1', Pipeline([
            ('selector', ItemSelector(key='numFeature1')),
        ])),
        ('numFeature2', Pipeline([
            ('selector', ItemSelector(key='numFeature2')),
        ])),
    ],
)),
('classifier', MultinomialNB()),
])

Feature 类也是从文档中采用的:

class Features(BaseEstimator, TransformerMixin):
  def fit(self, x, y=None):
    return self

  def transform(self, posts):
    features = np.recarray(shape=(len(posts),),
                           dtype=[('title', object),('otherText', object),
                                  ('numFeature1', object),('numFeature2', object)])

    for i, text in enumerate(posts):
        l = re.split("\|\w+", text)
        features['title'][i] = l[1]
        features['otherText'][i] = l[2]
        features['numFeature1'][i] = l[3]
        features['numFeature2'][i] = l[4]

    return features

我现在的问题是:如何将数字特征添加到 FeatureUnion?使用 CountVectorizer 时,我得到“ValueError:空词汇;也许文档只包含停用词”,并且使用只有一个条目的 DictVectorizer 并没有让我觉得要走的路。

【问题讨论】:

只需使用 ItemSelector() 类和 key='numFeature1' 和 'numFeature2' 返回ValueError: blocks[0,:] has incompatible row dimensions 显示整个管道的代码。 我已经相应地编辑了我的问题 【参考方案1】:

TfidfVectorizer() 对象尚未安装数据。

在构建管道之前,请执行此操作 -

vec = TfidfVectorizer()
vec.fit(data['free text column'])
pipeline = Pipeline([
('features', Features()),

('union', FeatureUnion(
    transformer_list=[
        ('title', Pipeline([
            ('selector', ItemSelector(key='title')),
            ('tfidf', vec),
        ])),

        ... other features

如果您想再次拟合数据以用于测试目的,这会有所帮助...因为对于测试数据,管道会自动为 TfidfVectorizer 使用 transform() 函数,而不是之前必须明确执行的 fit() 函数构建管道

【讨论】:

我使用pipeline.fit(train.data, train.target) 在构建管道后像文档一样适合我的数据。我的问题是我需要采取哪些步骤将剩余的非文本功能集成到管道中。【参考方案2】:

ItemSelector() 的作用是,根据构造函数中提供的key 从给定的dict(X) 中挑选数据,并返回一个一维[n,] 数组。

FeatureUnion 无法正确处理这种类型的 [n,] 数组。 FeatureUnion 需要其内部每个 transformers 的 2 维数组,其中第 1 维(样本数)应保持一致,最终可以水平堆叠以组合特征。

前两个转换器 (TfidfVectorizer()) 中的第二个操作从 ItemSelector 获取此 [n,] 数组并输出有效的 [n,m] 数组类型,其中 m = number of features extracted from raw text

但是您的第 3 和第 4 个转换器包含 ItemSelector(),因此它输出 [n,] 数组。这就是错误的原因。

要纠正这个问题,您应该将ItemSelector 的输出重新整形为[n,1]。 更改ItemSelector.transform() 中的以下代码(我假设您使用的是您指定的链接中的 ItemSelector 代码):

原创

data_dict[self.key]

data_dict[self.key].reshape((-1,1))

reshape() 会将您的[n,] 格式化为[n,1],然后FeatureUnion 可以使用它来正确附加数据。

【讨论】:

请看我的相关问题here。

以上是关于在 scikit-learn 中结合异构特征的主要内容,如果未能解决你的问题,请参考以下文章

结合Scikit-learn介绍几种常用的特征选择方法

干货:结合Scikit-learn介绍几种常用的特征选择方法

在 scikit-learn 中,DBSCAN 可以使用稀疏矩阵吗?

scikit-learn与Serverless架构结合

将 IMDB 数据用于 sci-kit 回归模型包,该包在特征变量中具有文本值

AI常用框架和工具丨5. 机器学习库Scikit-learn