Python 如何在朴素贝叶斯分类器中计算证据?
我用Python编写了一个简单的多项式朴素贝叶斯分类器。代码预测了正确的标签,但是当我使用分母中的先验P(X)概率来输出分数作为概率时,我得到了错误的值(比如概率>1)。下面我附上我的代码: 整个过程基于我从关于Naive Bayes的课程中学到的公式:Python 如何在朴素贝叶斯分类器中计算证据?,python,machine-learning,statistics,data-science,naivebayes,Python,Machine Learning,Statistics,Data Science,Naivebayes,我用Python编写了一个简单的多项式朴素贝叶斯分类器。代码预测了正确的标签,但是当我使用分母中的先验P(X)概率来输出分数作为概率时,我得到了错误的值(比如概率>1)。下面我附上我的代码: 整个过程基于我从关于Naive Bayes的课程中学到的公式: 因此,第一步是从文章中提取特征。为此,我使用Sklearn的计数矢量器。它统计词汇表中所有单词的出现次数: 因此,数据集中的每一篇文章都有9138个特性 下一步是计算每个标签的p(xi | Ck)。它由多项式分布公式给出: 我计算pki如下
def count_word_probability(features):
V_size = features.shape[1]
alpha = 1
total_counts_for_each_word = np.sum(features,axis=0)
total_count_of_words = np.sum(total_counts_for_each_word)
probs = (alpha + total_counts_for_each_word) / ( (V_size * alpha) + total_count_of_words)
return probs
基本上,此函数的作用是计算具有特定标签(例如业务)的所有文章中每个单词的总频率,并除以具有该标签的所有文章中的单词总数。它还应用拉普拉斯平滑(alpha=1)来解释频率为0的单词
def nb_constant (article, labels_probs, word_probs):
s_term = scaling_term(article)
evidence = [ np.log(s_term) + np.sum(article * np.log(word_probs[i])) + np.log(labels_probs[i]) for i in range(len(word_probs))]
evidence = np.sum(evidence)
return evidence
因此,上面的最后一个函数计算分母(先验概率p(x)。它将所有物品类别的p(x | Ck)相加:
没有一个常数项,这个函数为我提供给它的任何自定义文本输出正确的标签。但是所有类的分数都是一致的,接近于零。当我除以常数项得到加起来等于零的真实概率值时,我得到了奇怪的结果,比如所有类的概率都是1.25。我肯定在这个函数中遗漏了一些东西因为我对概率论和数学知之甚少。如果有任何帮助,我将不胜感激。谢谢。谢谢,我知道了问题所在。在除以常数(证据)之前确保将分子日志指数化为概率。此外,在对证据项中的所有类进行求和之前,确保对它们进行指数化。好吧,如果最终的每类概率总和不为1,则表示您计算的归一化因子不正确,因为根据定义,1/Z是使每类概率为1的因子-类概率之和为1。规范化应该如下所示:Z=k上非规范化概率之和,然后是规范化概率=非规范化/Z。在我看来,你的思路是正确的,坚持住,我想你能找到答案。@RobertDodier嗨,Robert!谢谢你的回答。你能解释一下这个公式吗一点点?什么是k上的非标准化概率?什么是标准化概率?我想我应该使用与分子-P(Ck)*P(x | Ck)相同的公式在我看来,你是在用对数把乘法变成加法,这是可以的,但你必须小心。从log(p)转换回来后,你必须应用1/Z对于p,也就是说,在使用exp.计算Z之后,最简单、最可靠的方法是对要规格化的数组求和,按原样将元素相加,然后将每个元素除以和。我的建议是,不要试图复制相同的公式,并在公式上求和——只需构造数组,然后在数字上求和数组中有。希望这有帮助!@RobertDodier非常感谢!它起作用了。我在取每个类的指数后,必须将Z个类相加。这是第一个错误。第二个错误是,在取分子的指数后,我必须除以Z。你能解释一下为什么这样的顺序吗?是因为如果取对数,我就不能除以对数吗分子数和分母数是分开取的吗?或者它可以与减法一起使用吗?log(分子)-log(分母)?如果你愿意,你也可以发表你对这个问题的答案,指出一些对数规则,以及在使用这个公式时如何小心?
labels_probs = [ len(data.index[data['category_id'] == i ]) / len(data) for i in range(5)]
import math as math
from scipy.special import factorial
def scaling_term(doc):
term = math.factorial(np.sum(doc)) / np.prod(factorial(doc))
return term
def nb_constant (article, labels_probs, word_probs):
s_term = scaling_term(article)
evidence = [ np.log(s_term) + np.sum(article * np.log(word_probs[i])) + np.log(labels_probs[i]) for i in range(len(word_probs))]
evidence = np.sum(evidence)
return evidence
def naive_bayes(article, label_probs, words_probs):
class_probs = []
s_term = scaling_term(article)
constant_term = nb_constant(article, label_probs, words_probs)
for cl in range(len(label_probs)):
class_prob = ( np.log(s_term) + np.sum(article * np.log(words_probs[cl])) + np.log(label_probs[cl]) ) / constant_term
class_probs.append(class_prob)
class_probs = np.exp(np.array(class_probs))
return class_probs