【问题标题】:Implementing Bag-of-Words Naive-Bayes classifier in NLTK在 NLTK 中实现词袋朴素贝叶斯分类器
【发布时间】:2012-04-23 07:42:06
【问题描述】:

我基本上有same question as this guy.. 朴素贝叶斯分类器的example in the NLTK book 只考虑一个单词是否出现在文档中作为一个特征.. 它不考虑单词的频率作为要查看的特征在(“词袋”)。

One of the answers 似乎暗示这不能用内置的 NLTK 分类器来完成。是这样吗?如何使用 NLTK 进行频率/词袋 NB 分类?

【问题讨论】:

    标签: python machine-learning nlp nltk naivebayes


    【解决方案1】:

    scikit-learnan implementation of multinomial naive Bayes,这是这种情况下朴素贝叶斯的正确变体。不过,支持向量机 (SVM) 可能会更好。

    正如 Ken 在 cmets 中指出的那样,NLTK 有 a nice wrapper for scikit-learn classifiers。根据文档修改,这里有一个有点复杂的,它进行 TF-IDF 加权,根据 chi2 统计选择 1000 个最佳特征,然后将其传递给多项式朴素贝叶斯分类器。 (我敢打赌这有点笨拙,因为我对 NLTK 或 scikit-learn 都不是很熟悉。)

    import numpy as np
    from nltk.probability import FreqDist
    from nltk.classify import SklearnClassifier
    from sklearn.feature_extraction.text import TfidfTransformer
    from sklearn.feature_selection import SelectKBest, chi2
    from sklearn.naive_bayes import MultinomialNB
    from sklearn.pipeline import Pipeline
    
    pipeline = Pipeline([('tfidf', TfidfTransformer()),
                         ('chi2', SelectKBest(chi2, k=1000)),
                         ('nb', MultinomialNB())])
    classif = SklearnClassifier(pipeline)
    
    from nltk.corpus import movie_reviews
    pos = [FreqDist(movie_reviews.words(i)) for i in movie_reviews.fileids('pos')]
    neg = [FreqDist(movie_reviews.words(i)) for i in movie_reviews.fileids('neg')]
    add_label = lambda lst, lab: [(x, lab) for x in lst]
    classif.train(add_label(pos[:100], 'pos') + add_label(neg[:100], 'neg'))
    
    l_pos = np.array(classif.classify_many(pos[100:]))
    l_neg = np.array(classif.classify_many(neg[100:]))
    print "Confusion matrix:\n%d\t%d\n%d\t%d" % (
              (l_pos == 'pos').sum(), (l_pos == 'neg').sum(),
              (l_neg == 'pos').sum(), (l_neg == 'neg').sum())
    

    这是为我打印的:

    Confusion matrix:
    524     376
    202     698
    

    不完美,但还不错,考虑到这不是一个超级简单的问题,而且只训练了 100/100。

    【讨论】:

    • 实际上,他可能想要 scikit-learn 支持向量机模型。 NLTK 有一个很好的包装器nltk.classify.scikitlearn.SklearnClassifier,它可以让这些分类器很好地融入它的 API。
    • @KenBloom 是的,SVM 可能会更好,但他确实特别询问了朴素贝叶斯。 :) 那个包装器很好,我刚刚意识到在 scikit-learn 中还有一个多项式朴素贝叶斯,所以我会改变我的答案来使用它。
    • 看起来非常简单。我希望我在攻读博士学位时已经学会了 python。在这。我做了很多在 Ruby 中包装分类器的工作,这完全没有必要。
    • +1,但请注意,此 scikit-learn 包装器尚未出现在 NLTK 版本中,因此您需要来自 GitHub 的前沿版本。
    • 我知道你问过朴素贝叶斯分类器,但我发现 PassiveAggressiveClassifier(n_iter=100) 效果最好。另外,设置TfidfTransformer(sublinear_tf=True)
    【解决方案2】:

    NLTK 贝叶斯分类器中的特征是“名义的”,而不是数字的。这意味着它们可以采用有限数量的离散值(标签),但不能将它们视为频率。

    因此,使用贝叶斯分类器,您不能直接将词频用作特征——您可以使用每个文本中出现频率较高的 50 个词作为特征集,但这是一个不一样的东西

    但也许 NLTK 中还有其他分类器依赖于频率。我不知道,但你看过吗?我会说值得一试。

    【讨论】:

      【解决方案3】:
      • 将您正在查看的字符串放入列表中,分成单词
      • 对于列表中的每个项目,询问:该项目是我的功能列表中的一个功能吗?
      • 如果是,照常添加log prob,如果不是,忽略它。

      如果您的句子多次使用相同的单词,它只会多次添加概率。如果单词在同一个课程中出现多次,您的训练数据应该在字数中反映出来。

      为提高准确性,请将所有二元组、三元组等视为单独的特征。

      手动编写您自己的分类器有助于您准确了解正在发生的事情以及您需要做些什么来提高准确性。如果您使用预打包的解决方案并且效果不佳,那么您无能为力。

      【讨论】:

        猜你喜欢
        • 2016-09-28
        • 2012-12-05
        • 2015-12-20
        • 2017-04-19
        • 2017-08-30
        • 2012-04-01
        • 2012-04-18
        • 2017-01-10
        相关资源
        最近更新 更多