机器学习实战之python实现朴素贝叶斯算法

图片.png

关于朴素贝叶斯的理论介绍,请参见下方链接:
带你搞懂朴素贝叶斯分类算法

python代码实现朴素贝叶斯分类算法

'''判断留言是否属于敏感类留言'''
import numpy as np
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] #0代表正常留言,1代表敏感留言
    return postingList,classVec

def createVocabList(dataSet):#利用文本集,生成一个词汇表
    vocabSet = set() #确保词汇表的唯一性
    for document in dataSet:
        vocabSet = vocabSet | set(document)
    return list(vocabSet)

def setofwordsvec(vocabList,inputSet):#检查句中的单词是否在词汇表里存在
    #(词集模型,即只判断该词是否出现)
    returnvec = [0]*len(vocabList) #依据词汇表的长度生成一个全为0的向量
    for word in inputSet:
        if word in vocabList:
            returnvec[vocabList.index(word)] = 1 #如果单词存在词汇表,则将词汇表
            #对应的值设为1
        else:
            print('the word:{}is not in my vocabulary'.format(word))
    return returnvec

def bagofwordsvec(vocabList,inputSet):#检查句中的单词是否在词汇表里存在
    #(词袋模型,统计每个词出现的次数)
    returnvec = [0]*len(vocabList) #依据词汇表的长度生成一个全为0的向量
    for word in inputSet:
        if word in vocabList:
            returnvec[vocabList.index(word)] += 1 #如果单词存在词汇表,则将词汇表
            #对应的值加1
        else:
            print('the word:{}is not in my vocabulary'.format(word))
    return returnvec
#朴素贝叶斯分类器通常有两种实现方式,一种基于贝努利模型实现,一种基于多项式模型实现
#贝努利模型不考虑词出现的次数,只考虑词出不出现,相当于每个词的权重都是一样的
#多项式模型考虑词出现的次数,即给词赋予不一样的权重
    

listOposts,listclasses = loadDataSet()
myvocablist = createVocabList(listOposts)

'''初版    
def trainNBO(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix) #获取有多少条文本
    numWords = len(trainMatrix[0]) #获取文本长度
    pAbusive = np.sum(trainCategory)/float(numTrainDocs)#带有敏感字的文档和是3,
    #除以总文档数,即为是敏感文档的概率p(1)
    p0Num = np.zeros(numWords)#根据文本长度设定一个全0向量
    p1Num = np.zeros(numWords)#这里注意,生成的类型是np.ndarray
    p0Denom = 0
    p1Denom = 0
    for i in range(numTrainDocs):#遍历所有文本
        if trainCategory[i] == 1:#如果对应的标签是1,即敏感文本
            p1Num += trainMatrix[i] #统计文本中所有单词出现的次数
            #因为类型是np.ndarray,所以这里对应位置的值是直接相加的
            p1Denom += np.sum(trainMatrix[i]) #这里统计共有多少词
        else:#因为此例只有两个特征,即0或1,所以if后可直接else,否则要多加判断,
            #且要新增对应的统计变量
            p0Num += trainMatrix[i]
            p0Denom += np.sum(trainMatrix[i])
    p1Vect = p1Num/p1Denom #这里计算敏感文本中,每个词占该类型下所有词的比例,即p(wi|c1)
    p0Vect = p0Num/p0Denom #这是p(wi|c0) #i和0是下标
    return p0Vect,p1Vect,pAbusive
    '''
#根据朴素贝叶斯假设,p(w|c) = p(w1|c)p(w2|c)...p(wn|c),因此我们要避免其中一项为0
#所以上述代码中,p0Num及p1Num的定义我们改为np.ones(numWords),同时将p0Denom和p1Denom初始化为2
#关于p0Vect和p1Vect的定义中,当因子非常小时,该变量值也小,那么p(w|c) = p(w1|c)p(w2|c)...p(wn|c)
#就很有可能下溢或者得不到正确答案,这里我们将其采用自然对数进行处理。改为:p1Vext = np.log(p1Num/p1Denom)
#f(x)和ln(f(x))在趋势上一致

'''优化后'''
def trainNBO(trainMatrix,trainCategory):#计算各类文档概率以及各种词出现在各类文档的概率
    numTrainDocs = len(trainMatrix) #获取有多少条文本
    numWords = len(trainMatrix[0]) #获取文本长度
    pAbusive = np.sum(trainCategory)/float(numTrainDocs)#带有敏感字的文档和是3,
    #除以总文档数,即为是敏感文档的概率p(1)
    p0Num = np.ones(numWords)#根据文本长度设定一个全0向量
    p1Num = np.ones(numWords)#这里注意,生成的类型是np.ndarray
    p0Denom = 0
    p1Denom = 0
    for i in range(numTrainDocs):#遍历所有文本
        if trainCategory[i] == 1:#如果对应的标签是1,即敏感文本
            p1Num += trainMatrix[i] #统计文本中所有单词出现的次数
            #因为类型是np.ndarray,所以这里对应位置的值是直接相加的
            p1Denom += np.sum(trainMatrix[i]) #这里统计共有多少词
        else:#因为此例只有两个特征,即0或1,所以if后可直接else,否则要多加判断,
            #且要新增对应的统计变量
            p0Num += trainMatrix[i]
            p0Denom += np.sum(trainMatrix[i])
    p1Vect = log(p1Num/p1Denom) #这里计算敏感文本中,每个词占该类型下所有词的比例,即p(wi|c1)
    p0Vect = log(p0Num/p0Denom) #这是p(wi|c0) #i和0是下标
    return p0Vect,p1Vect,pAbusive

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):#计算最终概率并对比
    p1 = np.sum(vec2Classify*p1Vec) + np.log(pClass1)#因为转成log了,所以原定理中
    #相乘的部分通过相加实现,另外定理中还有一个分母,这里也没用,是因为要对比的分母是一样的
    #因此,这里只对比分子
    p0 = np.sum(vec2Classify*p0Vec) + np.log(1-pClass1)
    if p1 > p0:
        return 1
    else:
        return 0
    
def testingNB():#定义测试函数
    listOPosts,listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:
        trainMat.append(setofwordsvec(myVocabList,postinDoc))
    p0V,p1V,pAb = trainNBO(np.array(trainMat),np.array(listClasses))
    testEntry = ['love','my','dalmation']
    thisDoc = np.array(setofwordsvec(myVocabList,testEntry))
    print(testEntry,'classified as :',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry = ['stupid','garbage']
    thisDoc = np.array(setofwordsvec(myVocabList,testEntry))
    print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))

示例:使用朴素贝叶斯过滤垃圾邮件

import re
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 = []
    fulltext = []
    for i in range(1,26):#打开所有邮件样本,并汇总其中的文本及词汇
        emailText = open('D:/Anaconda/test/机器学习/Ch04/email/spam/{}.txt'.format(i),encoding='gbk').read()
        wordlist = textParse(emailText)
        doclist.append(wordlist)
        fulltext.extend(wordlist)
        classlist.append(1)
        emailText = open('D:/Anaconda/test/机器学习/Ch04/email/ham/{}.txt'.format(i),encoding='gbk').read()
        wordlist = textParse(emailText)
        doclist.append(wordlist)
        fulltext.extend(wordlist)
        classlist.append(0)
    vocablist = createVocabList(doclist)#建立词汇集
    trainingSet = list(range(50))#总文档数是50
    testSet = []
    for i in range(10):#随机抽取10个文档作为测试集
        randIndex = int(np.random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del trainingSet[randIndex]
    trainMat = []
    trainClasses = []
    for docIndex in trainingSet:#剩下的40个文档为训练集
        trainMat.append(setofwordsvec(vocablist,doclist[docIndex]))
        #将剩下40个文档转化为向量后放入trainMat列表中
        trainClasses.append(classlist[docIndex])#将剩下40个文档的对应类型放到trainClasses列表中
    p0V,p1V,pSpam = trainNBO(np.array(trainMat),np.array(trainClasses))
    #计算概率
    errorCount = 0
    for docIndex in testSet:#利用测试集中的文档验证错误率
        wordVector = setofwordsvec(vocablist,doclist[docIndex])
        if classifyNB(np.array(wordVector),p0V,p1V,pSpam) != classlist[docIndex]:
            errorCount += 1
    print('the error rate is :',float(errorCount)/len(testSet))
    
#随机选择一部分作为训练集,二剩余部分作为测试集的过程称为留存交叉验证
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容