本文为自己学习机器学习所记笔记,主要参考《统计学习方法》和《机器学习实战》两本书。朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设 的分类方法。
1.统计学基础
条件独立公式,如果X与Y相互独立,
条件概率公式:
可得概率交换公式:
全概率公式:
带入得贝叶斯公式
将Y换成类别,X为特征,那么贝叶斯公式可以理解为:已知特征的情况下,求属于某一类别的概率。
对于不同的种类,公式中的分母都是相同的,因此朴素贝叶斯分类器可以表示为:
即选择使得在特征x下,属于该类别概率最大的类别。因此我们要求的所属类别,需要计算 P(X=x|Y=ck)和P(Y=ck)
P(Y=ck)易求得,而贝叶斯分类器假设各个特征之间相互独立(这是其“朴素”的原因),因此有
这样带入上述公式便可求出y。
2.朴素贝叶斯算法
输入:训练集,其中
,
为第i个样本的第j个特征,
的可能取值为
,
输出:实例x的 分类
(1)计算先验概率及条件概率
(2)对于给定实例x,计算
(3)确定x的类
3.贝叶斯估计
用极大似然估计计算概率时可能会出现由于样本数据不够而导致要估计的概率为零的情况,这显然不合理,解决这一问题的办法是贝叶斯估计,计算条件概率的贝叶斯估计为:
其中Sj为X(j)可取值的数目,,等价于在随机变量各个取值的频数上赋予一个正数
,
时就是极大似然估计,通常取
,这是称为拉普拉斯平滑。
计算先验概率的贝叶斯估计为
4 实例 用朴素贝叶斯过滤垃圾邮件,参考《机器学习实战》
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']]
classVec = [0, 1, 0, 1, 0, 1] # 1 is abusive, 0 not
return postingList, classVec
#创建一个包含所有文档中出现的不重复的词汇列表
def creatVocabList(dataSet):
vocabSet=set()
for document in dataSet:
vocabSet=vocabSet|set(document)
return list(vocabSet)
#输入参数为某个文档的词汇表和待查找词汇表,输出为文档向量,向量的每一元素为0或1,表示词汇表中的单词在文档中是否出现。
def setOfWords2List(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 vocabList!'% word)
return returnVec
#计算在给定文档类别条件下词汇表中单词出现的概率,输入为文档向量矩阵,元素为0和1,类别向量
#输出为不同类别条件下单词出现概率向量
def trainNB0(trainMatrix,labelVec):
numTraindocs=len(trainMatrix)
numWords=len(trainMatrix[0])
pAbusive=sum(labelVec)/float(numTraindocs)
p0num=ones(numWords)
p1num=ones(numWords)
p0Denom=2.0
p1Denom=2.0
for i in range(numTraindocs):
if labelVec[i] == 1:
p1num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect =log(p1num/p1Denom) #change to log()
p0Vect =log(p0num/p0Denom) #change to log()
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2classify,p0v,p1v,pclass1):
p1=sum(vec2classify*p1v)+log(pclass1)
p0=sum(vec2classify*p0v)+log(1-pclass1)
if p1>p0:
return 1
else:
return 0
#词袋向量,可以统计重复出现的词
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
def testingNB():
PostList, classVec = loadDataSet()
print('PostList=', PostList)
vocabList = creatVocabList(PostList)
print('vocabList=', vocabList)
trainMat = []
for postinDoc in PostList:
trainMat.append(setOfWords2List(vocabList, postinDoc))
print('trainMat=', trainMat)
p0v, p1v, pab = trainNB0(trainMat, classVec)
print(p0v, '\n', p1v, '\n', pab)
testEntry=['love','my','dagouzi']
thisDoc=array(setOfWords2List(vocabList,testEntry))
print(testEntry,'classified as :',classifyNB(thisDoc,p0v,p1v,pab))
testEntry=['stupid','garbage']
thisDoc = array(setOfWords2List(vocabList, testEntry))
print(testEntry, 'classified as :', classifyNB(thisDoc, p0v, p1v, pab))
#输入为长string,输出为词汇列表
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('D:\python\code\machinelearninginaction\Ch04\email\spam\%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList=textParse(open('D:\python\code\machinelearninginaction\Ch04\email\ham\%d.txt' % i,encoding='gb18030',errors='ignore').read())
#此处若无‘encoding='gb18030',errors='ignore'’,则会出现编码错误,详见https://blog.youkuaiyun.com/shijing_0214/article/details/51971734
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList=creatVocabList(docList)
trainingSet=list(range(50)); testSet=[]
for i in range(20):
randIndex=int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]; trainClass=[]
for docIndex in trainingSet:
trainMat.append(bagOfWords2VecMN(vocabList,docList[docIndex]))
trainClass.append(classList[docIndex])
p0v,p1v,pspam=trainNB0(array(trainMat),array(trainClass))
errorCount=0
for docIndex in testSet:
wordVec=bagOfWords2VecMN(vocabList,docList[docIndex])
if classifyNB(wordVec,p0v,p1v,pspam)!=classList[docIndex]:
errorCount+=1
print('classification error:',docList[docIndex])
print('Error rate is:',float(errorCount)/len(testSet))
#testingNB()
spamTest()