机器学习实战-4朴素贝叶斯

 

贝叶斯公式:p(c_i|w) = \frac{p(w|c_i)p(c_i)}{p(w)}

什么是朴素贝叶斯方法?思想和原理?

判断依据:如果p(c_1|x,y) > p(c_2|x,y),那么属于c1类。如果p(c_1|x,y) < p(c_2|x,y),那么属于c2类。

朴素贝叶斯优点:在数据较少的情况下仍然有效,可以处理多类别问题

缺点:对于输入数据的准备方式较为敏感

适用数据类型:标称型数据

应用:使用朴素贝叶斯法来文档分类

# encoding: utf-8
import numpy as np
from  numpy import *
#4-1词表到向量的转换函数
#loadDataSet()创建了一个实验样本,第一个变量是进行词条切分后的文档集合,第二个变量是一个类别标签的集合
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
#createVocabList()创建一个包含在所有文档中出现的不重复词的列表
def createVocabList(dataSet):
    vocabSet = set([]) #set()函数就是返回一个不包含重复元素的列表
    for document in dataSet:
        vocabSet = vocabSet | set(document)#操作符|相当于两个集合的并集
    return list(vocabSet)
#这个函数第一个输入参数是总样本(字母表),第二个参数是子样本
#该函数的作用是将子样本出现的单词一一在总样本中寻找,若总样本中有,就将此位置的值设为1
#此过程是在一个新的列表中进行的
def setOfWords2Vec(vocabList,inputSet):
    returnVec = [0]*len(vocabList)#创建一个和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

通过类别i(侮辱性留言或非侮辱性留言)中文档数除以总的文档数来计算概率p(ci)。接下来就是计算p(w|ci),这就需要用到朴素贝叶斯假设。如果将w展开为一个个独立特征,那么就可以将上述概率写作p(w0,w1,w2,w3...wN|ci)。这里我们再假设其条件独立性,将其写成p(w0|ci)p(w1|ci)p(w2|ci)p(w3|ci)p(w4|ci)来计算上述概率。

实现的伪代码:

计算每个类别中的文档数目

对每篇训练文档:

      对每个类别:

             如果词条出现在文档中   增加该词条的计数值

             增加所有词条的计数值

对每个类别:

      对每个词条:

           将该词条的数目除以总词条数目得到条件概率

返回每个类别的条件概率

#4-2朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory):#第一个参数为文档矩阵,第二个参数为类别标签
    numTrainDocs = len(trainMatrix)#读取文档的个数,这是一个文档矩阵的长度
    numWords = len(trainMatrix[0])#该文档第一个单词长度
    pAbusive = sum(trainCategory)/float(numTrainDocs)#sum(trainCategory)代表的是所有分类的和
    #p0Num = zeros(numWords);p1Num = zeros(numWords)
    #p0Denom = 0.0; p1Denom = 0.0
    p0Num = ones(numWords);p1Num = ones(numWords)#为什么把注释改成这样?《机器学习实战》P62
    p0Denom = 2.0;p1Denom = 2.0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:#遍历每一个词,若属于侮辱性文档
            p1Num += trainMatrix[i]#将它加入到p1Nm矩阵中
            p1Denom += sum(trainMatrix[i])#该文档的总词数也加1
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    #p1Vect = p1Num/p1Denom#每个元素除以该类别中总词数
    #p0Vect = p0Num/p0Denom
    p1Vect = log(p1Num / p1Denom)#为什么这么改,取对数,防止下溢出
    p0Vect = log(p0Num / p0Denom)
    return p0Vect,p1Vect,pAbusive#p1Vect中每个元素对应的条件概率,pAbusive就是p(ci)先验概率
#4-3朴素贝叶斯分类函数
def classifyNB(vec2Classify, p0Vec,p1Vec,pClass1):#第一个为要分类的向量以及trainNB0计算出的三个概率
    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,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)
#4-4朴素贝叶斯词袋模型,与setOfWords2Vec(词集模型)几乎一样,只不过改成累计数,而不是标1
def bagOfWords2VecMN(vocabList,inpuSet):
    returnVec = [0]*len(vocabList)
    for word in inpuSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    return returnVec

应用:使用朴素贝叶斯法来过滤垃圾邮件

#4-5文件解析及完整的垃圾邮件测试函数
def textParse(bigString):
    listOfTokens = re.split(r'\w*',bigString)
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]#将大写改为小写,返回单词长度大于2的单词
#这个函数首先读取样本,再把样本分别训练样本和测试样本,通过之前写的一系列的函数,朴素贝叶斯方法求出训练样本
#三个概率,然后再一一和测试样本进行比对,进而求出错误率。
def spamTest():
    docList = [];classList = [];fullTest = []
    for i in range(1,26):
        wordList = textParse(open('email/spam/%d.txt' %i).read())
        docList.append(wordList)
        fullTest.extend(wordList)
        classList.append(1)
        #正例
        wordList = textParse(open('email/ham/%d.txt' %i).read())
        docList.append(wordList)
        fullTest.extend(wordList)
        classList.append(0)
        #反例
    vocabList = createVocabList(docList)
    trainingSet = range(50)
    testSet = []
    #第一个for循环,随机选取十个索引,这十个数就是我们随机选取的十个测试样本。
    #所以训练样本要删除这十个数
    for i in range(10):
    #random.uniform(x, y) 方法将随机生成一个实数,它在 [x,y] 范围内。
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])
    trainMat = [];trainClasses = []
    #第二个for循环遍历所有的训练样本分别求出对应的p0V,p1V,pSpm
    for docIndex in trainingSet:
        trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpm = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    #第三个for循环分别对测试样本进行比对,求出错误率
    for docIndex in testSet:
        wordVector = setOfWords2Vec(vocabList, docList[docIndex])
        if classifyNB(array(wordVector),p0V,p1V,pSpm) != classList[docIndex]:
            errorCount += 1
    print 'the error rate is: ',float(errorCount)/len(testSet)

第一个函数textParse接收一个大字符串并将其解析为字符串列表。

append和extend两种列表操作函数有什么区别?

https://www.cnblogs.com/subic/p/6553187.html

发布了30 篇原创文章 · 获赞 29 · 访问量 2228

猜你喜欢

转载自blog.csdn.net/weixin_41938314/article/details/89034867