朴素贝叶斯naive bayes:
先说贝叶斯定理:
有事件A和事件B,
p(AB),发生A也发生B的概率。p(A)发生A的概率。p(B)发生B的概率。
p(A|B),发生B的条件下再发生A的概率。
p(B|A),发生A的条件下再发生B的概率。
根据常识有:
p(AB)=p(A)*p(B|A)=p(B)*p(A|B)
则有:
p(B|A)=p(B)*p(A|B)/p(A)
可以将难计算的概率转化成其他容易计算的概率。
用到分类中,则:
数据集合中,每一行都是一条数据,每一条数据都有多个特征值(x,y,z...)
所以也将每一行称作向量,每个特征值都是向量的一个维度。数据集合就是一个向量集合。
如果:数据w(x,y,z,.....)有类别A和B,
若:p(A|w)>p(B|w),则数据w属于类别A;
则:p(w|A)*p(A)/p(w)>p(w|B)*p(B)/p(w)
则:p(w|A)*p(A)>p(w|B)*p(B)
则:ln(p(w|A)*p(A))>ln(p(w|B)*p(B))
加ln是考虑到概率值都很小,会导致程序下溢出或者无法正确比较大小。
要注意:ln(x*y*z)=ln(x)+ln(y)+ln(z)
朴素贝叶斯就是假设向量w的各个特征值之间相互独立(假设并不符合事实,但会大大减少计算量):
则:p(w|A)=p(x|A)*p(y|A)*(z|A)*.......
# -*- coding: cp936 -*-
from numpy import *
#用样本数据可以训练得到所有特征列表在所有类别下的概率,形成列表,pAList,pBList
#各自乘以数据的特征矢量列表,可以得到数据的特征值在所有类别下的概率。
#乘积即可得到不同类别下数据的特征总概率。
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([])
for document in dataSet:
vocabSet=vocabSet | set(document) #操作符丨用于求两个集合的并集
return list(vocabSet)
def setOfWords2Vec(vocabList,inputSet):
'将单词列表处理成0,1列表,也就是向量'
returnVec=[0]*len(vocabList)#创建一个长度一定、元素都为0的列表。
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]=1
#可将inputSet中的每一个单词列表处理成0和1的列表;
#不过原列表中的顺序信息会丢失。
else:
print('the word:%s is not in my Vocabulary!' %word)
return returnVec
def trainNBO(trainMatrix,trianCategory):
'通过样本数据训练得到各个分类的概率,以及各个分类下所有特征值的概率列表。'
numTrainDocs=len(trainMatrix)
numWords=len(trainMatrix[0])
pAbusive=sum(trianCategory)/float(numTrainDocs)
p0Num=ones(numWords)
#将zeros改成ones,是考虑到总特征概率是每个特征值概率的乘积,
#如果其中有一个特征值概率为0,则总概率就为0,都是0的话就无法比较大小了。
#而且再用log函数时会出错。log指自然对数,以e为底数。log10,以10为底数。
p1Num=ones(numWords)
p0Denom=2.0
p1Denom=2.0
#这种处理叫拉普拉斯平滑,在分子上添加a(一般为1),分母上添加ka(k表示类别总数),
#即在这里将所有词的出现数初始化为1,并将分母初始化为2*1=2
for i in range(numTrainDocs):
if trianCategory[i]==1:
p1Num+=trainMatrix[i]
p1Denom+=sum(trainMatrix[i])
else:
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=log(p1Num/p1Denom)
p0Vect=log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
'贝叶斯分类'
p1=sum(vec2Classify*p1Vec)+log(pClass1)
p0=sum(vec2Classify*p0Vec)+log(1-pClass1)
if p1>p0:
return 1
else:
return 0
def bagOfWords2VecMN(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
def textParse(bigString):
'文本分析'
import re
listOfTokens=re.split(r'\W*',bigString)
#正则表达式模块有很多函数,这里是split函数,\W,匹配非字母;*匹配0或多个。
listOfTokens=[i.lower() for i in listOfTokens if len(i)>2]
#去掉太小的单词,并全部小写。
return listOfTokens
def spamTest():
import os
docList=[]
classList=[]
fullText=[]
path1=r'H:\study\python\machine learning\machinelearninginaction\Ch04\email\spam'
path2=r'H:\study\python\machine learning\machinelearninginaction\Ch04\email\ham'
for i in range(1,26):
wordList=textParse(open(path1+os.sep+'%d.txt' %i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList=textParse(open(path2+os.sep+'%d.txt' %i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList=createVocabList(docList)
trainingSet=range(50)
#一共有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:
trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainNBO(trainMat,trainClasses)
errorCount=0
#对测试样本进行分类,并计算错误率
for docIndex in testSet:
wordVector=setOfWords2Vec(vocabList,docList[docIndex])
if classifyNB(wordVector,p0V,p1V,pSpam)!=classList[docIndex]:
errorCount+=1
print('the error rate is ',float(errorCount)/len(testSet))
if __name__=='__main__':
'''
listOPosts,listClasses=loadDataSet()
myVocabList=createVocabList(listOPosts)
print(myVocabList)
returnVec=setOfWords2Vec(myVocabList,listOPosts[0])
print(returnVec)
returnVec=setOfWords2Vec(myVocabList,listOPosts[1])
print(returnVec)
listOVec=[]
for i in listOPosts:
listOVec.append(setOfWords2Vec(myVocabList,i))
print(listOVec)
list1=[myVocabList[i] for i in range(len(listOVec[0])) if listOVec[0][i]==1]
print(list1)
#'将词向量逆推回单词列表,不过原顺序信息丢失'
listOVec2Vocab=[]
for k in listOVec:
list2=[myVocabList[i] for i in range(len(k)) if k[i]==1]
listOVec2Vocab.append(list2)
print(listOVec2Vocab)
p0V,p1V,pAb=trainNBO(listOVec,listClasses)
print('pAb is ',pAb)
print('p0V is ',p0V)
print('p1V is ',p1V)
test1=['love','my','dalmation']
test2=['stupid','garbage']
vec2Classify1=setOfWords2Vec(myVocabList,test1)
vec2Classify2=setOfWords2Vec(myVocabList,test2)
class1=classifyNB(vec2Classify1,p0V,p1V,pAb)
class2=classifyNB(vec2Classify2,p0V,p1V,pAb)
print('test1 is ',class1)
print('test2 is ',class2)
'''
spamTest()