选择用于对用户文本数据进行分类的 sklearn 管道

Posted

技术标签:

【中文标题】选择用于对用户文本数据进行分类的 sklearn 管道【英文标题】:Choosing an sklearn pipeline for classifying user text data 【发布时间】:2016-04-16 13:23:09 【问题描述】:

我正在使用 Python 开发机器学习应用程序(使用 sklearn 模块),目前正在尝试确定用于执行推理的模型。问题的简要描述:

鉴于用户数据的许多实例,我试图根据相关关键字包含将它们分类为各种类别。它是有监督的,所以我有很多很多已经分类的预分类数据实例。 (每条数据在 2 到 12 个单词之间。)

我目前正在尝试在两个潜在模型之间做出决定:

    CountVectorizer + 多项朴素贝叶斯。使用 sklearn 的 CountVectorizer 获取训练数据中的关键字计数。然后,使用 sklearn 的 MultinomialNB 模型使用朴素贝叶斯对数据进行分类。

    对关键字计数使用 tf-idf 术语权重 + 标准朴素贝叶斯。使用 CountVectorizer 获取训练数据的关键字计数矩阵,使用 sklearn 的 TfidfTransformer 将该数据转换为 tf-idf 加权,然后将其转储到标准的朴素贝叶斯模型中。

我已经阅读了这两种方法中使用的类的文档,似乎都很好地解决了我的问题。

对于此类问题,为什么使用标准朴素贝叶斯模型的 tf-idf 加权可能优于多项朴素贝叶斯模型,是否有任何明显的原因?这两种方法有什么明显的问题吗?

【问题讨论】:

构建多个模型,看看哪个模型的 CV 得分最高。 【参考方案1】:

朴素贝叶斯和 MultinomialNB 是相同的算法。您得到的区别来自 tfidf 转换,它惩罚出现在您的语料库中的许多文档中的单词。

我的建议: 使用 tfidf 并为特征调整 TfidfVectorization 的 sublinear_tf、二值参数和归一化参数。

还可以尝试 scikit-learn 中可用的各种不同分类器,如果您正确调整正则化类型(罚分八分之一 l1 或 l2)和正则化参数 (alpha) 的值,我怀疑这些分类器会给您带来更好的结果。

如果您正确调整它们,我怀疑您可以使用带有“log”损失(逻辑回归)或“铰链”损失(SVM)的 SGDClassifier 获得更好的结果。

人们通常调整参数的方式是通过 scikit-learn 中的 GridSearchCV 类。

【讨论】:

我有点困惑。你说 Naive Bayes 和 MultinomialNB 是一样的,但 MultinomialNB 不是对训练数据强加了不同的分布吗? 您可以阅读stats.stackexchange.com/questions/33185/… 了解有关朴素贝叶斯的解释。朴素贝叶斯是一组通用的分类器,它们对标签分布的假设不同(Gaussian、BernoulliNB、MultinomialNB)。 您可以使用此脚本scikit-learn.org/stable/auto_examples/text/… 尝试不同的分类器。你只需要注入你自己的特性。对于单个分类器的参数,使用 GridSearchCV 进行调优。不要忘记调整参数会对性能产生巨大影响。【参考方案2】:

我同意大卫的评论。您可能想训练不同的模型,看看哪个是最好的。

import pandas as pd
import numpy as np

from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB, GaussianNB, BernoulliNB
from sklearn.pipeline import Pipeline
from sklearn.grid_search import GridSearchCV

from pprint import pprint

df = pd.DataFrame('Keyword': ['buy widget', 'buy widgets', 'fiberglass widget',
                               'fiberglass widgets', 'how much are widget',
                               'how much are widgets', 'installing widget',
                               'installing widgets', 'vinyl widget', 'vinyl widgets',
                               'widget cost', 'widget estimate', 'widget install',
                               'widget installation', 'widget price', 'widget pricing',
                               'widgets cost', 'widgets estimate', 'widgets install',
                               'widgets installation', 'widgets price', 'widgets pricing',
                               'wood widget', 'wood widgets'],
                   'Label': ['Buy', 'Buy', 'Fiberglass', 'Fiberglass', 'Cost', 'Cost',
                             'Install', 'Install', 'Vinyl', 'Vinyl', 'Cost', 'Estimate',
                             'Install', 'Install', 'Cost', 'Cost', 'Cost', 'Estimate',
                             'Install', 'Install', 'Cost', 'Cost', 'Wood', 'Wood'],
                  columns=['Label', 'Keyword'])

X = df['Keyword']
y = df['Label']

##pipeline = Pipeline(steps=[
##  ('cvect', CountVectorizer()),
##  ('mnb', MultinomialNB())
##  ])

pipeline = Pipeline(steps=[
  ('tfidf', TfidfVectorizer()),
  ('bnb', BernoulliNB())
  ])

parameters = 'tfidf__ngram_range': [(1,1), (1,2)],
              'tfidf__stop_words': [None, 'english'],
              'tfidf__use_idf': [True, False],
              'bnb__alpha': [0.0, 0.5, 1.0],
              'bnb__binarize': [None, 0.2, 0.5, 0.7, 1.0],
              'bnb__fit_prior': [True, False]

grid = GridSearchCV(pipeline, parameters, scoring='accuracy', cv=2, verbose=1)
grid.fit(X, y)

print('Best score:', grid.best_score_)
print('Best parameters:', pprint(grid.best_params_, indent=2))

# Here's how to predict (uncomment)
#pred = grid.predict(['buy wood widget', 'how much is a widget'])

#print(pred)

【讨论】:

以上是关于选择用于对用户文本数据进行分类的 sklearn 管道的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sklearn 库使用朴素贝叶斯执行文本分类?

用于文本分类的 SkLearn 模型

sklearn:文本分类交叉验证中的向量化

逻辑回归推导

实战:朴素贝叶斯对文档进行分类

基于协同训练的半监督文本分类算法