1 朴素贝叶斯算法的总结
朴素贝叶斯算法:主要是基于贝叶斯公式进行概率的计算,某类概率较大则判定属于某类型。朴素贝叶斯对条件概率分布做了条件独立性的假设,使得在计算概率使变得简单。在此基础上还有三种基本模型和平滑的处理(后面会讲到)。
2 朴素贝叶斯算法适用场景和优缺点
适用场景:1)文本分类/垃圾文本过滤/情感判别;2)推荐系统:朴素贝叶斯和协同过滤(Collaborative Filtering)是一对好搭档,协同过滤是强相关性,但是泛化能力略弱,朴素贝叶斯和协同过滤一起,能增强推荐的覆盖度和效果。
优点:1)朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率;2)对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练;3)对缺失数据不太敏感,算法也比较简单,常用于文本分类等
缺点:1) 朴素贝叶斯的理论假设使得在真实应用中效果不是很好(除非属性之间的相关性较小);2)先验概率的模型选择会影响先验模型导致预测效果不佳。3)由于通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率等
3 算法过程
首先计算训练样本中的先验概率,再计算其条件概率,然后在计算测试样本时分别计算其概率p,通过判断不同p值的大小来判断其分类。
如: 假如在街上看到一个黑人讲英语,那我们是怎么去判断他来自于哪里?
提取特征:
肤色: 黑 语言: 英语
黑色人种来自非洲的概率: 80% 黑色人种来自于美国的概率:20%
讲英语的人来自于非洲的概率:10% 讲英语的人来自于美国的概率:90%
在我们的自然思维方式中,就会这样判断:
这个人来自非洲的概率:80% * 10% = 0.08
这个人来自美国的概率:20% * 90% =0.18
我们的判断结果就是:此人来自美国
通过这个例子可以发现,前期的数据训练我们是在计算某些条件概率,到应用时直接匹配到特征的概率进行相应的计算即可。
4 具体实例
4.1 实现创建的数据文本,进行简单的语句是不是脏话进行判断
from numpy import *
'''
#词表到向量的转换模式
'''
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']]
#有侮辱性文字为1 否为正常言论
classVec = [0,1,0,1,0,1]
return postingList,classVec
'''
#获得没有重复词汇表的函数
'''
def createVocabList(dataSet):
vocabSet = set([]) #创建一个空集
for document in dataSet:
vocabSet = vocabSet | set(document) #合并连个集合
return list(vocabSet) #返回一个没有重值的列表
'''
#对文档进行向量化的函数
#vocabList :词汇表
#inputSet :某个文档
'''
def setOfWords2Vec(vocabList, inputSet):
#创建同vocabList同样长度的全0列表
returnVec = [0]*len(vocabList)
#针对某篇inpustSet处理
for word in inputSet:
if word in vocabList:
#找到某篇文档的词,其在词表中出现的位置,将其改为1
returnVec[vocabList.index(word)] = 1
else: print ("the word: %s is not in my Vocabulary!") % word
return returnVec #返回一个文档向量
'''
#朴素贝叶斯分类的训练函数
#trainMatrix :文档矩阵
#trainCategory :每篇文档类别标签向量
'''
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #计算训练的文档数目
numWords = len(trainMatrix[0]) #计算每篇文档的词条数
#文档属于侮辱类的概率
pAbusive = sum(trainCategory)/float(numTrainDocs)
#创建numpy.zeros数组,词条出现数初始化
p0Num = ones(numWords); p1Num = ones(numWords)
p0Denom = 2.0; p1Denom = 2.0 #分母初始化为2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1: #类别标签属于侮辱性
#统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)·
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
#统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = log(p1Num/p1Denom)
p0Vect = log(p0Num/p0Denom)
#返回属于侮辱类,非侮辱类的条件概率数组,文档属于侮辱类的概率
return p0Vect,p1Vect,pAbusive
'''
#朴素贝叶斯分类函数
#vec2Classify :要分类的向量
#p0Vec :非侮辱类的条件概率数组
#p1Vec :侮辱类的条件概率数组
#pClass1 : 文档属于侮辱类的概率
'''
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
#元素相乘 这里的 vec2Classify * p1Vec相乘是指矩阵里对应的元素相乘
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1 > p0:
return 1 #返回侮辱性
else:
return 0
"""
#词袋模型:每个单词可以出现多次
# vocabList: 词汇表
# inputSet: 文档向量
"""
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
#找到某篇文档的词在词表中出现的位置,将其改为1,如果重复出现就+1
returnVec[vocabList.index(word)] += 1
return returnVec #包含词汇出现次数信息的文档向量
'''
#朴素贝叶斯分类器测试
'''
def testingNB():
#获取文档集合和文档类别标签的集合
listOPosts,listClasses = loadDataSet()
#得到所有文档中出现的词且不重复的列表
myVocabList = createVocabList(listOPosts)
#建立一个空集用来存储元素为文档向量(该文档向量每一个文档含有所有训练集的词汇)
trainMat=[]
#根据训练集词汇列表,对每个文档的词汇进行检测,输出与词汇列表一样的标称型文档向量
for postinDoc in listOPosts:
#得到训练集文档的标称型文档向量
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
#得到训练集的非侮辱类的条件概率数组、侮辱类的条件概率数组、文档属于侮辱类的概率
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)
以上程序可以在jupyter中实现简单语句的脏话鉴别,只是对此过程做了一个简单的了解并不能识别全部。
4.2 实现垃圾邮件的判别
'''
#字符串解析
'''
def textParse(bigString):
import re #提供各种正则表达式的匹配操作
#解析文本分割成字符串
listOfTokens = re.split(r'\W*', bigString)
#对分割成字符串的文本剔除少于2个字符串的字符
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
'''
#根据贝叶斯算法对垃圾邮件分类自动化处理
'''
def spamTest():
#docList每封邮件的词汇作为元素的列表、classList人为设定的邮件的类别
#fullText所有邮件的词汇列表,一个词作为一个元素
docList=[]; classList = []; fullText =[]
for i in range(1,26): #对25封垃圾邮件和非垃圾邮件进行导入并解析文本文件
#读取垃圾邮件并将其生成词列表
wordList = textParse(open('email/spam/%d.txt' % i).read())
#垃圾邮件词列表作为一个元素存放在docList文档列表中
docList.append(wordList)
#将垃圾邮件里的词汇全部存放在fullText列表中,一个词汇作为一个元素
fullText.extend(wordList)
#用1标记垃圾邮件存放在classList列表中
classList.append(1)
#读取非垃圾邮件并将其生成词列表
wordList = textParse(open('email/ham/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
#建立词典(包括了25封垃圾和非垃圾邮件的词汇长>2)词典里的词不重复
vocabList = createVocabList(docList)
#设置训练长度(共有50封邮件)和创建测试集
trainingSet = range(50); testSet=[]
#随机构建训练集
for i in range(10):
#生成0到50之间的随机数,并将其转换成整型作为索引号
randIndex = int(random.uniform(0,len(trainingSet)))
#将生成的随机整数存放在testSet列表中
testSet.append(trainingSet[randIndex])
#删除trainingSet列表中对应随机生成的索引号的值从而得到训练集索引号
del(trainingSet[randIndex])
#建立trainMat空集用来存储文档向量,建立trainClasses空集用来存储邮件分类向量
trainMat=[]; trainClasses = []
#为分类器准备数据
for docIndex in trainingSet:
#得到针对词汇出现次数训练集计数的文档向量
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
#得到训练集文档对应的类别向量标签
trainClasses.append(classList[docIndex])
#根据训练集得到非垃圾/垃圾邮件类的条件概率数组,文档属于垃圾类的概率
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0 #错误计数初始化
for docIndex in testSet: #分类器测试并测试错误率
#得到关于测试组词汇出现次数的文档向量
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
#检测分类器分类的结果是否与测试集实际的类别一样
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1 #不一样,错误计数加1
#输出分类错误的文档
print "classification error",docList[docIndex]
#输出分类器的错误率
print 'the error rate is: ',float(errorCount)/len(testSet)
此程序添加到上述代码中,下载相应的数据库,可以进行垃圾邮件的识别。
5 贝叶斯当中的三种模型与平滑
5.1 多项式模型
5.2 高斯模型
5.3 伯努利模型
(可以参考:https://blog.csdn.net/u012162613/article/details/48323777/)
5,.4 平滑
不做平滑,当某一维特征的值没在训练样本中出现过时,会导致后验概率为0,加上平滑后可以克服这个问题(多项式模型可平滑/Laplace平滑);还有在计算概率时很多乘数会很小,会导致下溢或的不到正确值,通过取对数可以解决这个问题。