本章内容
使用概率分布进行分类
学习朴素贝叶斯分类器
解析RSS源数据
使用朴素贝叶斯来分析不同地区的态度
朴素贝叶斯
优点:在数据较少的情况下仍然有效,可以处理多类别问题。
缺点:对于输入数据的准备方式较为敏感。
适用数据类型:标称型数据。
朴素贝叶斯是贝叶斯决策理论的一部分。
贝叶斯决策理论的核心思想是:选择具有最高概率的决策。
贝叶斯概率理论:贝叶斯概率引入先验知识和逻辑推理来处理不确定命题。另一种概率解释称为频数概率,它只从数据本身获得结论,并不考虑逻辑推理及先验知识。
使用贝叶斯准则来交换概率中条件与结果:
朴素贝叶斯分类器中的一个假设:每个特征同等重要
示例一:文档分类
朴素贝叶斯的一般过程
(1)收集数据:可以使用任何方法。本章使用RSS源。
(2)准备数据:需要数值型或布尔型数据。
(3)分析数据:有大量特征时,绘制特征作用不大,此时使用直方图效果更好。
(4)训练算法:计算不同的独立特征的条件概率。
(5)测试算法:计算错误率。
(6)使用算法:一个常见的朴素贝叶斯应用是文档分类。可以在任意的分类场景中使用朴素贝叶斯分类器,不一定非要是文本。
'''----------------------------程序一:词集模型(示例1:文档分类)-------------------------------'''
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
'''
@Project -> File :ML_in_action -> bayes
@IDE :PyCharm
@Author :NatW
@Date :2019/11/27 13:58'''
from numpy import *
# 示例1:文档分类
'''将文档看成单词向量或词条向量,先考虑出现在所有文档中的所有单词,再决定将哪些词
纳入词汇表,然后必须要将每一篇文档转换为词汇表上的向量。'''
# 准备数据:从文本中构建词向量
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] #1 代表侮辱性文字,0 代表正常言论
return postingList,classVec
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空集
for document in dataSet:
vocabSet = vocabSet | set(document) # 创建两个集合的并集
return list(vocabSet)
# 词集模型
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print('the world: %s is not in my Vocabulary!'%word)
return returnVec
# 训练算法:从词向量计算概率
# 朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) # 训练的文档数量
numWords = len(trainMatrix[0]) # 每个文档中的单词数量
pAbusive = sum(trainCategory)/float(numTrainDocs) #侮辱性文档出现在总文档中的概率
# p0Num = zeros(numWords); p1Num = zeros(numWords)
# p0Denom = 0.0; p1Denom = 0.0
# 拉普拉斯平滑解决问题:多个乘积相乘,不被一个为零的数影响
p0Num = ones(numWords);p1Num = ones(numWords)
p0Denom = 2.0;p1Denom = 2.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])
# p1Vect = p1Num/p1Denom
# p0Vect = p0Num/p0Denom
# 用对数运算处理下溢出问题
p1Vect = log(p1Num/p1Denom)
p0Vect = log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = sum(vec2Classify*p1Vec)+log(pClass1)
p0 = sum(vec2Classify*p0Vec)+log(1.0-pClass1)
if p1 > p0: return 1
else:return 0
# 测试算法
def testingNB():
# 训练:准备数据
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
# print(myVocabList)
# 测试:训练算法
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
# p0v,p1v,pAb = trainNB0(trainMat,listClasses)
p0v, p1v, pAb = trainNB0(array(trainMat), array(listClasses))
# print(pAb);print(p0v);print(p1v)
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))
if __name__ == '__main__':
testingNB()
示例二:使用朴素贝叶斯过滤垃圾邮件
收集数据:提供文本文件。
准备数据:将文本解析成词条向量
分析数据:检查词条确保解析的正确性
训练算法:使用我们之前建立的trainNB0()函数
测试算法:使用classsifyNB(),并且构建一个新的测试函数来计算文档集的错误率
使用算法:构建一个完整的程序对一组文档进行分类,将错分的文档输出到屏幕上。
from numpy import *
# 示例2:垃圾邮件过滤
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空集
for document in dataSet:
vocabSet = vocabSet | set(document) # 创建两个集合的并集
return list(vocabSet)
# 词集模型
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print('the world: %s is not in my Vocabulary!'%word)
return returnVec
# 词袋模型
def bagOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
# 训练算法:从词向量计算概率
# 朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) # 训练的文档数量
numWords = len(trainMatrix[0]) # 每个文档中的单词数量
pAbusive = sum(trainCategory)/float(numTrainDocs) #侮辱性文档出现在总文档中的概率
# p0Num = zeros(numWords); p1Num = zeros(numWords)
# p0Denom = 0.0; p1Denom = 0.0
# 拉普拉斯平滑解决问题:多个乘积相乘,不被一个为零的数影响
p0Num = ones(numWords);p1Num = ones(numWords)
p0Denom = 2.0;p1Denom = 2.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])
# p1Vect = p1Num/p1Denom
# p0Vect = p0Num/p0Denom
# 用对数运算处理下溢出问题
p1Vect = log(p1Num/p1Denom)
p0Vect = log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = sum(vec2Classify*p1Vec)+log(pClass1)
p0 = sum(vec2Classify*p0Vec)+log(1.0-pClass1)
if p1 > p0: return 1
else:return 0
# 测试算法:使用朴素贝叶斯进行交叉验证
def textParse(bigString):
import re
listOfTokens = re.split(r'\W+',bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
def spamTest():
docList=[];classList=[];fullText=[]
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1) # 垃圾邮件
wordList = textParse(open('email/ham/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0) # 非垃圾广告邮件
vocablist = createVocabList(docList)
trainingSet = list(range(50));testSet = []
for i in range(10):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[];trainClasses=[]
for docIndex in trainingSet:
trainMat.append(setOfWords2Vec(vocablist,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet:
wordVector = setOfWords2Vec(vocablist,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1
errorRate = float(errorCount)/len(testSet)
print('the error rate is: %.3f'%errorRate)
return errorRate
# 测试算法
if __name__ == '__main__':
errorRateSum = 0.0
for i in range(10):
errorRate = spamTest()
errorRateSum += errorRate
errorRateAvg = float(errorRateSum)/10.0
print(errorRateAvg)