例子入手: 购买计算机预测
代码:
机器学习实战 第4章
# 训练函数
# 计算每个类别中的文档数目
# 对每篇训练文档:
# 对每个类别:
# 如果词条出现在文档中→ 增加该词条的计数值
# 增加所有词条的计数值
# 对每个类别:
# 对每个词条:
# 将该词条的数目除以总词条数目得到条件概率
# 返回每个类别的条件概率
# [trainMatrix训练矩阵:由6个句子的向量组合成的总向量;trainCategory训练分类:即数据集分类标签label矩阵]
def trainNB0(trainMatrix, trainCategory):
# 获取训练矩阵长度,即多少个句子,此处为6
numTrainDocs = len(trainMatrix)
# 获取库中所有单词数量,也就是矩阵中特征数量
numWords = len(trainMatrix[0])
# 计算侮辱性句子总体占比,此处为1/2
pAbusive = sum(trainCategory) / float(numTrainDocs)
# 初始化概率
'''利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概
率,即计算p(w0|1)p(w1|1)p(w2|1)。如果其中一个概率值为0,那么最后的乘积也为0。为降低
这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2。'''
p0Num = ones(numWords)
p1Num = ones(numWords)
# p0Num = zeros(numWords)
# p1Num = zeros(numWords)
p0Denom = 2.0
p1Denom = 2.0
# p0Denom = 0
# p1Denom = 0
# 遍历所有句子向量
for i in range(numTrainDocs):
# 如果当前句子为侮辱性的
if trainCategory[i] == 1:
# 累加句子向量
p1Num += trainMatrix[i]
# 累加句中词库中词出现的数量
p1Denom += sum(trainMatrix[i])
else:
# 如但如果当前句子为非侮辱性的正常言论
# 累加句子向量
p0Num += trainMatrix[i]
# 累加句中词库中词出现的数量
p0Denom += sum(trainMatrix[i])
##
#'''另一个遇到的问题是下溢出, 这是由于太多很小的数相乘造成的。当计算乘积
#p(w0|ci)p(w1|ci)p(w2|ci)...p(wN|ci)时,由于大部分因子都非常小,所以程序会下溢出或者
#得到不正确的答案。(读者可以用Python尝试相乘许多很小的数,最后四舍五入后会得到0。)一
#种解决办法是对乘积取自然对数。在代数中有ln(a*b) = ln(a)+ln(b),于是通过求对数可以
#避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。图4-4
#给出函数f(x)与ln(f(x))的曲线。检查这两条曲线,就会发现它们在相同区域内同时增加或者
#减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。通过修改return
#前的两行代码,将上述做法用到分类器中:
#'''
p1Vect = log(p1Num / p1Denom)
p0Vect = log(p0Num / p0Denom)
# 对每个元素做除法
# p1Vect = p1Num / p1Denom
# p0Vect = p0Num / p0Denom
# 返回两种类型的算术矩阵和侮辱言论占比
return p0Vect, p1Vect, pAbusive
# 分类函数
# [测试输入语义向量,正常评论词汇概率矩阵,侮辱言论词汇概率矩阵,侮辱言论数据集句子概率]
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
# 侮辱性预判值
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
print('p1:', p1)
# 正常言论预判值
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
print('p0:', p0)
# 比较预判值
if p1 > p0:
return 1
else:
return 0
# 测试函数
def testingNB():
# 初始化数据集中句子和分类
listOPosts, listClasses = loadDataSet()
# 生成词库
myVocabList = createVocabList(listOPosts)
# 初始化语义向量矩阵
trainMat = []
# 遍历所有句子数据,生成测试数据集矩阵
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
# 根据测试数据,求出正常评论词汇概率矩阵 p(x|c0 ),侮辱言论词汇概率矩阵 p(x|c1 ),和 侮辱言论数据集句子先验概率 pc1 pc0=1-pc1
p0V, p1V, pAb = trainNB0(array(trainMat), array(listClasses))
# 测试输入
testEntry = ['love', 'my', 'dalmation']
# 转换成对应语义向量
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
# 打印分类情况
print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb))
# 测试输入
testEntry = ['stupid', 'garbage']
# 转换成对应语义向量
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
# 打印分类情况
print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb))
testingNB()
print('\n')
结果:
p1: -9.826714493730215
p0: -7.694848072384611
['love', 'my', 'dalmation'] classified as: 0
p1: -4.702750514326955
p0: -7.20934025660291
['stupid', 'garbage'] classified as: 1