本文主要介绍一下内容:1贝叶斯,2 朴素贝叶斯的推导,3 最大似然估计的推到过程,4朴素贝叶斯的计算步骤 ,5 贝叶斯估计
假设有两类数据p1(x,y)表示(x,y)属于类别1,用p2(x,y)表示(x,y)属于类别2,那么对于一个新的数据集(x,y),可以根据一下规则来判断他的类别
1.如果p1(x,y)>p2(x,y),则(x,y)属于类别1
2.如果p2(x,y)>p1(x,y),则(x,y)属于类别2
也就是说,我们会选择具有最高概率的决策,这就是贝叶斯决策理论的核心思想通常,事件A在事件B(发生)的条件下的概率,与事件B在事件A的条件下的概率是不一样的;然而,这两者是有确定的关系,贝叶斯法则就是这种关系的陈述。作为一个规范的原理,贝叶斯法则对于所有概率的解释是有效的;然而,频率主义者和贝叶斯主义者对于在应用中概率如何被赋值有着不同的看法:频率主义者根据随机事件发生的频率,或者总体样本里面的个数来赋值概率;贝叶斯主义者要根据未知的命题来赋值概率。一个结果就是,贝叶斯主义者有更多的机会使用贝叶斯法则。
朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类
用极大似然估计可能会出现所要估计的概率值为0的情况,这时会影响到后验概率的影响结果,使分类产生误差解决这一问题的方法是采用贝叶斯估计
等价于在随机变量各个取值的频数上赋予一个正数,值为0时为极大似然估计,值为1是为拉普拉斯平滑至此朴素贝叶斯的基本原理均介绍完成,后续会增加朴素贝叶斯的python实现
以下代码参照机器学习实战第四章,
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 createVocabList(dataSet):
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) #union of the two sets
return list(vocabSet)#生成一个包含所有单词的列表
#数输参数是文档,输出参数是变量,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 word: %s is not in my Vocabulary!" % word
return returnVec #生成词集向量
#原始的计算需要多项相乘,这样如果其中一项为0 ,则影响整体,因此初始化数据分子为1分母为2
#令一种情况为下溢出问题,即一些很小的数据相乘四舍五入会得到0结果,因此一种处理方法为取对数
#def trainNB0(postingList,trainCategory):
# trainMatrix=[]
# for p in postingList:
# trainMatrix.append(setOfWords2Vec(myVocablist, p))
# print trainMatrix[2]
# numTrainDocs = len(trainMatrix)#取行6
# numWords = len(trainMatrix[0])#取列32
# pAbusive = sum(trainCategory)/float(numTrainDocs)#出现侮辱性文档的概率,包含侮辱性句子/所有句子
# p0Num = zeros(numWords)#生成一个包含单词个数的列表,值均为0
# p1Num = zeros(numWords) #生成一个包含单词个数的列表,值均为0 #change to ones()
# p0Denom = 0.0
# p1Denom = 0.0 #change to 2.0
# for i in range(numTrainDocs):
# if trainCategory[i] == 1:#类别为1
# p1Num += trainMatrix[i]#各变量均增加1
# p1Denom += sum(trainMatrix[i])#每次变量中发生的次数
# else:
# p0Num += trainMatrix[i]
# p0Denom += sum(trainMatrix[i])
# p1Vect = p1Num/p1Denom #change to log()
# p0Vect = p0Num/p0Denom #change to log()
# return p0Vect,p1Vect,pAbusive
#
#词袋模型,每个词可以多次出现
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
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 = ones(numWords); p1Num = ones(numWords) #change to ones()
p0Denom = 2.0; p1Denom = 2.0 #避免其中一项为0的影响
#change to 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 = log(p1Num/p1Denom) #避免下溢出问题 #change to log()
p0Vect = log(p0Num/p0Denom) #change to log()
return p0Vect,p1Vect,pAbusive
#计算属于类别1和类别0的概率,把数据进行分类
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)#生成一个包含所有单词的列表
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) #测试结果
#文本解析,把大写转小写,且去掉长度小于2的字符
def textParse(bigString): #input is big string, #output is word list
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 = 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:#train the classifier (get probs) trainNB0
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet: #classify the remaining items
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1
print "classification error",docList[docIndex]
print 'the error rate is: ',float(errorCount)/len(testSet)
#return vocabList,fullText
if __name__=='__main__':
spamTest()