贝叶斯算法代码实现以及运用实例-垃圾邮件分类

目录

0、前言

1. 存在问题

2、代码实现

        2.1 预处理

        2.2 构建语料库

        2.3  转换词向量

        2.4  训练模块

        2.5 测试模块

         2.6 主模块

3、完整代码及结果

4、说明


0、前言

        阅读本文之前,需要懂得贝叶斯算法的原理,可以参考机器学习算法的另一个分支-贝叶斯算法原理(贝叶斯要解决什么问题)

        本文实现了,贝叶斯算法,包括邮件预处理,将文本转换成词向量,语料库的构建,训练和测试模块实现,即:先验概率的计算,测试邮件在垃圾邮件中和正常邮件的词频统计。

1. 存在问题

        1.1 如果测试邮件的某一个词不在正常邮件(垃圾邮件)的语料库里,那么得到的p(D_i|h-)=0(p(D_i|h+)=0)导致p(D|h-)=0(p(D|h+)=0),这是要不得的。那么解决的方法就是默认每一词的次数都是1开始。

        1.2 在词频统计时每个词出现的次数少,那么得到的概率就变小,那么在进行计算p(D|h-)\;or\;p(D|h+)得到值很小。解决方法就是采用求对数的方式,将值变大,将乘法转换成加法。

2、代码实现

        2.1 预处理

#预处理
def textParse(input_string):
    '''
    把文章转换成词,用list存储
    :param input_string:
    :return:
    '''
    listofTokens = re.split(r'\w+',input_string) #切分单词
    return [tok.lower() for tok in listofTokens if len(listofTokens)>2] #把单词转换成小写

        2.2 构建语料库

def creatVocablist(doclist):
    '''
    生成样本的语料库,把测试的样本生成语料库 用list存储
    :param doclist:
    :return:
    '''
    vocabSet = set([])
    for document in doclist:
        vocabSet = vocabSet|set(document)
    return list(vocabSet)

        2.3  转换词向量

def setOfWord2Vec(vocablist,inputSet):  #词向量
    '''
    把文本转成向量
    :param vocablist: 
    :param inputSet: 
    :return: 
    '''
    returnVec = [0]*len(vocablist) #为方便计算 大小为语料库一样大
    for word in inputSet:
        if word in vocablist:
            returnVec[vocablist.index(word)] = 1 #表示出现
    return  returnVec

        2.4  训练模块

        根据训练集得到先验概率,测试邮件在垃圾邮件中和正常邮件的词频统计。

def trainNB(trainMat,trainClass):
    numTrainDocs = len(trainMat)
    numWords = len(trainMat[0])
    p1 = sum(trainClass)/float(numTrainDocs)
    p0Num = np.ones((numWords)) # 做了一个平滑处理 防止最后结果为0
    p1Num = np.ones((numWords)) # 拉普拉斯平滑
    p0Denom = 2
    p1Denom = 2  #通常情况下都是设置类别个数

    for i in range(numTrainDocs):
        if trainClass[i] == 1: #垃圾邮件
            p1Num += trainMat[i]
            p1Denom += sum(trainMat[i])
        else:
            p0Num += trainMat[i]
            p0Denom += sum(trainMat[i])

    #贝叶斯公式对数变换
    p1Vec = np.log(p1Num/p1Denom)
    p0Vec = np.log(p0Num/p0Denom)
    return p0Vec,p1Vec,p1

        2.5 测试模块

        根据贝叶斯公式得出邮件类别

def classifyNB(wordVec,p0Vec,p1Vec,p1_class):
    '''
    贝叶斯公式转换 化成对数就是加法
    :param wordVec:
    :param p0Vec:
    :param p1Vec:
    :param p1_class:
    :return:
    '''
    p1 = np.log(p1_class) + sum(wordVec*p1Vec)
    p0 = np.log(1.0 - p1_class) + sum(wordVec*p0Vec)
    if p0 > p1:
        return 0
    else:
        return 1

         2.6 主模块

def spam():
    doclist = []
    classlist = []
    for i in range(1,26):
        wordlist = textParse(open('Spam/%d.txt'%i,'r').read())
        doclist.append(wordlist)
        classlist.append(1) #1代表垃圾邮件

        wordlist = textParse(open('Ham/%d.txt' % i, 'r').read())
        doclist.append(wordlist)
        classlist.append(0)  # 0代表正常邮件

    vocablist = creatVocablist(doclist) #语料表
    trainSet = list(range(50))
    testSet = []
    for i in range(10):
        randIndex = int(random.uniform(0,len(trainSet)))
        testSet.append(trainSet[randIndex])
        del (trainSet[randIndex])

    #训练的向量和标签
    trainMat = []
    trainClass = []

    #将文本转换成向量
    for docIndex in trainSet:
        trainMat.append(setOfWord2Vec(vocablist,doclist[docIndex]))
        trainClass.append(classlist[docIndex])

    #分类别统计词频
    p0Vec,p1Vec,p1 = trainNB(np.array(trainMat),np.array(trainClass))
    errorCount = 0
    for docIndex in testSet:
        wordVoc = setOfWord2Vec(vocablist, doclist[docIndex])
        if classifyNB(np.array(wordVoc),p0Vec,p1Vec,p1) != classlist[docIndex]:
            errorCount += 1
    print('当前是{}个测试样本错了'.format(errorCount))

3、完整代码及结果

import numpy as np
import re
import random

#预处理
def textParse(input_string):
    '''
    把文章转换成词,用list存储
    :param input_string:
    :return:
    '''
    listofTokens = re.split(r'\w+',input_string) #切分单词
    return [tok.lower() for tok in listofTokens if len(listofTokens)>2] #把单词转换成小写

def creatVocablist(doclist):
    '''
    生成样本的语料库,把测试的样本生成语料库 用list存储
    :param doclist:
    :return:
    '''
    vocabSet = set([])
    for document in doclist:
        vocabSet = vocabSet|set(document)
    return list(vocabSet)

def setOfWord2Vec(vocablist,inputSet):  #词向量
    '''
    把文本转成向量
    :param vocablist:
    :param inputSet:
    :return:
    '''
    returnVec = [0]*len(vocablist) #为方便计算 大小为语料库一样大
    for word in inputSet:
        if word in vocablist:
            returnVec[vocablist.index(word)] = 1 #表示出现
    return  returnVec

def trainNB(trainMat,trainClass):
    numTrainDocs = len(trainMat)
    numWords = len(trainMat[0])
    p1 = sum(trainClass)/float(numTrainDocs)
    p0Num = np.ones((numWords)) # 做了一个平滑处理 防止最后结果为0
    p1Num = np.ones((numWords)) # 拉普拉斯平滑
    p0Denom = 2
    p1Denom = 2  #通常情况下都是设置类别个数

    for i in range(numTrainDocs):
        if trainClass[i] == 1: #垃圾邮件
            p1Num += trainMat[i]
            p1Denom += sum(trainMat[i])
        else:
            p0Num += trainMat[i]
            p0Denom += sum(trainMat[i])

    #贝叶斯公式对数变换
    p1Vec = np.log(p1Num/p1Denom)
    p0Vec = np.log(p0Num/p0Denom)
    return p0Vec,p1Vec,p1

def classifyNB(wordVec,p0Vec,p1Vec,p1_class):
    '''
    贝叶斯公式转换 化成对数就是加法
    :param wordVec:
    :param p0Vec:
    :param p1Vec:
    :param p1_class:
    :return:
    '''
    p1 = np.log(p1_class) + sum(wordVec*p1Vec)
    p0 = np.log(1.0 - p1_class) + sum(wordVec*p0Vec)
    if p0 > p1:
        return 0
    else:
        return 1

def spam():
    doclist = []
    classlist = []
    for i in range(1,26):
        wordlist = textParse(open('Spam/%d.txt'%i,'r').read())
        doclist.append(wordlist)
        classlist.append(1) #1代表垃圾邮件

        wordlist = textParse(open('Ham/%d.txt' % i, 'r').read())
        doclist.append(wordlist)
        classlist.append(0)  # 0代表正常邮件

    vocablist = creatVocablist(doclist) #语料表
    trainSet = list(range(50))
    testSet = []
    for i in range(10):
        randIndex = int(random.uniform(0,len(trainSet)))
        testSet.append(trainSet[randIndex])
        del (trainSet[randIndex])

    #训练的向量和标签
    trainMat = []
    trainClass = []

    #将文本转换成向量
    for docIndex in trainSet:
        trainMat.append(setOfWord2Vec(vocablist,doclist[docIndex]))
        trainClass.append(classlist[docIndex])

    #分类别统计词频
    p0Vec,p1Vec,p1 = trainNB(np.array(trainMat),np.array(trainClass))
    errorCount = 0
    for docIndex in testSet:
        wordVoc = setOfWord2Vec(vocablist, doclist[docIndex])
        if classifyNB(np.array(wordVoc),p0Vec,p1Vec,p1) != classlist[docIndex]:
            errorCount += 1
    print('当前是{}个测试样本错了'.format(errorCount))

if __name__ == '__main__':
    spam()













4、说明

        本文所用的数据集包括25封正常邮件,25封垃圾邮件

        数据集获取读者可以自行搜索下载。 

        

 

         

 

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值