如何在朴素贝叶斯分类器中计算证据?

我在Python中编写了一个简单的多项式朴素贝叶斯分类器。代码能够为BBC新闻数据集预测正确的标签,但当我在分母中使用先验P(X)概率来输出概率分数时,我得到了错误的值(例如概率大于1)。下面我附上了我的代码:

整个过程基于我在维基百科关于朴素贝叶斯的文章中学到的公式:

enter image description here

  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个特征。

  1. 下一步是计算每个标签的p(xi | Ck)。这是由多项式分布公式给出的:

enter image description here

我计算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的词。

  1. 接下来,我计算p(Ck),即标签的先验概率。我简单地将某一类别的文章总数除以所有类别的文章总数:
labels_probs = [ len(data.index[data['category_id'] == i ]) / len(data) for i in range(5)]
  1. 这些是用于缩放项和常数项(相应地为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)加总:

enter image description here

  1. 最终的朴素贝叶斯分类器看起来像这样:
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,我弄清楚了问题所在。在除以常数(证据)之前,确保将分子中的对数转换回概率。同时,在对证据项中的所有类别求和之前,确保对其进行指数化处理。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注