朴素贝叶斯分类

import  numpy as np
import logging as log

#生成实验样本
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):
    returnVec=np.zeros(len(vocabList)) #生成零向量的array
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)]=1 #有单词,则该位置填充0
        else: print('the word:%s is not in my Vocabulary!'% word)
    return returnVec #返回全为0和1的向量
#词袋模型
def bagOfWords2VecMN(vocabList,inputSet):
    returnVec=[0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)]+=1
    return returnVec #返回非负整数的词向量

def trainNB0(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix) #文档数目
    numWord=len(trainMatrix[0]) #词汇表词数目
    print("numDocs=",numTrainDocs,"numword=",numWord)
    pAbusive=sum(trainCategory)/len(trainCategory) #p1,出现侮辱性评论的概率
    p0Num=np.zeros(numWord);p1Num=np.zeros(numWord)
    p0Demon=0;p1Demon=0
    for i in range(numTrainDocs):
        if trainCategory[i]==0:
            p0Num+=trainMatrix[i] #向量相加
            p0Demon+=sum(trainMatrix[i]) #向量中1累加求和
        else:
            p1Num+=trainMatrix[i]
            p1Demon+=sum(trainMatrix[i])
    print("p0Num=", p0Num)
    print("p1Demon=", p1Demon)
    p0Vec=p0Num/p0Demon
    p1Vec=p1Num/p1Demon
    return p0Vec,p1Vec,pAbusive

def trainNB1(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix)
    numWord=len(trainMatrix[0])
    pAbusive=sum(trainCategory)/len(trainCategory)
    p0Num=np.ones(numWord)
    p1Num=np.ones(numWord)# 初始化为1
    p0Demon=2;p1Demon=2 #初始化为
    for i in range(numTrainDocs):
        if trainCategory[i]==0:
            p0Num+=trainMatrix[i]
            p0Demon+=sum(trainMatrix[i])
        else:
            p1Num+=trainMatrix[i]
            p1Demon+=sum(trainMatrix[i])
    print("p0Num=",p0Num)
    p0Vec=log(p0Num/p0Demon) #对结果求对数
    p1Vec=log(p1Num/p1Demon) #对结果求自然对数
    return p0Vec,p1Vec,pAbusive

if __name__ == '__main__':
   listPosts,listClasses=loadDataSet()
   myVocabList=createVocabList(listPosts)
   print(myVocabList)
   print(setOfWords2Vec(myVocabList,listPosts[0]))
   trainMat=[]
   for postinDoc in listPosts:
       trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
   print("trainMat=",trainMat)
   p0v,p1v,pAb = trainNB0(trainMat,listClasses)
   print("p0v=", p0v)
   print("p1v=", p1v)
   print("pAb=", pAb)
   print("p0v[19]=",p0v[19])
   print("p1v[19]=", p1v[19])

总结:

1.loadDataSet()
获取数据 比如是一些对话内容,我们判断对话内容是否是侮辱性言论
列举出一些侮辱性言论,一些非侮辱性言论,两者数量相当,一个数组标记那一条数据是侮辱性,那些是非侮辱性,这样就有两个数组,一个数组保存这些言论,一个数组存储每一条言论对应的分类,1为侮辱性言论,0为非侮辱性言论。

2.获取言论中所有词组成的一个数组,这里用到了set()函数,创建一个无序不重复元素集,通过|可以得到所有词组成的一个数组vocabList,对应createVocabList()方法.

vocabList = ['cute', 'take', 'stop', 'maybe', 'I', 'licks', 'mr', 'food', 'help', 'not', 'garbage', 'stupid', 'worthless', 'love', 'flea', 'quit', 'buying', 'him', 'posting', 'my', 'to', 'how', 'is', 'please', 'has', 'ate', 'dalmation', 'problems', 'steak', 'dog', 'so', 'park']

3.获取每条言论对应的词向量,向量的维数为整个数据集所有的词的个数,这个词如果在指定的这条言论中出现了,那么对应的词在向量中这个值设为1,由setOfWords2Vec(vocabList,inputSet)方法实现。vocabList为整个数据集中出现的词构成的列表,inputSet为指定的一条言论。下面的就是输出的指定的言论对应的词向量

[0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 1. 0. 0. 0. 1.1. 0. 0. 1. 0. 1. 0. 0.]
这种构建词向量的方法,只记录了每个词是否出现,而没有记录词出现的次数,这样的模型叫做词集模型,如果在词向量中记录词出现的次数,没出现一次,则多记录一次,这样的词向量构建方法,被称为词袋模型

4.将数据集中的每条言论的词向量添加到一个数组,得到trainMat

5.我们已知了每个言论是否为侮辱性言论,可以得到数据中每个词在它所在的分类中出现的概率。所有同一分类的词向量相加,如果用的是词集模型获取的词向量,那么得到的是这个分类中每个词在言论中出现的次数的向量(p0Num,p1Num),同一条言论中的不累加,如果是词袋模型,得到的是每个词在言论中总共出现的次数,同一条言论中是累加的. p0Vec=p0Num/p0Demon为以每个词在这个分类中出现的概率组成的矩阵。比如“love”在vocabList 中的索引是19,p0Vec[19]= 0.041666666666666664,
p1Vec[19]= 0.0即就是love在侮辱性言论中出现的概率为0。
pAbusive=sum(trainCategory)/len(trainCategory),表示文档集中分类为1的文档数目,累加求和将词向量中所有1相加,len求长度函数则对所有0和1进行计数,最后得到分类为1的概率

算法漏洞:

  1. 乘积为0
    我们看到,当某分类下某词项出现频次为0时,其概率也是0,因此在计算p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)会因为其中某个的概率为0而全部是0。
    为了避免这样的情况发生,我们将所有词项出现的频次都初始化为1,某类所有词项数量初始化为2。
  2. 因子太小导致结果溢出问题
    由于p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)中每个因子都很小,所有因子相乘,特别是因子数量多的时候,会导致结果溢出,从而得到错误的数据
    避免溢出问题的发生,可以使用求自然对数的方法,自然对数和原本的数值同增同减,不会有任何损失,因此不会影响求得的概率结果。
def trainNB1(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix)
    numWord=len(trainMatrix[0])
    pAbusive=sum(trainCategory)/len(trainCategory)
    p0Num=np.ones(numWord)
    p1Num=np.ones(numWord)# 初始化为1
    p0Demon=2;p1Demon=2 #初始化为
    for i in range(numTrainDocs):
        if trainCategory[i]==0:
            p0Num+=trainMatrix[i]
            p0Demon+=sum(trainMatrix[i])
        else:
            p1Num+=trainMatrix[i]
            p1Demon+=sum(trainMatrix[i])
    print("p0Num=",p0Num)
    p0Vec=log(p0Num/p0Demon) #对结果求对数
    p1Vec=log(p1Num/p1Demon) #对结果求自然对数
    return p0Vec,p1Vec,pAbusive

用分类函数进行分类,取概率较大者为该言论的分类,分类函数:

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    p1=sum(vec2Classify*p1Vec)+np.log(pClass1)
    p0=sum(vec2Classify*p0Vec)+np.log(1-pClass1)
    if p1>p0:
        return 1
    else:
        return 0

testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as:', classifyNB(thisDoc, p0v, p1v, pAb))
testEntry = ['stupid', 'garbage']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as:', classifyNB(thisDoc, p0v, p1v, pAb))

输出:

['love', 'my', 'dalmation'] classified as: 0
['stupid', 'garbage'] classified as: 1

参考网址:https://blog.csdn.net/moxigandashu/article/details/71480251?locationNum=16&fps=1

你可能感兴趣的:(朴素贝叶斯分类)