机器学习实战(代码部分)-- 朴素贝叶斯之文本分类(Ⅲ 根据现实情况修改分类器)

mac2025-02-28  4

4-3 朴素贝叶斯分类函数

使用一般的朴素贝叶斯分类器训练函数存在以下两个问题:

(1)其中一个词语在文本中没出现概率为0导致整组数据概率值为0。

        利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(w0|1)p(w1|1)p(w2|1)。如果其中一个概率值为0,那么最后的乘积也为0。

如下图:两组数据都出现了一个概率为0的情况。

(2)下溢出。这是由于太多很小的数相乘造成的。当计算乘积p(w0|ci)p(w1|ci)p(w2|ci)...p(wN|ci)时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。

 

解决方案:

(1)为降低其中一个概率为0导致结果概率为0的影响,可以将所有词的出现数初始化为1,并将分母初始化为2。

对以下四行代码进行修改:

p0Num = np.zeros(numWords) p1Num = np.zeros(numWords) # 创建numpy.zeros数组,词条出现数初始化为0 p0Denom = 0.0 p1Denom = 0.0 # 分母初始化为0

修改为:

# 将所有词的出现次数初始化为1,分母则初始化为2 p0Num = np.ones(numWords) p1Num = np.ones(numWords) p0Denom = 2.0 p1Denom = 2.0

(2)为解决下溢出,可以对乘积取自然对数。在代数中有ln(a*b) = ln(a)+ln(b),于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。

修改以下两行代码:

p1Vect = p1Num / p1Denom p0Vect = p0Num / p0Denom

修改为:

p1Vect = log(p1Num / p1Denom) p0Vect = log(p0Num / p0Denom)

 

朴素贝叶斯分类函数如下:

# P(侮辱类 | a ,b) = P(a | 侮辱类) * P(b | 侮辱类) / P(a, b) # P(非侮辱类 | a ,b) = P(a | 非侮辱类) * P(b | 非侮辱类) / P(a, b) # 由于比较的是两值大小,不需要计算分母P(a, b)的值 # P(a | 侮辱类)计算:首先找出所有侮辱类样本,构造子空间,然后在该子空间中计算a单词出现的概率即可 def classifyByNB(vecToClssify, p0Vect, p1Vect, pClass1): p1 = sum(vecToClssify * p1Vect) + np.log(pClass1) p0 = sum(vecToClssify * p0Vect) + np.log(1 - pClass1) print(p1, ' -- ', p0) if p1 > p0: return 1 else: return 0

在主函数编写如下代码测试:

if __name__ == "__main__": postingList, classVec = loadDataSet() myVocabList = createVocabList(postingList) print(myVocabList) trainMat = [] for postinDoc in postingList: trainMat.append(setWordsToVec(myVocabList, postinDoc)) # trainMat类似[1, 0, 1, 0, 0, 0, ...],[0, 1, 0, 0, 0, 0, ...], ... # print('trainMat:\n', trainMat) p0V, p1V, pAb = trainNB0(trainMat, classVec) testEntry1 = ['love', 'my', 'dalmation'] thisDoc = np.array(setWordsToVec(myVocabList, testEntry1)) if classifyByNB(thisDoc, p0V, p1V, pAb): print(testEntry1, '侮辱类') else: print(testEntry1, '非侮辱类') testEntry2 = ['stupid', 'garbage'] thisDoc = np.array(setWordsToVec(myVocabList, testEntry2)) if classifyByNB(thisDoc, p0V, p1V, pAb): print(testEntry2, '侮辱类') else: print(testEntry2, '非侮辱类')

运行结果如下:

 

最新回复(0)