朴素贝叶斯概率总是 1

Posted

技术标签:

【中文标题】朴素贝叶斯概率总是 1【英文标题】:Naive Bayes probability always 1 【发布时间】:2013-08-06 06:46:31 【问题描述】:

我开始使用 sklearn.naive_bayes.GaussianNB 进行文本分类,并且得到了很好的初步结果。我想使用分类器返回的概率作为置信度的度量,但是 predict_proba() 方法总是为所选类返回“1.0”,而对于所有其他类返回“0.0”。

我知道(来自here)“......不要太认真地对待 predict_proba 的概率输出”,但是到那个程度?! 分类器可能会弄错 finance-investingchords-strings,但 predict_proba() 输出没有任何犹豫的迹象...

关于上下文的一点: - 我一直在使用 sklearn.feature_extraction.text.TfidfVectorizer 进行特征提取,首先没有使用 stop_wordsmin/max_df --> 我得到了非常大的向量。 - 我一直在分层类别树(浅层:深度不超过 3 层)上训练分类器,每个类别有 7 个文本(手动分类)。现在是flat 培训:我没有考虑层次结构。

生成的 GaussianNB 对象非常大(~300MB),预测速度相当慢:一个文本大约需要 1 秒。 这有关系吗?巨大的向量是这一切的根源吗? 如何获得有意义的预测?我需要使用不同的分类器吗?

这是我正在使用的代码:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import GaussianNB
import numpy as np
from sklearn.externals import joblib

Vectorizer = TfidfVectorizer(input = 'content')
vecs = Vectorizer.fit_transform(TextsList) # ~2000 strings
joblib.dump(Vectorizer, 'Vectorizer.pkl') 
gnb = GaussianNB()
Y = np.array(TargetList) # ~2000 categories 
gnb.fit(vecs.toarray(), Y)
joblib.dump(gnb, 'Classifier.pkl') 
...

#In a different function:
Vectorizer = joblib.load('Vectorizer.pkl')
Classifier = joblib.load('Classifier.pkl')
InputList = [Text] # One string
Vec = Vectorizer.transform(InputList)
Probs = Classifier.predict_proba([Vec.toarray()[0]])[0]
MaxProb = max(Probs)
MaxProbIndex = np.where(Probs==MaxProb)[0][0]
Category = Classifier.classes_[MaxProbIndex]
result = (Category, MaxProb)  

更新: 按照下面的建议,我尝试了 MultinomialNBLogisticRegression。它们都返回不同的概率,并且在任何方面都更适合我的任务:更准确的分类、更小的内存对象和更快的速度(MultinomialNB 快如闪电!)。

我现在有一个新问题:返回的概率非常小——通常在 0.004-0.012 范围内。这是针对预测/获胜类别的(并且分类是准确的)。

【问题讨论】:

【参考方案1】:

"...predict_proba 的概率输出不要太认真"

我是写那个的人。关键是朴素贝叶斯倾向于预测几乎总是非常接近于零或非常接近于一的概率。正是您观察到的行为。逻辑回归(sklearn.linear_model.LogisticRegressionsklearn.linear_model.SGDClassifier(loss="log"))产生更现实的概率。

生成的 GaussianNB 对象非常大(~300MB),预测速度相当慢:一个文本大约需要 1 秒。

这是因为GaussianNB 是非线性模型,不支持稀疏矩阵(您已经发现了,因为您使用的是toarray)。使用MultinomialNBBernoulliNB 或逻辑回归,它们在预测时速度更快,而且更小。他们的假设。对于术语特征,输入也更真实。 GaussianNB 确实不是一个很好的文本分类估计器。

【讨论】:

感谢您的快速且非常有帮助的回答。我听从了你的建议,下面是一个小的跟进: ... LogisticRegressionMultinomialNB 都返回了不同的概率,彼此几乎完全一致,尽管数字非常小:通常在范围 0.004-0.012; SGDClassifier 只能返回二进制估计的概率;这三个确实比 GaussianNB 更快(MultinomialNB - 非常快)、更小且更准确。两个问题: 1. 我如何理解这些非常低的概率值? 2. scikit-learn 中是否有用于降维的工具,或者我应该在监控 score()的同时“玩”min/max_df >? @AviM:如果升级到 0.14,那么SGDClassifier 会执行多类概率。广告 1.,如果 LR 给出了极端概率,那么要么你的类非常明确,要么你需要更多的正则化。广告 2.,降维有很多选择。对于文本,有TruncatedSVD,但与MultinomialNB 不匹配。也可以尝试特征选择,见examples目录下的文档分类示例。 抱歉,可能不太清楚:我引用的“低价值”概率是预测/获胜类别的概率,即先出现的概率;现在分类还不错。这就是为什么我对低价值感到惊讶。再次感谢。 我将把它改写为一个问题:我如何看待我得到的非常低的概率(MultinomialNBLogisticRegression)?我可以认真对待它们吗?是不是我的类别“太接近”了?注:分类比较准确。

以上是关于朴素贝叶斯概率总是 1的主要内容,如果未能解决你的问题,请参考以下文章

朴素贝叶斯:朴素贝叶斯定义朴素贝叶斯公式分解朴素贝叶斯分类流程高斯型朴素贝叶斯多项式朴素贝叶斯伯努利型朴素贝叶斯朴素贝叶斯预测概率校准朴素贝叶斯优缺点

sklearn-朴素贝叶斯

朴素贝叶斯算法

朴素贝叶斯以及三种常见模型推导

朴素贝叶斯分类

朴素贝叶斯与贝叶斯网络