朴素贝叶斯——垃圾邮件分类

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

        垃圾邮件是否一直困扰着你,贝叶斯公式,给予你求得这是否为垃圾文件的概率,减少你打开才发现这是垃圾的烦恼!


相关内容

一、贝叶斯公式

贝叶斯公式是用来描述两个条件概率之间的关系,比如 P(A|B) 和 P(B|A)。

(1)条件概率公式

设A,B是两个事件,且P(B)>0,则在事件B发生的条件下,事件A发生的条件概率为:

P(A|B)=P(AB)/P(B)

(2)由条件概率公式得出乘法公式: P(AB)=P(A|B)P(B)=P(B|A)P(A)

P(A|B) = P(AB)/P(B)可变形为:

P(A|B)=\frac{P(B|A)\cdot P(A)}{P(B)}

即为贝叶斯公式

先验概率——即P(A),在B事件发生前根据以往经验就可求得的A概率,如收到一封邮件,是垃圾邮件

后验概率——即P(A|B),在B发生后对A发生概率进行的重新评估,如收到一封邮件,如果含有某个词这个邮件是垃圾邮件

(3)全概率公式:

P(A)=P(A|B_{1})\cdot P(B_{1})+P(A|B_{2})\cdot P(B_{2})+......+P(A|B_{n})\cdot P(B_{n})

二、朴素贝叶斯公式

        朴素贝叶斯贝叶斯不同的点为——朴素贝叶斯采用了属性条件独立性假设,即每个属性对结果产生独立的影响

公式:
   令 x 表示训练集 X 中可能的类别数,C_{i}表示第i个属性可能的取值数,则贝叶斯公式可修正为

P(C=c_{i}|X=x)=\frac{P(X=x|C=c_{i})}{P(X=x)}=\frac{P(C)}{P(X)}\prod_{i=1}^{d}P(x_{i}|C)

因为可能有数据收集不全可能的情况即有的数据为0导致直接为另一个结果,所以可以利用拉普拉斯修正,公式为:

P(x_{i}|c)=\frac{|D_{c,x_{i}}|+1}{|D|+N_{i}}

Ni为第i个属性可能的取值数

因为所有结果值都为小数所以可能在最后累乘时产生下溢出情况,所以可采用对数化:

ln(ab)=lna+lnb

防止下溢出

三、代码

本次实验中,所采用的数据集来源

https://github.com/Jack-kui/machine-learning/tree/2272a56dcf13c98b8a3946eede2fb4fa02cb7c4b/Naive%20Bayes/email

数据集分为spam(垃圾)和ham(正常)

spam邮件:

ham邮件:

代码实现:

1、创建词汇表

#创建词汇表
def createwordList(dataSet):
    #dataSet:包含多个文档的数据集
    vocabSet = set([])#去重词汇表
    for document in dataSet:
        vocabSet=vocabSet|set(document)#取并集
    return list(vocabSet)

2、建立词袋、词集模型

词集模型单词构成的集合,集合自然每个元素都只有一个,也即词集中的每个单词都只有一个

词袋模型:在词集的基础上如果一个单词在文档中出现不止一次,统计其出现的次数(频数)。

不同词袋词集有没有某词的基础上更关注有几个某词

#词集模型
def setOfWords(vocabList,inputSet):
    #vocabList:去重词汇表
    #inputSet:输入文档
    returnVec=[0]*len(vocabList)  #建立和去重词汇表相同长度的全0向量
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)]=1  #遍历所有单词,如果存在使相应向量=1
        else:print("妹这个单词哦~")
    return returnVec

#词袋模型
def bagOfWords(vocabList,inputSet):
    returnVec=[0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)]+=1
    return returnVec

3、贝叶斯公式

#训练朴素贝叶斯
def trainBYS(trainMatrix,trainClasses):
    #trainMatrix:每个returnVec组成的矩阵
    #trainClasses:每个reVec对应的类别,1侮辱类 0正常类

    numTrainDocs=len(trainMatrix) #总文档数
    numWords=len(trainMatrix[0]) #每个文档总字数
    p_1=sum(trainClasses)/float(numTrainDocs) #文档属于侮辱类
    #拉普拉斯修正_防止下溢出
    p0Num=np.ones(numWords)  #分子各单词出现数初始化为1
    p1Num=np.ones(numWords) 
    p0Denom=2.0  #分母总单词数初始化为类别数 2
    p1Denom=2.0
    
    for i in range(numTrainDocs):  #遍历训练样本
        if trainClasses[i]==1:
            p1Num+=trainMatrix[i]  #侮辱类各个单词数量
            p1Denom+=sum(trainMatrix[i])  #侮辱类总单词数量
        else:
            p0Num+=trainMatrix[i]
            p0Denom+=sum(trainMatrix[i])

    p1Vect=np.log(p1Num/p1Denom)  #取对数
    p0Vect=np.log(p0Num/p0Denom) 
    #print(p0Vect)
    return p0Vect,p1Vect,p_1

4、分类文档

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    '''
    对测试文档进行分类
    
    Parameter:
    vec2Classify:测试文档向量
    p0Vec:正常类中每一个词的条件概率
    p1Vec:侮辱类中每一个词的条件概率
    pClass1:侮辱类占总样本概率
    
    p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)    	
    p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else: 
        return 0

5、所有单词转化为小写

#将字符串转换为小写字符列表
def textParse(bigString):   
    '''
    Parameter:
    bigString:输入字符串
    
    Return:
    tok.lower():小写字符列表
    '''       
                                             
    #将特殊符号作为切分标志进行字符串切分,即非字母、非数字
    listOfTokens = re.split(r'\W+', bigString)
    #除了单个字母,其它单词变成小写                   
    return [tok.lower() for tok in listOfTokens if len(tok) > 2] 

6、测试分类器

#测试朴素bys分类器
def spamTest(method='bag'):
    #method有bag词袋和set词集两中
    
    if method == 'bag':                   #判断使用词袋模型还是词集模型
        words2Vec = bagOfWords
    elif method == 'set':
        words2Vec = setOfWords
    
    docList=[]
    classList=[]

    #遍历文件夹
    for i in range(1,26):
        #读取垃圾邮件 转化乘字符串列表
        wordList=textParse(open('C:/Users/kid/Desktop/ML/machine-learning-master/Naive Bayes/email/spam/%d.txt' % i,'r').read())
        #将列表记录加入文档列表并分类为1 侮辱类
        docList.append(wordList)
        classList.append(1)
        #读取正常文件
        wordList=textParse(open('C:/Users/kid/Desktop/ML/machine-learning-master/Naive Bayes/email/ham/%d.txt' % i,'r').read())
        docList.append(wordList)
        classList.append(0)


    #创建去重词汇表
    vocabList=createwordList(docList)
    #print(vocabList)

    #创建索引
    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=[]
    trainClasses=[]

    for docIndex in trainSet:
        #将生成模型添加到训练矩阵并记录类别
        trainMat.append(words2Vec(vocabList,docList[docIndex]))
        trainClasses.append(classList[docIndex])

    #训练bys
    p0V,p1V,pSpam=trainBYS(np.array(trainMat),np.array(trainClasses))

    #错误分类器
    error=0

    for docIndex in testSet:
        wordVec=words2Vec(vocabList,docList[docIndex])
        #测试
        if classifyNB(np.array(wordVec),p0V,p1V,pSpam)!=classList[docIndex]:
            error+=1
            #print("分类错误的:",docList[docIndex])
    #print("错误率:%.2f%%"%(float(error)/len(testSet)*100))
    errorRate=float(error)/len(testSet)#分类错误率
    return errorRate

7、调用进行实验


if __name__ == "__main__":
    total = 100
    print('使用词袋模型训练:')
    sum_bag_error = 0
    for i in range(total):
        sum_bag_error += spamTest(method = 'bag')
    print('使用词袋模型训练' + str(total) + '次得到的平均错误率为: ' + str((sum_bag_error / total)))

结果为:

四、小小自我判别

对于已有的邮件进行朴素贝叶斯训练后我们可以对自己收集的一些邮件进行判别是否为垃圾邮件

邮件内容:

将其读取输入:

#读取自己输入集测试
    testList=textParse(open('C:/Users/kid/Desktop/ML/machine-learning-master/Naive Bayes/email/testy/1.txt','r').read())

将其与训练用去重词汇表进行文档分类

wordVec=words2Vec(vocabList,testList)

进行分类测试,判断其是否为侮辱类1或非侮辱类0

if classifyNB(np.array(wordVec),p0V,p1V,pSpam)!=1:

判断结果:

错误率为0,确定为侮辱类。


总结

可作出英文文档分类,下次会努力实现中文分类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值