【机器学习实战二:朴素贝叶斯算法之过滤垃圾邮件】

来源:互联网 发布:网络的利与弊议征文 编辑:程序博客网 时间:2024/05/06 11:01
http://blog.csdn.net/u013634684/article/details/49306563
标签: 机器学习python贝叶斯算法垃圾邮件过滤
 173人阅读 评论(0) 收藏 举报
 分类:
 


一、部分说明

----------------------------------------------------------------

1、本文代码是《机器学习实战》这本书的例程。点击下载《机器学习实战》及原书中的源代码;

2、运行环境为:window10+python3.2+各种python机器学习库

     安装可参考:点击打开链接

3、本文注重代码的实现过程,其基本知识请参考《机器学习实战》和一些知名博客。

4、本人属于初学者,有些注释部分可能不对,还请指正。

5、(1)、本代码从原来的python2.x改为python3.x

      (2)、加入详细的注释,方便理解;

      (3)、还有加入自己想要实现的一些功能。

----------------------------------------------------------------

二、重点回顾

1、朴素贝叶斯算法原理:

2、朴素贝叶斯算法原理用于垃圾邮件过滤:


3、注意事项

     (1)、为了防止步骤四的小数相乘造成精度损失(及比较小的数相乘最后会被当作0),故通过相乘比较大小转化为对数相加,避免此类问题的出现,影响实验结果;

     (2)、分类时候还分为词集模式,知关心某个单词是否出现在邮件中;词袋模式,不仅关心单词是否出现还关心出现的次数;

     (3)、其他一些具体的注意事项,会在代码中标注,可以查看,方便理解;

三、源代码




[python] view plain copy
  1. <strong>'''''*********************************************************** 
  2.   Copyright (C), 2015-2020, cyp Tech. Co., Ltd. 
  3.   FileName:           朴素贝叶斯实例.cpp 
  4.   Author:             cyp      
  5.   Version :           v1.0           
  6.   Date:               2015-10-21 上午10:38 
  7.   Description:        利用朴素贝叶斯原理对邮件进行分类      
  8.   Function List:       
  9.     1.  createVocalList:计算输入各集的并集,且每个元素是unique 
  10.     2.  setofWords2Vec:  运用词集方式将数据预处理 
  11.     3.  bagofWords2Vec:  运用词袋方式将数据预处理 
  12.     4.  trainNB0:       训练数据 
  13.     5.  classifyNB:      对email进行分类 
  14.     6.  test             相当于主函数,训练模型并测试 
  15. ***********************************************************'''  
  16.   
  17.   
  18. '''''*********************************************************** 
  19. 需要导入的模块 
  20. ***********************************************************'''  
  21. import random  
  22. import math  
  23. import numpy as np  
  24. import os  
  25.   
  26. '''''*********************************************************** 
  27.   Function:        createVocalList 
  28.   Description:     计算输入各集的并集,且每个元素是unique 
  29.   Calls:            
  30.   Called By:       test 
  31.   Input:           dataSet输入的数据集,及单词向量集 
  32.   Return:          返回输入数据集的并集,返回数据的数据类型是list 
  33.                    表示出现过的单词 
  34. ************************************************************'''  
  35. def createVocalList(dataSet):  
  36.     vocalSet = set([])                  #创建一个空集  
  37.     for data in dataSet:  
  38.         vocalSet = vocalSet | set(data) #利用set的特性求两个集合的并集  
  39.     return list(vocalSet)               #以list的方式返回结果  
  40.       
  41.       
  42. '''''*********************************************************** 
  43.   Function:        setofWords2Vec 
  44.   Description:     判断的向量的单词是否在词库中是否出现,如果出现 
  45.                    则标记为1,否则标记为0 
  46.   Calls:            
  47.   Called By:       test 
  48.   Input: 
  49.                    vocabList: 
  50.                    词库,曾经出现过的单词集合,即createVocalList 
  51.                    inputSet: 
  52.                    测试的单词向量 
  53.   Return:          returnVec是一个同vocalList同大小的数据,如果inputset单词 
  54.                    出现在vocalList则将returnVec对应的位置置1,否则为0 
  55. ************************************************************'''  
  56. def setofWords2Vec(vocalList,inputset):  
  57.     returnVec = [0]*len(vocalList)         
  58.     #同vocalList同大小的list,开始假设每个单词都没出现,即全为0  
  59.     for word in inputset:                                          
  60.         if word in vocalList:        #如果输入的单词出现在词库中,则置1     
  61.             returnVec[vocalList.index(word)] = 1  
  62.         else:                        #如果没出现在词库中,默认为0,并输出  
  63.             print("the word:%s is not in my Vocabulary!"%word)  
  64.     return returnVec                 #返回结果  
  65. '''''*********************************************************** 
  66.   Function:        bagofWords2Vec 
  67.   Description:     统计的单词是否在词库中出现频率 
  68.                   
  69.   Calls:            
  70.   Called By:       test 
  71.   Input: 
  72.                    vocabList: 
  73.                    词库,曾经出现过的单词集合,即createVocalList 
  74.                    inputSet: 
  75.                    测试的单词向量 
  76.   Return:          returnVec是一个同vocalList同大小的数据,对应位置 
  77.                     表示该单词出现的个数 
  78. ************************************************************'''  
  79. def bagofWords2Vec(vocalList,inputset):  
  80.     returnVec = [0]*len(vocalList)         
  81.     #同vocalList同大小的list,开始假设每个单词都没出现,即全为0  
  82.     for word in inputset:                                          
  83.         if word in vocalList:        #如果输入的单词出现在词库中,则加1     
  84.             returnVec[vocalList.index(word)] += 1  
  85.     return returnVec                 #返回结果  
  86. '''''*********************************************************** 
  87.   Function:        trainNB0 
  88.   Description:     统计侮辱性email出现概率,侮辱性邮件各单词出现的概率,非 
  89.                    侮辱性email各单词出现概率 
  90.   Calls:            
  91.   Called By:       test 
  92.   Input: 
  93.                    trainDataSet:参与训练的数据集,即setofWords2Vec返回数据的集合 
  94.                    trainLabels:训练数据的标签 
  95.   Return:           
  96.                     pShame:侮辱性email 
  97.                     p0Vect:非侮辱性email中单词出现的概率 
  98.                     p1Vect:侮辱性email中单词出现的概率 
  99. ************************************************************'''  
  100. def trainNB0(trainDataSet,trainLabels):  
  101.     numTrains = len(trainDataSet)     #训练数据的组数  
  102.     numWords = len(trainDataSet[0])   #每组训练数据的大小  
  103.     pShame = sum(trainLabels)/float(numTrains)  
  104.     #标签中1表示侮辱,0表示非侮辱,故上述统计侮辱性email出现概率  
  105.     #zeros(numWords)表示1*numWords数组,非numWords*numWords数组  
  106.     #p0Num = np.zeros(numWords)         #存储统计非侮辱性邮件各单词出现频率  
  107.     #p1Num = np.zeros(numWords)         #存储统计侮辱性邮件各单词出现频率  
  108.     #p0SumWords = 0.0                  #非侮辱性邮件中单词总数  
  109.     #p1SumWords = 0.0                  #侮辱性邮件中单词总数  
  110.     #为了防止与0相乘,故初始化为1,因为两者的初始化一样,所以不影响结果  
  111.     p0Num = np.ones(numWords)           #存储统计非侮辱性邮件各单词出现频率  
  112.     p1Num = np.ones(numWords)           #存储统计侮辱性邮件各单词出现频率  
  113.     p0SumWords = 2.0                    #非侮辱性邮件中单词总数  
  114.     p1SumWords = 2.0                    #侮辱性邮件中单词总数  
  115.     for i in range(numTrains):  
  116.         if trainLabels[i]==1:         #如果为侮辱性email  
  117.             p1Num += trainDataSet[i]  #统计非侮辱性邮件各单词  
  118.         else:  
  119.             p0Num += trainDataSet[i]  #统计侮辱性邮件各单词  
  120.     p0SumWords = sum(p0Num)           #计算非侮辱性邮件中单词总数  
  121.     p1SumWords = sum(p1Num)           #计算侮辱性邮件中单词总数  
  122.     p0Vect = p0Num/p0SumWords         #非侮辱性邮件中单词出现的概率  
  123.     p1Vect = p1Num/p1SumWords         #侮辱性邮件中单词出现的概率  
  124.     return pShame,p0Vect,p1Vect  
  125.       
  126. '''''*********************************************************** 
  127.   Function:        classifyNB 
  128.   Description:     对email进行分类 
  129.   Calls:            
  130.   Called By:       test 
  131.   Input: 
  132.                    vec2Classify:要分类的数据 
  133.                    pShame:侮辱性email 
  134.                    p0Vect:非侮辱性email中单词出现的概率 
  135.                    p1Vect:侮辱性email中单词出现的概率 
  136.   Return:           
  137.                    分类的结果,1表示侮辱性email,0表示非侮辱性email 
  138. ************************************************************'''  
  139. def classifyNB(vec2Classify,p0Vect,p1Vect,pShame):  
  140.     #由于小数相乘,会有很大误差,故先求对数再相乘  
  141.     temp0 = vec2Classify*p0Vect   
  142.     temp1 = vec2Classify*p1Vect  
  143.     temp00 = []   
  144.     temp11 = []  
  145.     #分步求对数,因为log不能处理array,list  
  146.     for x in temp0:  
  147.         if x>0:  
  148.             temp00.append(math.log(x))   
  149.         else:  
  150.             temp00.append(0)  
  151.     for x in temp1:  
  152.         if x>0:  
  153.             temp11.append(math.log(x))   
  154.         else:  
  155.             temp11.append(0)  
  156.     p0 = sum(temp00)+math.log(1-pShame)  #属于非侮辱性email概率  
  157.     p1 = sum(temp11)+math.log(pShame)    #属于侮辱性email概率  
  158.     if p1 > p0: #属于侮辱性email概率大于属于非侮辱性email概率  
  159.         return 1  
  160.     else:  
  161.         return 0  
  162.   
  163. '''''*********************************************************** 
  164.   Function:        text2VecOfWords 
  165.   Description:     从email的string中提取单词 
  166.   Calls:            
  167.   Called By:       test 
  168.   Input: 
  169.                    string: email字符串 
  170.   Return:           
  171.                    单词向量 
  172. ************************************************************'''  
  173. def text2VecOfWords(string):  
  174.     import re        #正则表达式工具  
  175.     listOfWolds = re.split(r"\W*",string)  
  176.     #分割数据,其分隔符是除单词,数字外任意的字符串   
  177.     return [word.lower() for word in listOfWolds if len(word)>2]  
  178.     #单词不区分大小写,及全部转换为(小写),滤除没用短字符串  
  179.   
  180. '''''*********************************************************** 
  181.   Function:        test 
  182.   Description:     将数据部分用来训练模型,部分用来测试 
  183.   Calls:           text2VecOfWords 
  184.                    createVocalList 
  185.                    trainNB0 
  186.                    classifyNB 
  187.   Called By:       main 
  188.   Input: 
  189.   Return:           
  190. ************************************************************'''  
  191. def test():  
  192.     emailList = []               #存放每个邮件的单词向量  
  193.     emailLabel = []              #存放邮件对应的标签  
  194.     cwd = "C:\\Users\\cyp\\Documents\\sourcecode\\machinelearning\\my__code\\chapter4\\"  
  195.     for i in range(1,26):  
  196.         #读取非侮辱邮件,并生成单词向量  
  197.         wordList = text2VecOfWords(open(cwd+r"email\ham\%d.txt"%i,encoding='Shift_JIS').read())  
  198.         emailList.append(wordList)#将单词向量存放到emailList中  
  199.         emailLabel.append(0)      #存放对应的标签  
  200.         wordList = text2VecOfWords(open(cwd+r"email\spam\%d.txt"%i,encoding='Shift_JIS').read())  
  201.         #读取侮辱邮件,并生成单词向量  
  202.         emailList.append(wordList)#将单词向量存放到emailList中  
  203.         emailLabel.append(1)      #存放对应的标签  
  204.     vocabList = createVocalList(emailList)#由所有的单词向量生成词库  
  205.     trainSet = [i for i in range(50)]     #产生0-49的50个数字  
  206.     testIndex = []                        #存放测试数据的下标  
  207.     for i in range(10):                   #从[0-49]中随机选取10个数  
  208.         randIndex = int(random.uniform(0,len(trainSet)))  
  209.                                           #随机生成一个trainSet的下标  
  210.         testIndex.append(trainSet[randIndex])#提取对应的数据作为训练数据  
  211.         del(trainSet[randIndex])          #删除trainSet对应的值,以免下次再选中  
  212.     trainDataSet = []             #存放训练数据(用于词集方法)  
  213.     trainLabels = []              #存放训练数据标签(用于词集方法)  
  214.     trainDataSet1 = []             #存放训练数据(用于词袋方法)  
  215.     trainLabels1 = []              #存放训练数据标签(用于词袋方法)  
  216.     for index in trainSet:        #trainSet剩余值为训练数据的下标  
  217.         trainDataSet.append(setofWords2Vec(vocabList,emailList[index]))  
  218.         #提取训练数据  
  219.         trainLabels.append(emailLabel[index])  
  220.         #提取训练数据标签  
  221.         trainDataSet1.append(bagofWords2Vec(vocabList,emailList[index]))  
  222.         #提取训练数据  
  223.         trainLabels1.append(emailLabel[index])  
  224.         #提取训练数据标签  
  225.     pShame,p0Vect,p1Vect = trainNB0(trainDataSet,trainLabels)#开始训练  
  226.     pShame1,p0Vect1,p1Vect1 = trainNB0(trainDataSet1,trainLabels1)#开始训练  
  227.     errorCount = 0.0                #统计测试时分类错误的数据的个数  
  228.     errorCount1= 0.0                #统计测试时分类错误的数据的个数  
  229.     for index in testIndex:  
  230.         worldVec = setofWords2Vec(vocabList,emailList[index])#数据预处理  
  231.         #进行分类,如果分类不正确,错误个位数加1  
  232.         if classifyNB(worldVec,p0Vect,p1Vect,pShame) != emailLabel[index]:  
  233.             errorCount += 1  
  234.         worldVec = bagofWords2Vec(vocabList,emailList[index])#数据预处理  
  235.         #进行分类,如果分类不正确,错误个位数加1  
  236.         if classifyNB(worldVec,p0Vect1,p1Vect1,pShame1) != emailLabel[index]:  
  237.             errorCount1 += 1  
  238.     #输出分类错误率  
  239.     print("As to set,the error rate is :",float(errorCount)/len(testIndex))  
  240.     print("AS to bag,the error rate is :",float(errorCount1)/len(testIndex))  
  241.       
  242. '''''*********************************************************** 
  243.   Function:       main 
  244.   Description:    运行test函数 
  245.   Calls:          test 
  246.   Called By:        
  247.   Input: 
  248.   Return:           
  249. ************************************************************'''  
  250. if __name__=="__main__":  
  251.     test()</strong>  

[python] view plain copy
  1. <span style="font-family: Microsoft YaHei; font-size: 18px;"><strong>四、结果展示</strong></span>  
0 0
原创粉丝点击