美文网首页
机器学习实战教程(四):朴素贝叶斯基础篇之论过滤器(b)

机器学习实战教程(四):朴素贝叶斯基础篇之论过滤器(b)

作者: 公子曼步 | 来源:发表于2020-10-24 21:11 被阅读0次

    三、动手实战

    说了这么多,没点实践编程怎么行?

    以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。过滤这类内容是一个很常见的需求。对此问题建立两个类型:侮辱类和非侮辱类,使用1和0分别表示。

    我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。简单起见,我们先假设已经将本文切分完毕,存放到列表中,并对词汇向量进行分类标注。编写代码如下:

    # -*- coding: UTF-8 -*-

    """

    函数说明:创建实验样本

    Parameters:

        无

    Returns:

        postingList - 实验样本切分的词条

        classVec - 类别标签向量

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    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

    if __name__ == '__main__':

        postingLIst, classVec = loadDataSet()

        for each in postingLIst:

            print(each)

        print(classVec)

    从运行结果可以看出,我们已经将postingList是存放词条列表中,classVec是存放每个词条的所属类别,1代表侮辱类 ,0代表非侮辱类。

    免费视频教程:www.mlxs.top      

    继续编写代码,前面我们已经说过我们要先创建一个词汇表,并将切分好的词条转换为词条向量。

    # -*- coding: UTF-8 -*-

    """

    函数说明:创建实验样本

    Parameters:

        无

    Returns:

        postingList - 实验样本切分的词条

        classVec - 类别标签向量

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    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

    """

    函数说明:根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

    Parameters:

        vocabList - createVocabList返回的列表

        inputSet - 切分的词条列表

    Returns:

        returnVec - 文档向量,词集模型

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    def setOfWords2Vec(vocabList, inputSet):

        returnVec = [0] * len(vocabList)                                    #创建一个其中所含元素都为0的向量

        for word in inputSet:                                                #遍历每个词条

            if word in vocabList:                                            #如果词条存在于词汇表中,则置1

                returnVec[vocabList.index(word)] = 1

            else: print("the word: %s is not in my Vocabulary!" % word)

        return returnVec                                                    #返回文档向量

    """

    函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

    Parameters:

        dataSet - 整理的样本数据集

    Returns:

        vocabSet - 返回不重复的词条列表,也就是词汇表

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    def createVocabList(dataSet):

        vocabSet = set([])                      #创建一个空的不重复列表

        for document in dataSet:             

            vocabSet = vocabSet | set(document) #取并集

        return list(vocabSet)

    if __name__ == '__main__':

        postingList, classVec = loadDataSet()

        print('postingList:\n',postingList)

        myVocabList = createVocabList(postingList)

        print('myVocabList:\n',myVocabList)

        trainMat = []

        for postinDoc in postingList:

            trainMat.append(setOfWords2Vec(myVocabList, postinDoc))

        print('trainMat:\n', trainMat)

            从运行结果可以看出,postingList是原始的词条列表,myVocabList是词汇表。myVocabList是所有单词出现的集合,没有重复的元素。词汇表是用来干什么的?没错,它是用来将词条向量化的,一个单词在词汇表中出现过一次,那么就在相应位置记作1,如果没有出现就在相应位置记作0。trainMat是所有的词条向量组成的列表。它里面存放的是根据myVocabList向量化的词条向量。

    免费视频教程:www.mlxs.top      

    我们已经得到了词条向量。接下来,我们就可以通过词条向量训练朴素贝叶斯分类器。

    # -*- coding: UTF-8 -*-

    import numpy as np

    """

    函数说明:创建实验样本

    Parameters:

        无

    Returns:

        postingList - 实验样本切分的词条

        classVec - 类别标签向量

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    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

    """

    函数说明:根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

    Parameters:

        vocabList - createVocabList返回的列表

        inputSet - 切分的词条列表

    Returns:

        returnVec - 文档向量,词集模型

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    def setOfWords2Vec(vocabList, inputSet):

        returnVec = [0] * len(vocabList)                                    #创建一个其中所含元素都为0的向量

        for word in inputSet:                                                #遍历每个词条

            if word in vocabList:                                            #如果词条存在于词汇表中,则置1

                returnVec[vocabList.index(word)] = 1

            else: print("the word: %s is not in my Vocabulary!" % word)

        return returnVec                                                    #返回文档向量

    """

    函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

    Parameters:

        dataSet - 整理的样本数据集

    Returns:

        vocabSet - 返回不重复的词条列表,也就是词汇表

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    def createVocabList(dataSet):

        vocabSet = set([])                      #创建一个空的不重复列表

        for document in dataSet:

            vocabSet = vocabSet | set(document) #取并集

        return list(vocabSet)

    """

    函数说明:朴素贝叶斯分类器训练函数

    Parameters:

        trainMatrix - 训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵

        trainCategory - 训练类别标签向量,即loadDataSet返回的classVec

    Returns:

        p0Vect - 非侮辱类的条件概率数组

        p1Vect - 侮辱类的条件概率数组

        pAbusive - 文档属于侮辱类的概率

    Author:

        Jack Cui

    Modify:

        2017-08-12

    """

    def trainNB0(trainMatrix,trainCategory):

        numTrainDocs = len(trainMatrix)                            #计算训练的文档数目

        numWords = len(trainMatrix[0])                            #计算每篇文档的词条数

        pAbusive = sum(trainCategory)/float(numTrainDocs)        #文档属于侮辱类的概率

        p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)    #创建numpy.zeros数组,词条出现数初始化为0

        p0Denom = 0.0; p1Denom = 0.0                            #分母初始化为0

        for i in range(numTrainDocs):

            if trainCategory[i] == 1:                            #统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···

                p1Num += trainMatrix[i]

                p1Denom += sum(trainMatrix[i])

            else:                                                #统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···

                p0Num += trainMatrix[i]

                p0Denom += sum(trainMatrix[i])

        p1Vect = p1Num/p1Denom                                     

        p0Vect = p0Num/p0Denom       

        return p0Vect,p1Vect,pAbusive                            #返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率

    if __name__ == '__main__':

        postingList, classVec = loadDataSet()

        myVocabList = createVocabList(postingList)

        print('myVocabList:\n', myVocabList)

        trainMat = []

        for postinDoc in postingList:

            trainMat.append(setOfWords2Vec(myVocabList, postinDoc))

        p0V, p1V, pAb = trainNB0(trainMat, classVec)

        print('p0V:\n', p0V)

        print('p1V:\n', p1V)

        print('classVec:\n', classVec)

        print('pAb:\n', pAb)

              运行结果如下,p0V存放的是每个单词属于类别0,也就是非侮辱类词汇的概率。比如p0V的倒数第6个概率,就是stupid这个单词属于非侮辱类的概率为0。同理,p1V的倒数第6个概率,就是stupid这个单词属于侮辱类的概率为0.15789474,也就是约等于15.79%的概率。我们知道stupid的中文意思是蠢货,难听点的叫法就是傻逼。显而易见,这个单词属于侮辱类。pAb是所有侮辱类的样本占所有样本的概率,从classVec中可以看出,一用有3个侮辱类,3个非侮辱类。所以侮辱类的概率是0.5。因此p0V存放的就是P(him | 非侮辱类) = 0.0833,P(is | 非侮辱类) = 0.0417,一直到P(dog | 非侮辱类) = 0.0417,这些单词的条件概率。同理,p1V存放的就是各个单词属于侮辱类的条件概率。pAb就是先验概率。

    免费视频教程:www.mlxs.top      

    已经训练好分类器,接下来,使用分类器进行分类。

    # -*- coding: UTF-8 -*-

    import numpy as np

    from functools import reduce

    """

    函数说明:创建实验样本

    Parameters:

        无

    Returns:

        postingList - 实验样本切分的词条

        classVec - 类别标签向量

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    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                                                                #返回实验样本切分的词条和类别标签向量

    """

    函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

    Parameters:

        dataSet - 整理的样本数据集

    Returns:

        vocabSet - 返回不重复的词条列表,也就是词汇表

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    def createVocabList(dataSet):

        vocabSet = set([])                      #创建一个空的不重复列表

        for document in dataSet:               

            vocabSet = vocabSet | set(document) #取并集

        return list(vocabSet)

    """

    函数说明:根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

    Parameters:

        vocabList - createVocabList返回的列表

        inputSet - 切分的词条列表

    Returns:

        returnVec - 文档向量,词集模型

    Author:

        Jack Cui

    Modify:

        2017-08-11

    """

    def setOfWords2Vec(vocabList, inputSet):

        returnVec = [0] * len(vocabList)                                    #创建一个其中所含元素都为0的向量

        for word in inputSet:                                                #遍历每个词条

            if word in vocabList:                                            #如果词条存在于词汇表中,则置1

                returnVec[vocabList.index(word)] = 1

            else: print("the word: %s is not in my Vocabulary!" % word)

        return returnVec                                                    #返回文档向量

    """

    函数说明:朴素贝叶斯分类器训练函数

    Parameters:

        trainMatrix - 训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵

        trainCategory - 训练类别标签向量,即loadDataSet返回的classVec

    Returns:

        p0Vect - 非侮辱类的条件概率数组

        p1Vect - 侮辱类的条件概率数组

        pAbusive - 文档属于侮辱类的概率

    Author:

        Jack Cui

    Modify:

        2017-08-12

    """

    def trainNB0(trainMatrix,trainCategory):

        numTrainDocs = len(trainMatrix)                            #计算训练的文档数目

        numWords = len(trainMatrix[0])                            #计算每篇文档的词条数

        pAbusive = sum(trainCategory)/float(numTrainDocs)        #文档属于侮辱类的概率

        p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)    #创建numpy.zeros数组,

        p0Denom = 0.0; p1Denom = 0.0                            #分母初始化为0.0

        for i in range(numTrainDocs):

            if trainCategory[i] == 1:                            #统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···

                p1Num += trainMatrix[i]

                p1Denom += sum(trainMatrix[i])

            else:                                                #统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···

                p0Num += trainMatrix[i]

                p0Denom += sum(trainMatrix[i])

        p1Vect = p1Num/p1Denom                                    #相除       

        p0Vect = p0Num/p0Denom         

        return p0Vect,p1Vect,pAbusive                            #返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率

    """

    函数说明:朴素贝叶斯分类器分类函数

    Parameters:

        vec2Classify - 待分类的词条数组

        p0Vec - 侮辱类的条件概率数组

        p1Vec -非侮辱类的条件概率数组

        pClass1 - 文档属于侮辱类的概率

    Returns:

        0 - 属于非侮辱类

        1 - 属于侮辱类

    Author:

        Jack Cui

    Modify:

        2017-08-12

    """

    def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):

        p1 = reduce(lambda x,y:x*y, vec2Classify * p1Vec) * pClass1                #对应元素相乘

        p0 = reduce(lambda x,y:x*y, vec2Classify * p0Vec) * (1.0 - pClass1)

        print('p0:',p0)

        print('p1:',p1)

        if p1 > p0:

            return 1

        else:

            return 0

    """

    函数说明:测试朴素贝叶斯分类器

    Parameters:

        无

    Returns:

        无

    Author:

        Jack Cui

    Modify:

        2017-08-12

    """

    def testingNB():

        listOPosts,listClasses = loadDataSet()                                    #创建实验样本

        myVocabList = createVocabList(listOPosts)                                #创建词汇表

        trainMat=[]

        for postinDoc in listOPosts:

            trainMat.append(setOfWords2Vec(myVocabList, postinDoc))                #将实验样本向量化

        p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))        #训练朴素贝叶斯分类器

        testEntry = ['love', 'my', 'dalmation']                                    #测试样本1

        thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))                #测试样本向量化

        if classifyNB(thisDoc,p0V,p1V,pAb):

            print(testEntry,'属于侮辱类')                                        #执行分类并打印分类结果

        else:

            print(testEntry,'属于非侮辱类')                                        #执行分类并打印分类结果

        testEntry = ['stupid', 'garbage']                                        #测试样本2

        thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))                #测试样本向量化

        if classifyNB(thisDoc,p0V,p1V,pAb):

            print(testEntry,'属于侮辱类')                                        #执行分类并打印分类结果

        else:

            print(testEntry,'属于非侮辱类')                                        #执行分类并打印分类结果

    if __name__ == '__main__':

        testingNB()

    我们测试了两个词条,在使用分类器前,也需要对词条向量化,然后使用classifyNB()函数,用朴素贝叶斯公式,计算词条向量属于侮辱类和非侮辱类的概率。运行结果如下:

    免费视频教程:www.mlxs.top      

    你会发现,这样写的算法无法进行分类,p0和p1的计算结果都是0,显然结果错误。这是为什么呢?下一篇文章继续讲解~

    四、总结

    朴素贝叶斯推断的一些优点:

    生成式模型,通过计算概率来进行分类,可以用来处理多分类问题。

    对小规模的数据表现很好,适合多分类任务,适合增量式训练,算法也比较简单。

    朴素贝叶斯推断的一些缺点:

    对输入数据的表达形式很敏感。

    由于朴素贝叶斯的“朴素”特点,所以会带来一些准确率上的损失。

    需要计算先验概率,分类决策存在错误率。免费视频教程:www.mlxs.top    

    相关文章

      网友评论

          本文标题:机器学习实战教程(四):朴素贝叶斯基础篇之论过滤器(b)

          本文链接:https://www.haomeiwen.com/subject/chmwmktx.html