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

问题描述 投票:0回答:1

我用Python编写了一个简单的多项式朴素贝叶斯分类器。代码为BBC news dataset预测了正确的标签,但是当我在分母中使用先前的P(X)概率输出分数作为概率时,我得到的值不正确(例如> 1)。下面我附上我的代码:

整个过程基于我从Wikipedia article中学到的关于朴素贝叶斯的公式:

enter image description here

  1. 因此,第一步是从文章中提取特征。为此,我使用了Sklearn的计数矢量化程序。它计算词汇表中所有单词的出现次数:
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = 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(x i | C k)。它由多项式分布公式给出:

enter image description here

我按如下方式计算p ki

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(C k)。我只是将一个类别中的文章总数除以所有类别中的文章总数:
labels_probs = [ len(data.index[data['category_id'] == i ]) / len(data) for i in range(5)]
  1. 这些是相应地缩放项和常数项(P(x)的函数:
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

因此,以上最后一个函数计算所有商品类别的分母(先验概率P(x)。它求和P(x | C k)之和:

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。我肯定缺少理论上的东西,因为我对概率论和数学知识不多。我将不胜感激任何帮助。谢谢。

python machine-learning statistics data-science naivebayes
1个回答
1
投票

由于Robert Dodier,我弄清楚了问题所在。除以常数(证据)之前,请确保对分子对数取幂以求幂。同样,在总结之前,确保对证据项中的所有类别进行求幂。

© www.soinside.com 2019 - 2024. All rights reserved.