机器学习实战之朴素贝叶斯naive bayes

朴素贝叶斯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)

可以将难计算的概率转化成其他容易计算的概率。

用到分类中,则:

机器学习实战之朴素贝叶斯naive bayes

数据集合中,每一行都是一条数据,每一条数据都有多个特征值(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()