您的位置:首页 > 编程语言 > Python开发

基于概率论的分类方法:朴素贝叶斯

2017-09-01 18:45 453 查看

一 、什么是贝叶斯公式?

贝叶斯公式用来描述两个条件概率之间的关系:P(Y|X)=P(X|Y)P(Y)P(X)

以上公式也可变形为:P(Y,X)=P(Y|X)P(X)=P(X|Y)P(Y)

举例说明:

现分别有 A、B 两个容器,在容器 A 里分别有 7 个红球和 3 个白球,在容器 B 里有 1 个红球和 9 个白球,现已知从这两个容器里任意抽出了一个球,问这个球是红球且来自容器 A 的概率是多少?

假设已经抽出红球为事件 B,选中容器 A 为事件 A,则有:P(B) = 8/20,P(A) = 1/2,P(B|A) = 7/10,按照公式,则有:P(A|B) = (7/10)*(1/2) / (8/20) = 0.875

叶贝斯公司常用来计算已知先验概率求后验概率的情景。

二、什么是朴素叶贝斯公式?

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。即:加上条件独立假设的贝叶斯方法就是朴素贝叶斯方法(Naive
Bayes)。

贝叶斯公式
+ 条件独立假设 = 朴素贝叶斯方法

所谓的独立是统计意义上的独立,即每个条件发生的概率不受其它条件的影响。显然这是一种假设,但朴素贝叶斯的实际效果却很好。

三、使用朴素贝叶斯进行文档分类

(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([])  #创建set空集合,用来存放无重复的样本数据
for document in dataSet:
vocabSet = vocabSet | set(document) #将每篇文章的新词汇添加到集合中
return list(vocabSet)

def setOfWords2Vec(vocabList, inputSet):#判断词汇列表中的词汇是否在每组中,存在返回1,否则返回默认值0
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 Vocabulary!" % word
return returnVec


三个函数的作用分别是:创建样本数据以及人工标注分类标签,1代表有侮辱词汇,0没有;创建无重复单词的词汇列表;把单词转换成向量。

(2)训练算法:从词向量计算概率

def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)#求有侮辱性的分类占总分类的比例
p0Num = zeros(numWords); p1Num = zeros(numWords)      #change to ones()
p0Denom = 0.0; p1Denom = 0.0                        #change to 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:#计算侮辱词汇的数目,trainMatrix为0-1值形成的向量
p1Num += trainMatrix[i] # p1Num存储的是每个词在侮辱分类下出现的次数
p1Denom += sum(trainMatrix[i])# p1Denom存储的是侮辱分类下词的总数目
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num/p1Denom         #计算侮辱词汇分类下每个词出现的概率
p0Vect = p0Num/p0Denom         #计算非侮辱词汇分类下每个词出现的概率
return p0Vect,p1Vect,pAbusive
该函数是用来计算每个词汇在1和0两大分类情况下的概率,返回的p0Vect,p1Vect结果如图所示:



但因为在计算多个概率的乘积时,其中有一个概率为0,那么最后的概率也为0,所以我们可以把所有词初始化为1,分母初始化为2.

p0Num = ones(numWords); p1Num = ones(numWords)
p0Denom = 2.0; p1Denom = 2.0
此外,如果很多小概率数字相乘会出现下溢问题,所以我们对乘积取自然对数,

p1Vect = log(p1Num/p1Denom)
p0Vect = log(p0Num/p0Denom)
进行如上操作后会得到与原始数据同等增加或减少的图像



(3)构造朴素贝叶斯分类函数:

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,listClass = loadDataSet()
# 创建词汇列表
myVocabList = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClass))
# print p0V,p1V,pAb
# print trainMat
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)
两个函数分别构建了分类函数和测试函数,最后选择一些数据集进行测试,并返回概率大的标签。


、应用:用朴素贝叶斯过滤垃圾邮件


朴素贝叶斯最大的应用便是用来过滤垃圾邮件,我们选择25封垃圾邮件和25份非垃圾邮件使用算法根据以下步骤过滤垃圾邮件:

(1)收集数据:提供文本文件,下载地址:http://download.csdn.net/detail/liyuefeilong/9106481

(2)准备数据:将文本文件解析成词条向量;

(3)分析数据:检查词条确保解析的正确性;

(4)训练算法:使用我们之前建立的trainNB0()函数;

(5)测试算法:使用函数classifyNB(),并且构建一个新的测试函数来计算文档集的错误率;

 使用算法:构建一个完整的程序对一组文档进行分类,将错分的文档输出到屏幕上。

代码的Python语言实现如下:注意我们随机选择10个邮件作为测试集,用算法得到的分类标签与已知的分类标签比较,不相同则错误率加一。因为随机选择,所以每次运行的结果的不同,我们取十次的运行结果取平均值,得到错误率约为0.6.

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所有文档词汇
docList=[]; classList = []; fullText =[]
for i in range(1,26):#导入并解析文件,spam为1,ham为0
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):#随机选取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))
#print trainClasses 训练集邮件(40份)的分类结果,也就是正确的分类,classList根据文件名判断
errorCount = 0
for docIndex in testSet: #从测试集中遍历邮件
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
print classifyNB(array(wordVector),p0V,p1V,pSpam)#调用classifyNB()分类函数,输出测试模型的分类结果
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:#注意docIndex是取自测试集
errorCount += 1
print "classification error",docList[docIndex]
print 'the error rate is: ',float(errorCount)/len(testSet)
此外,要注意textParse()函数是对文本文件进行分词,单词长度小于2自动舍弃,最后的运行结果如图所示:

 


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息