朴素贝叶斯算法及实现 AHU实验

       ps: 实验中本来就有的描述用紫字表示

  • 实验目的

        以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。

  • 实验步骤

        1.创建一个词汇表,并将切分好的词条转换为词条向量

        2.通过词条向量训练朴素贝叶斯分类器。


  1. 创建一个词汇表,并将切分好的词条转换为词条向量

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

# -*- coding: UTF-8 -*-
"""
函数说明:创建实验样本
Parameters:
    无
Returns:
    postingList - 实验样本切分的词条
    classVec - 类别标签向量
"""
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)
#---------测试---------

        补充切分词条的方法:可以使用python的jieba库

        安装jieba,摁键盘的Windows键+R,输入cmd,在打开的窗口中输入如下代码,直接从清华大学镜像中下载,快过下载源文件 或 在 pycharm中使用python interpreter这也是一个检查当前项目中装载了什么包的方法)添加此包等其他一切方法,且稳定性最高。

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba

        jieba分词的使用方法:

import jieba
text = open('分词文件.txt','r').read()
words = jieba.cut(text)
for word in words:
    print(word)

        运行结果:

['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']
[0, 1, 0, 1, 0, 1]

        从运行结果可以看出,我们已经将postingList是存放词条列表中,classVec是存放每个词条的所属类别,1代表侮辱类 ,0代表非侮辱类。
        继续编写代码,前面我们已经说过我们要先创建一个词汇表,并将切分好的词条转换为词条向量。

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

"""
函数说明:根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0
Parameters:
    vocabList - createVocabList返回的列表
    inputSet - 切分的词条列表
Returns:
    returnVec - 文档向量,词集模型
"""
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 - 返回不重复的词条列表,也就是词汇表
"""
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)

         第一个函数中的returnVec[vocabList.index(word)] = 1:列表使用 index(a) 是查找列表中的对应元素 a 第一次出现的位置索引值,返回查找对象的索引位置, 没有找到对象会抛出异常。本句代码让列表returnVec相应位置的值置为1。returnVec的大小是实验样本中过滤重复词条后的词条列表大小,下文解释如何过滤。

        第二个函数中vocabset的类型是set,重复元素在set中自动被过滤,set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的并集操作。另外,可以通过updat(key)的操作添加元素或集合到set中,故第二个函数中的代码亦可以写为:

def createVocabList(dataSet):
    vocabSet = set([])                      #创建一个空的不重复列表
    for document in dataSet:
        vocabSet.update(document) #从遍历取并集变成了遍历更新
    return list(vocabSet)

 运行结果:

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']]
myVocabList:
 ['I', 'ate', 'not', 'please', 'mr', 'flea', 'problems', 'maybe', 'posting', 'to', 'quit', 'my', 'dog', 'dalmation', 'take', 'so', 'love', 'food', 'buying', 'stupid', 'him', 'how', 'has', 'worthless', 'stop', 'licks', 'help', 'park', 'garbage', 'is', 'cute', 'steak']
trainMat:
 [[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]]

        从运行结果可以看出,postingList是原始的词条列表,myVocabList是词汇表。myVocabList是所有单词出现的集合,没有重复的元素。词汇表是用来干什么的?没错,它是用来将词条向量化的,一个单词在词汇表中出现过一次,那么就在相应位置记作1,如果没有出现就在相应位置记作0。trainMat是所有的词条向量组成的列表。它里面存放的是根据myVocabList向量化的词条向量。
        我们已经得到了词条向量。接下来,我们就可以通过词条向量训练朴素贝叶斯分类器。

import numpy as np
from functools import reduce
"""
函数说明:朴素贝叶斯分类器训练函数

Parameters:
    trainMatrix - 训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
    trainCategory - 训练类别标签向量,即loadDataSet返回的classVec
Returns:
    p0Vect - 非侮辱类的条件概率数组
    p1Vect - 侮辱类的条件概率数组
    pAbusive - 文档属于侮辱类的概率
"""
def trainNB0(trainMatrix,trainCategory):
    ### Start Code Here ###
    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):    #统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)
        
        if trainCategory[i] == 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
    #求得各类的概率
    #返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率
    
    ### End Code Here ###
    
    
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)
运行结果:
myVocabList:
 ['I', 'ate', 'not', 'please', 'mr', 'flea', 'problems', 'maybe', 'posting', 'to', 'quit', 'my', 'dog', 'dalmation', 'take', 'so', 'love', 'food', 'buying', 'stupid', 'him', 'how', 'has', 'worthless', 'stop', 'licks', 'help', 'park', 'garbage', 'is', 'cute', 'steak']
p0V:
 [0.04166667 0.04166667 0.         0.04166667 0.04166667 0.04166667
 0.04166667 0.         0.         0.04166667 0.         0.125
 0.04166667 0.04166667 0.         0.04166667 0.04166667 0.
 0.         0.         0.08333333 0.04166667 0.04166667 0.
 0.04166667 0.04166667 0.04166667 0.         0.         0.04166667
 0.04166667 0.04166667]
p1V:
 [0.         0.         0.05263158 0.         0.         0.
 0.         0.05263158 0.05263158 0.05263158 0.05263158 0.
 0.10526316 0.         0.05263158 0.         0.         0.05263158
 0.05263158 0.15789474 0.05263158 0.         0.         0.10526316
 0.05263158 0.         0.         0.05263158 0.05263158 0.
 0.         0.        ]
classVec:
 [0, 1, 0, 1, 0, 1]
pAb:
 0.5

        functools中的reduce:将两个参数的函数累加应用于序列中的项,从左到右,以便将序列减少到单个值。

        p0Num中存放的是非侮辱类文档个数,p0Denom中存放的是非侮辱类文档中的单词总数,p0V存放的就是各个单词属于非侮辱类的条件概率,p1()同理。

  •  评价

        除了文档数量过少分类不准确,文档切分中还有him my 此类词,可以专门准备一个文档去除停用词(一些意义不大的词、过渡词),代码完成了训练集的分类器部分,但没有做到测试及真正的预测。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值