原理
举例:
1、出处:
正常思路:一个不透明的盒子中,黑球N个,白球M个==>取到黑球的概率,取到白球的概率
逆向思路:已知取到黑球的概率、白球的概率==>白球的个数,黑球的个数
2、推导公式:
学校的人数U,男生穿长裤,女生穿长裤或裙子==>穿长裤的女生的概率
P(Boy),P(Girl),P(Pants),P(Dress)是可以直接得到的
P(Girl|Pants)=P(Pants,Girl)/P(Pants)=P(Pants|Girl)P(Girl)/P(Pants)
P(Pants)=P(Boy)P(Pants|Boy)+P(Girl)P(Pants|Girl)
3、当所求的条件概率较难时,转换成条件概率
P(A|B)=P(AB)/P(B)=P(B|A)P(A)/P(B)
垃圾邮件处理:
1、宏观
下面的算法介绍,共有50篇邮件,25篇垃圾邮件,25篇正常邮件,有监督分类:
分类40篇训练数据,10篇测试
2、微观
D:表示一篇邮件,由N个单词组成,h+表示垃圾邮件,h-表示正常邮件
P(h+|D),P(h-|D)对比大小,判断时正常还是垃圾
P(h+|D)=P(D|h+)P(h+)/P(D)
P(D|h+)=P(d1,d2,…,dN|h+)链式求解
=P(d1|h+)P(d2|d1,h+)…P(dN|d1,d2,…,dN-1,h+)
朴素贝叶斯算法:每一个词都是独立存在,相互之间时没有关系的
所以可以化简为
=P(d1|h+)P(d2|h+)…P(dN|h+)
算法
1、流程图
2、基础准备:
1、主程序:
def spam():
#1、进行数据读取
doclist=[]#存放数据
classlist=[]#存放标签
error=[]#存放预测错误的列表
for i in range(1,26):#每个都有26个邮件
wordlist=textParse(open('email/spam/%d.txt' % i,'r').read())#将读取的数据分割
doclist.append(wordlist)
classlist.append(1)#1表示垃圾邮件
wordlist = textParse(open('email/ham/%d.txt' % i, 'r').read())
doclist.append(wordlist)
classlist.append(0) # 0表示正常邮件
#2、创建语料表,统计一下出现的词总共有哪些
vocablist=creatVocablist(doclist)
trainSet=list(range(50))#先将所有都作为训练集合
testSet=[]#测试列表初始化
#随机挑选10个测试数据,作为测试数据,从训练集中剔除
for i in range(10):#当前个数
randIndex=int(random.uniform(0,len(trainSet)))
testSet.append(trainSet[randIndex])#训练集中剔除的数据作为测试集
del (trainSet[randIndex])#将随机选择的值,从训练集中剔除
#3、进行训练啦
trainMat=[]#训练矩阵
trainClass=[]#训练标签
#将当前的一句话转换成向量
#1、训练模块只计算概率值
#2、转化成向量,当作一个函数书写
for docIndex in trainSet:
#进行向量填充
trainMat.append(setOfWord2Vec(vocablist,doclist[docIndex]))#将训练的数据转成向量存储
#list标为1,
trainClass.append(classlist[docIndex])#训练的标签
p0Vec,p1Vec,p1=trainNB(np.array(trainMat),np.array(trainClass))
#测试数据
errorCount=0#统计错误的数量
for docIndex in testSet:
wordVec=setOfWord2Vec(vocablist,doclist[docIndex])
if classifyNB(np.array(wordVec),p0Vec,p1Vec,p1)!=classlist[docIndex]:#预测与标签对比
errorCount+=1
error.append(docIndex)
print('当前10个测试样本,错了:', errorCount)
print("testSet:",testSet)
print('error:',error)
2、分解单词
用正则表达式
def textParse(input_string):
listofToken=re.split(r'\W+',input_string)#将所有字符进行切分
return [tok.lower() for tok in listofToken if len(listofToken)>2]#将字符转换成小写
3、创建语料库
def creatVocablist(doclist):
vocabSet=set([])#每个词都是不重复的,直接用集合
for document in doclist:
vocabSet=vocabSet | set(document)#将两者取成一个
return list(vocabSet)
4、将文章转换成向量存储:
def setOfWord2Vec(vocablist, inputSet):
#直接创建语料库大小的列表,出现的单词置为1
returnVec=[0]*len(vocablist)#保证每一遍做出了的向量都是相同的,用语料表的大小来表示
for word in inputSet:#[0]*len(vocabList)列表*一个常数,则列表扩宽原来的常数被,内部的值重复
if word in vocablist:
returnVec[vocablist.index(word)]=1
# 若单词出现在语料库,就将单词设置为1
return returnVec
5、训练数据:
分别计算正常和垃圾,语料库中的单词所出现的概率
# p0Vec,p1Vec,p1=trainNB(np.array(trainMat),np.array(trainClass))调用方式和返回值表示
def trainNB(trainMat, trainClass):
numTrainDocs=len(trainMat)#训练的矩阵的长度40
numWords=len(trainMat[0])#是语料库的大小
#trainMat=40*769
#p1是垃圾邮件,标注为1的
p1=sum(trainClass)/float(numTrainDocs)#训练集中的垃圾邮件所占的比例P(h+)
# p0=1-p1#训练集中正常邮件所占概率P(h-)
#为什么要为1?因为一旦出现某一个单词是0,那么概率相乘直接为0
p0Num=np.ones((numWords))#平滑处理,不能为0,创建语料库大小的769
p1Num=np.ones((numWords))#拉普拉斯平滑
p0Denom=2#通常设置为类别的个数
p1Denom=2
for i in range(numTrainDocs):#总共40个
if trainClass[i]==1:#为垃圾的时候
p1Num+=trainMat[i]
p1Denom+=sum(trainMat[i])
else:
p0Num+=trainMat[i]
p0Denom+=sum(trainMat[i])
#为什么为log?因为连乘转换成log就是连加,且概率都是小于1的数,连乘太小
p1Vec=np.log(p1Num/p1Denom)#得到的概率很小,相乘几乎为0
#不需要确切的值 ,只需要相对的大小值,取对数进行了放大
p0Vec=np.log(p0Num/p0Denom)
return p0Vec,p1Vec,p1
6、测试数据
def classifyNB(wordVec, p0Vec, p1Vec, p1_class):
# 转换成log,所有相加就可以,测试的文章的向量wordvec与
p1 = np.log(p1_class) + sum(wordVec * p1Vec)#垃圾邮件各个单词所占的概率
p0=np.log(1.0-p1_class)+sum(wordVec*p0Vec)#正常邮件各个单词所占的概率
if p0>p1:
return 0
else:
return 1