机器学习实战笔记--朴素贝叶斯(实例代码)
#coding:utf-8
from numpy import *
#加载文档词向量数据以及相应文档类别,0表示正常言论,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]
return postingList,classVec
def createVocabList(dataSet):
'''
功能:将已知类别文档中出现的词汇 存入到 所有词汇集合,相当于字典 返回其list类型
输入数据类型:列表类型(列表中存储的是列表元素,每篇文档的词汇集合)
输出数据类型:列表类型(字典)
'''
vocabSet = 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:
#在此函数中有个小疑问:当词向量在字典中出现,则将该文档的词向量对应词索引处置为1,这里假设每条留言中出现的词汇不重复。但如果该词出现多次呢?不是该相加么。。
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print "the word : %s is not in my Vocabulary!" % word
return returnVec
def trainNB0(trainMatrix, trainCategory):
'''
功能:计算属于1类对应下的所有词汇出现的词频数(词向量形式),用p1Num存放。0类一样。
计算属于1类的所有词汇总数,用p1Denom存放。0类一样。
返回字典词汇的条件概率p0Vect,p1Vect以及文档属于1类的概率pAbusive。p0Vect= [p(w1|c1),p(w2|c1)...p(wn|c1)]
输入的数据类型:array列表类型(样本词向量)
array列表类型(样本对应的类别)
输出的数据类型:列表类型(字典词汇的条件概率0)
列表类型(字典词汇的条件概率1)
浮点数(文档属于1类的概率)
'''
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
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
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
'''
功能:计算贝叶斯概率公式,忽略分母(因为每个类别的分母相等)。计算技巧是分子变形,使相乘的n个数转换为log每个数相加
返回留言板的预测类别。
输入数据类型:列表(词向量形式)
列表(字典词汇的条件概率0)
列表(字典词汇的条件概率1)
浮点数(文档属于1类的概率)
输出数据类型:整数(预测类别)
'''
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1>p0:
return 1
else:
return 0
def tesingNB():
'''
功能:调用以上定义的功能函数,训练分类器然后测试两条数据
'''
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)
#以下这个例子可以作为感兴趣的点。贝叶斯中的0类,1类正负抵消。并不是出现侮辱性词就判定为侮辱类
testEntry = ['love','my','dalmation','stupid']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print testEntry,'Classified as :',classifyNB(thisDoc,p0V,p1V,pAb)
朴素贝叶斯算法之所以称为朴素是因为有个前提假设条件:对于给定样本各属性相互条件独立。也就是说给定一句话 d1=“苹果很好吃”,我们来判定这句话是食物类还是器材类,那如果用朴素贝叶斯算法,就假设了这句话里的每个词(特征)w1=“苹果”,w2=“很”,w3=”好吃”出现的概率是相互独立的,没有依赖的。但我们知道实际上这条假设并不能真正反映现实的规律,因为“苹果”后面往往有很大概率会出现“好吃”,也就是 p(苹果,好吃) = p(苹果)* p(好吃 | 苹果),但我们现在就假设 p(苹果,好吃) = p(苹果)* p(好吃) 。
朴素贝叶斯分类的目标就是实际上已知训练数据,求出它属于哪个类的概率值最大就预测为哪个类。就拿上面的例子所说,食物类是C1,器材类是C2,P(C1|d1)>P(C2|d1) 则把d1判定为C1类,反之。利用贝叶斯公式可知 P(C1|d1) = P(d1|C1)P(C1)/P(d1),目标是比较P(C1|d1)和P(C2|d1)大小,分母是相同的可以忽略。近似比较P(d1|C1)P(C1)和P(d1|C2)P(C2),两个类别的先验概率P(C1)和P(C2)可以根据训练数据集求出,由于以上的假设得 P(d1|C1)=P(w1|C1)P(w2|C1)P(w3|C1),而已知类别下的各个特征条件概率也可以根据训练数据集统计出来,比如P(w1|C1)具体计算就是在C1类别下w1出现的次数/C1类别下出现所有词的总次数。这样就可以通过每项的计算来进行近似比较了。那如果w1在某类下出现的次数为0呢?岂不是条件概率P(d1|C1)就为0了,别急,下面会介绍拉普拉斯估计。下面给出形式化的数学表述:
(据听说数学是世界上最好的语言之一)
设训练样本集分为k类,记为 C= {C1,C2 ,…, Ck},则每个类的先验概率为P(Ci),i=1,2,...,k, 其值为Ci类的样本数除以训练集总样本数n。对于新样本d,其属于Ci类的条件概率是P(d|Ci)。根据贝叶斯定理,Ci类的后验概率为:
P(d)对于所有类均为同一常数,可以忽略。为避免P(Ci)等于0,采用拉普拉斯概率估计:
其中|C|为训练集中类的数目,|Dci|为训练集中属于类Ci的文档数,|Dc|为训练集包含的总文档数。
对于待分类文本文档d,本文采用向量空间模型,其基本思想是将每一个文本表示为一个向量d= (w1,...,wm),m是d的特征词个数。 贝叶斯算法假设各特征词相互独立。
朴素贝叶斯分类器将未知样本归于哪类的依据,如下: