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

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

1.问题描述:

现有50封电子邮件,存放在数据集task1中,试基于朴素贝叶斯分类器原理,用Python编程实现对垃圾邮件和正常邮件的分类。采用交叉验证方式并且输出分类的错误率及分类错误的文档。

2.实验原理:

  • 朴素贝叶斯:

    基于概率论的分类方法:朴素贝叶斯,要求分类器给出一个最优的类别猜测结果,同时给出这个猜测的概率估计值。一种有效计算条件概率的方法称为贝叶斯准则,贝叶斯准则告诉我们如何交换条件概率中的条件与结果,即如果已知$ P(x|c)$,要求 P ( c ∣ x ) P(c|x) P(cx),那么可以使用下面的计算方法:
    P ( c ∣ x ) = P ( x ∣ c ) P ( c ) P ( x ) P(c \mid x)=\frac{P(x \mid c) P(c)}{P(x)} P(cx)=P(x)P(xc)P(c)

    于是,可以定义贝叶斯分类准则为:若那么属于类别若$ P(c1|x,y)>P(c2|x,y)$, 那么属于类别 C1

    若那么属于类别若 P ( c 1 ∣ x , y ) < P ( c 2 ∣ x , y ) P(c1|x,y)<P(c2|x,y) P(c1x,y)<P(c2x,y), 那么属于类别 C2

    使用贝叶斯准则,可以通过已知的三个概率值来计算未知的概率值。

  • 由词向量计算:

    由于这里的特征是词向量,于是重写贝叶斯准则,将之前的x、y 替换为w。粗体w表示这是一个向量,即它由多个数值组成,长度N为词典长度。在词袋模型中,数值个数与词典中的词个数相同,贝叶斯准则公式如下:
    P ( c i ∣ w ) = P ( w ∣ c i ) P ( c i ) P ( w ) P(ci|w)=P(w|ci)P(ci)P(w) P(ciw)=P(wci)P(ci)P(w)
    我们使用上述公式,对每个类别计算该值,然后比较这两个概率值的大小。首先通过类别(垃圾邮件或正常邮件)中样本数除以总的样本数来计算概率$ P(ci)$,接下里计算 P ( w ∣ c i ) P(w|ci) P(wci) ,这里使用朴素贝叶斯假设,若将w展开为一个个独立特征,那么就可以将上述概率写作$ P(w0,w1,w2,…wN|ci)$ ,这里假设所有词都互相独立,该假设也称作条件独立性假设,它意味着可以使用 如下公式计算上述概率:
    P ( w ∣ c i ) = P ( w 0 ∣ c i ) P ( w 1 ∣ c i ) P ( w 2 ∣ c i ) . . . P ( w N ∣ c i ) P(w|ci)=P(w0|ci)P(w1|ci)P(w2|ci)...P(wN|ci) P(wci)=P(w0ci)P(w1ci)P(w2ci)...P(wNci)
    这样就极大的简化了计算过程。

  • 具体步骤:

  1. 设D是词向量集合,每个词向量用一个N维向量 $w={w0,w1,w2,…,wN} $表示。

  2. 假定有m个类 c i = { c 1 , c 2 , . . . , c m } ci=\{c1,c2,...,cm\} ci={c1,c2,...,cm},给定词向量w,分类法将预测w属于最高后验概率的类,即,朴素贝叶斯分类法预测w属于类ci,当且仅当
    P ( c i ∣ w ) > P ( c j ∣ w ) , 1 ≤ j ≤ m , j ≠ i ​ P(ci|w)>P(cj|w), 1≤j≤m,j≠i​ P(ciw)>P(cjw),1jm,j=i
    其中,P(ci|w) 最大的类 ci 称为最大后验概率。

  3. 做条件独立性假设,于是将公式简化:
    P ( w ∣ c i ) = ∏ k = 1 N w k ∣ c i P\left(w \mid c_{i}\right)=\prod_{k=1}^{N} w_{k} \mid c_{i} P(wci)=k=1Nwkci

  4. 训练:利用公式,对每个词向量每个类别分别计算条件概率,得出 P 0 v , P 1 v , P s p a m P0v,P1v,Pspam P0v,P1v,Pspam ,分类器训练完成。

  5. 应用:利用贝叶斯分类准则,对预测词向量分别计算$ P0,P1$ ,选择最大概率对应的分类作为目标预测结果。

3.代码实现:

  1. 数据处理:

    1)需要从文本中获取特征,需要拆分文本,分成词条

    2)获取数据字典

    3)向量化处理,方便进行特征提取

    实现:

    • 分词:

      def textParse(bigString):
          import re
          listOfTokens=re.split('\W',bigString)
          #匹配非字母数字下划线
          return [tok.lower() for tok in listOfTokens if len(tok)>2] 
      	#取出掉长度过短的单词
      
    • 获取数据字典:

      def creatVocabList(dataset):
          vocabSet=set([])
          for document in dataset:
               vocabSet=vocabSet|set(document)  #两个集合的并集
          return list(vocabSet)
      
    • 向量化处理:

      这里可以使用词集模型或者词袋模型:

      1)词集模型:只关注token是否出现,并不关注出现的次数。

      def setOfWords2Vec(vocabList, inputSet):
        returnVec = [0]*len(vocabList)
        for word in inputSet:
        	if word in vocabList:
          	return Vec[vocabList.index(word)] = 1
        return returnVec
      

      2)词袋模型:关注token的出现次数,有较好的处理结果

      #词袋模型
      def bagOfWords2Vec(vocabList,inputSet): #参数分别为词汇表,输入文档
          returnVec=[0]*len(vocabList)
          for word in inputSet:
              if word in vocabList:
                  returnVec[vocabList.index(word)]+=1
          return returnVec
      
  2. 训练模型:

    朴素贝叶斯是基于概率的分类器,其训练过程就是计算各个概率的过程。

    流程为:

    对每篇训练文档:
    ===对每个类别:
    ======如果词条出现在文档中,则增加该词条的计数
    ======增加所有出现词条的计数值
    ===对每个类别:
    ======对每个词条:
    =========将该词条的数目除以总词条的数目得到条件概率
    ===返回每个类别的条件概率
    

    代码:

    #朴素贝叶斯分类函数
    def classifyNB(vec2Classify,p0Vec,p1Vec,pClass): #参数分别为:要分类的向量以及使用trainNB0()计算得到的三个概率
        p1=sum(vec2Classify*p1Vec)+np.log(pClass)
        p0=sum(vec2Classify*p0Vec)+np.log(1-pClass)
        if p1>p0:
            return 1  
        else:
            return 0
    
  3. 测试:

    在50封邮件中,正常邮件和垃圾邮件各占25,在在其中随机抽取10封电子邮件,预测其所在的类别。

    #测试算法:使用朴素贝叶斯交叉验证。同时保存分类模型的词汇表以及三个概率值,避免判断时重复求值
    def spamTest():
        docList = []  # 文档(邮件)矩阵
        classList = []  # 类标签列表
        for i in range(1, 26):
            wordlist = textParse(open('spam/{}.txt'.format(str(i))).read())
            docList.append(wordlist)
            classList.append(1)
            wordlist = textParse(open('ham/{}.txt'.format(str(i))).read())
            docList.append(wordlist)
            classList.append(0)
        vocabList = creatVocabList(docList)  # 所有邮件内容的词汇表
        import pickle
        file=open('vocabList.txt',mode='wb')  #存储词汇表
        pickle.dump(vocabList,file)
        file.close()
        # 对需要测试的邮件,根据其词表fileWordList构造向量
        # 随机构建40训练集与10测试集
        trainingSet = list(range(50))
        testSet = []
        for i in range(10):
            randIndex = int(np.random.uniform(0, len(trainingSet)))
            testSet.append(trainingSet[randIndex])
            del (trainingSet[randIndex])
        trainMat = []  # 训练集
        trainClasses = []  # 训练集中向量的类标签列表
        for docIndex in trainingSet:
            # 使用词袋模式构造的向量组成训练集
            trainMat.append(bagOfWords2Vec(vocabList, docList[docIndex]))
            trainClasses.append(classList[docIndex])
        p0v,p1v,pAb=trainNB0(trainMat,trainClasses)
        file=open('threeRate.txt',mode='wb') #用以存储分类器的三个概率
        pickle.dump([p0v,p1v,pAb],file)
        file.close()
        errorCount=0
        for docIndex in testSet:
            wordVector=bagOfWords2Vec(vocabList,docList[docIndex])
            if classifyNB(wordVector,p0v,p1v,pAb)!=classList[docIndex]:
                errorCount+=1
        return float(errorCount)/len(testSet)
    

4.测试结果:

由于测试集的生成是随机的,所以分类器误分率每次运行结果不一致。通过运行10次的平均值作为分类器的分类效果:
在这里插入图片描述

机器学习导论代码地址:

机器学习导论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuetianw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值