机器学习:伯努利朴素贝叶斯分类器(原理+python实现)

Agatha ·
更新时间:2024-09-20
· 626 次阅读

伯努利朴素贝叶斯分类器主要用于文本分类,下面我们以一个具体的例子,来讲述下伯努利朴素贝叶斯的原理和实现逻辑。
具体例子:

已知我们有八个句子以及每个句子对应的类别,即中性或侮辱性。那么再给出一个句子,我们来判断该句子是中性还是侮辱性,即计算该句子是中性的概率大还是侮辱性的概率大,概率大的类别即为我们判断的类别。

首先要把句子进行处理,即把句子分解成拥有多个单词的单词组,句子对应的单词组以及类别如下所示:

def loadDataSet(): postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'], ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'], ['stop', 'posting', 'stupid', 'worthless', 'garbage'], ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'], ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']] classVec = [0, 1, 0, 1, 0, 1] # 类别0为中性,1为带有侮辱性质 return postingList, classVec

那么在给出一个单词组的情况下,根据贝叶斯决策理论,计算出该单词组属于类别0和类别1的概率,其计算公式如下:

p(类别 i│单词组)=(p(单词组│类别 i )×p(类别i))/(p(单词组))

其中, i=0或1
p(类别i)该如何计算?
对于训练集内的八个单词组,当类别为i时所对应的单词组数占这八个单词组的比例即为p(类别i)
p(单词组│类别 i )该如何计算?

p(单词组│类别 i )=p(单词1│类别 i )×p(单词2│类别 i )×…p(单词n│类别 i )

可以看出,对于一个单词组而言,其p(单词组│类别 i )是由在该类别下的各个单词的条件概率相乘而来,这意味着在计算p(单词组│类别 i )时,认为单词组内所有单词都是彼此独立的特征,该假设叫做条件独立性假设,这也是朴素贝叶斯的决策原理。
那么对于p(单词j│类别 i ),它该如何计算呢?具体如下:

p(单词j│类别 i )=(符合类别 i的训练集内单词j的数目)/(符合类别 i的训练集内所有单词的数目)

根据例子的描述可以知道,训练集指的是这八个单词组,符合类别i的训练集指的是,在这八个单词组中,只有对应类别是i的单词组,才算是符合类别i的训练集。那么单词的数目是什么呢?首先我们来了解下单词表的概念。对于训练集的单词组,我们可以以此来构建一个单词表,那么对于单词j而言,只要在一个单词组出现过,那么在单词j的数目上就增加一次,而训练集内有八个单词组,所以单词j出现的次数最多为8次。从这里可以看出,单词j即使是在同一个单词组内出现多次,也依然会记作1次,这就是伯努利模型。

在伯努利模型中,假设所有单词的权重是一样的,所以即使两个单词在同一词组出现的次数不同,伯努利模型会认为这两个单词的重要程度是一样的。

那么什么是训练集内所有单词的数目呢?这就是说,在计算出各个词组内都有多少个单词出现在了单词表中,其数目的累加和。
根据上面的描述,我们可以先构建一个单词表,其单词表涵盖了这八个单词组内所出现的所有单词。

# 根据句子构建单词表 def createVocabList(dataSet): vocabSet = set([]) # 因为document也是[]结构 for document in dataSet: vocabSet = vocabSet | set(document) # 集合的并集 return list(vocabSet) # 将集合格式变为list格式

接下来,根据单词表,将所有的单词组都转换成一个词向量,这样的转换方式使得每个长度不一的单词组都转换成了长度一样的数字向量,与此同时,词向量可以可以很清晰地显示出每个词组都出现哪些单词,需要注意的是,这里是应用了伯努利模型,所以单词在同一词组内无论出现多少次都记作1,没出现记作0。

# 将单词组转换成数字组 def setOfWords2Vec(vocabList, inputSet): returnVec = [0] * len(vocabList) # 构建指定长度的列表 for word in inputSet: if word in vocabList: returnVec[vocabList.index(word)] = 1 else: print "the word: %s is not in my Vocabulary!" % word return returnVec

那么现在按照p(单词j│类别 i )的计算方式,可以计算出训练集内的八个单词组各个单词在不同类别下的条件概率,以及p(类别i),其实现方式如下:

# 输入词向量矩阵和类别标签 def trainNB0(trainMatrix, trainCategory): numTrainDocs = len(trainMatrix) # 训练集单词组数 numWords = len(trainMatrix[0]) # pAbusive = sum(trainCategory) / float(numTrainDocs) # p(类别1) p0Num = ones(numWords); #初始化为1 p1Num = ones(numWords) #初始化为1 p0Denom = 2.0; # 初始化为2 p1Denom = 2.0 # 初始化为2 for i in range(numTrainDocs): # 对于每一个词向量而言 if trainCategory[i] == 1: p1Num += trainMatrix[i] # 记录类别为1时每个词的出现次数 p1Denom += sum(trainMatrix[i]) # 记录类别为1时单词出现总数 else: p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i]) p1Vect = log(p1Num / p1Denom) # 进行log处理 p0Vect = log(p0Num / p0Denom) # 进行log处理 return p0Vect, p1Vect, pAbusive

那么在这里,我们要考虑一个现实问题,那就是

p(单词1│类别 i )×p(单词2│类别 i )×…p(单词n│类别 i )

如果说有一个因子为0,那么p(单词组│类别 i )就为0,所以我们可以将词向量作下修改,即不出现单词的记作1,出现单词的记作2,这样就避免了 p(单词j│类别 i )可能为0的情况。但与此同时,若p(单词j│类别 i )都很小时,乘积出来依然为0,为了避免这个问题,我们将p(单词j│类别 i )修改为ln(p(单词j│类别 i )),通过取对数,来化解概率较小的问题。根据上面这两个修改,我们计算两个类别下的概率。

# 输入要预测的词向量和p0Vect, p1Vect, pAbusive def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): p1 = sum(vec2Classify * p1Vec) + log(pClass1) # element-wise mult p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) if p1 > p0: return 1 else: return 0

根据构建好的贝叶斯决策,进行预测[‘love’, ‘my’, ‘dalmation’] 和[‘stupid’, ‘garbage’]这两个词组的类别

def testingNB(): listOPosts, listClasses = loadDataSet() myVocabList = createVocabList(listOPosts) trainMat = [] for postinDoc in listOPosts: trainMat.append(setOfWords2Vec(myVocabList, postinDoc)) p0V, p1V, pAb = trainNB0(np.array(trainMat), np.array(listClasses)) testEntry = ['love', 'my', 'dalmation'] thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb)) testEntry = ['stupid', 'garbage'] thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb)) testingNB()

其预测的类别为
在这里插入图片描述

总结:本文在讲述伯努利朴素贝叶斯分类器原理的同时,也引入了文本处理的方法,主要是将长短不一的单词词组经过指定的单词表转换成了词向量,由此可以通过贝叶斯准则计算出各个类别的概率,决策出类别。但在整个过程中,伯努利朴素贝叶斯假设单词组内各个单词的特征是相互独立的,且每个单词的作用程度地位是一样的,因此也存在一定的局限性。


作者:DocPark



伯努利 朴素贝叶斯 学习 分类 贝叶斯 贝叶斯分类器 分类器 机器学习 Python

需要 登录 后方可回复, 如果你还没有账号请 注册新账号