我在Python中编写了一个简单的多项式朴素贝叶斯分类器。代码能够为BBC新闻数据集预测正确的标签,但当我在分母中使用先验P(X)概率来输出概率分数时,我得到了错误的值(例如概率大于1)。下面我附上了我的代码:
整个过程基于我在维基百科关于朴素贝叶斯的文章中学到的公式:
- 所以,第一步是从文章中提取特征。我使用Sklearn的计数向量化器来实现这个目的。它计算词汇表中所有词的出现次数:
from sklearn.feature_extraction.text import CountVectorizervectorizer = CountVectorizer(stop_words='english', min_df=5, ngram_range=(1,1) )features = vectorizer.fit_transform(data.news).toarray()print(features.shape)(2225, 9138)
结果是,我为数据集中每篇文章得到了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的词。
- 接下来,我计算p(Ck),即标签的先验概率。我简单地将某一类别的文章总数除以所有类别的文章总数:
labels_probs = [ len(data.index[data['category_id'] == i ]) / len(data) for i in range(5)]
- 这些是用于缩放项和常数项(相应地为P(x))的函数:
import math as mathfrom scipy.special import factorialdef 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
所以,上面的最后一个函数计算分母(先验概率P(x))。它将所有文章类的P(x|Ck)加总:
- 最终的朴素贝叶斯分类器看起来像这样:
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
没有常数项,这个函数能够为我输入的任何自定义文本输出正确的标签。但所有类别的分数都均匀且接近于零。当我通过常数项(证据)来得到总和为零的真实概率值时,我得到了奇怪的结果,比如所有类别的概率为1.25。我肯定在理论上遗漏了一些东西,因为我对概率论和数学知之甚少。任何帮助我都会非常感激。谢谢。
回答:
感谢Robert Dodier,我弄清楚了问题所在。在除以常数(证据)之前,确保将分子中的对数转换回概率。同时,在对证据项中的所有类别求和之前,确保对其进行指数化处理。