机器学习实战3-贝叶斯分类

1 基础名词解释

1.1 概率: 已知模型和参数,预测出现某个结果的概率。

1.2 统计:已知大量数据,利用数据去预测模型及其参数。

1.3 先验概率: 根据以往经验和分析得到的概率,如抛硬币,我们抛之前,就认为硬币向上概率为0.5.

1.4 后验概率: 事情已发生,判断事情发生由那个原因引起的概率。(由果溯因)

1.5 P(x|θ): x表示一个具体数据,θ表示模型参数;x确定,表示为似然函数;θ确定,表示为概率函数。

1.6 极大似然估计(MLE):已知一组样本数据,假定该数据满足某种模型,依据数据对模型的参数进行估计。

2 过滤网站恶意留言

朴素贝叶斯分类:

关于该公式的几点说明:

    1. 该公式用于预测,c为分类的类别,可以有c1、c2、····ci等等若干种,下例中只有两种,即是否侮辱性词汇。
    2. X为属性向量,即总有d个属性,xi为第i个属性所对应的值。
    3. P(xi|c)根据训练数据集求出。
    4. 朴素贝叶斯分类的一个关键点是:属性条件独立性假设,即假设所有属性间相互独立,所有属性独立对分类结果产生影响。
    5. P(x)不会影响判断结果,故并不需要知道。

例子:关于一个输入文本,判断其是否含有侮辱性言论语言

思路剖一下:

    1. 需要数据:待测文本,已经带有标签的数据样本(即已标出是否为侮辱性)
    2. 建立词汇库,将所有出现的词语不重复放入库中,此即属性
    3. 将每条样本与词汇库比对,即建立属性值矩阵
    4. 根据样本集求出相关概率值,p1,p2,pc
    5. 比较待测数据两种情况下的概率,概率大的则为判断结果
代码如下: 
 1 from numpy import *
 2 
 3 # 创建实验样本
 4 def loadDataSet():
 5     postingList=[['my','dog','has','flea','problems','help','please'],
 6                  ['maybe','not','take','him','to','dog','park','stupid'],
 7                  ['my','dalmation','is','so','cute','I','love','him'],
 8                  ['stop','posting','stupid','worthless','garbage'],
 9                  ['mr','licks','ate','my','steak','how','to','stop','him'],
10                  ['quit','buying','worthless','dog','food','stupid']]
11     classVec=[0,1,0,1,0,1]
12     return postingList,classVec
13 
14 # 创建一个在所有文档中出现的不重复词的列表
15 def createVocabList(dataSet):
16     vocabSet=set([])
17     #set()函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等(set之间)。
18     for document in dataSet:
19         vocabSet=vocabSet|set(document)
20     return list(vocabSet)
21 
22 # 判断输入文档中词是否在词汇表中出现,输出一个向量表(0或1)
23 def setOfWords2Vec(vocabList,inputSet):
24     returnVec=[0]*len(vocabList) #创建一个与词汇表等长的初始0向量
25     for word in inputSet:
26         if word in vocabList:
27             returnVec[vocabList.index(word)]=1
28         else:
29             print("the word: %s is not in my Vocabulary!"%word)
30     return returnVec
31 
32 # 朴素贝叶斯分类器训练函数
33 def trainNB0(trainMatrix,trainCategory):
34     numTrainDocs=len(trainMatrix) #计算训练样本总数,即训练个数
35     numWords=len(trainMatrix[0]) #计算样本种类数,即词汇个数
36     pAbusive=sum(trainCategory)/float(numTrainDocs) #计算是侮辱性样本占比
37     p0Num=ones(numWords) #初始化p0num,p1num为0向量
38     p1Num=ones(numWords)
39     p0Denom=2.0
40     p1Denom=2.0
41     # 从第一个样本到最后一个样本依次检查,如果该样本的标签是1(即为侮辱性),
42     # 则将该样本数据加入p1num中,否则放入p0num中,p1denom表示的是放入p1num的样本1总和
43     for i in range(numTrainDocs):
44         if trainCategory[i]==1:
45             p1Num+=trainMatrix[i]
46             p1Denom+=sum(trainMatrix[i])
47         else:
48             p0Num+=trainMatrix[i]
49             p0Denom+=sum(trainMatrix[i])
50     p1Vect=log(p1Num/p1Denom)
51     p0Vect=log(p0Num/p0Denom)
52     return p0Vect,p1Vect,pAbusive
53 
54 # 朴素贝叶斯分类函数
55 def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
56     p1=sum(vec2Classify*p1Vec)+log(pClass1)
57     p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1)
58     if p1>p0:
59         return 1
60     else:
61         return 0
62 
63 def testingNB():
64     listOPosts,listClasses=loadDataSet()
65     myVolcabList=createVocabList(listOPosts)
66     trainMat=[]
67     for postinDoc in listOPosts:
68         trainMat.append(setOfWords2Vec(myVolcabList,postinDoc))
69     p0v,p1v,pAb=trainNB0(array(trainMat),array(listClasses))
70     testEntry=['love','my','dalmation']
71     thisDoc=array(setOfWords2Vec(myVolcabList,testEntry))
72     print(testEntry ,'classified as: ',classifyNB(thisDoc,p0v,p1v,pAb))
73     testEntry=['stupid','garbage']
74     thisDoc=array(setOfWords2Vec(myVolcabList,testEntry))
75     print(testEntry,' classified as: ',classifyNB(thisDoc,p0v,p1v,pAb))
76 
77 testingNB()
结果如下:

3 过滤垃圾邮件

内容介绍:
  1. 两个文件夹各取25个邮件,spam装着垃圾邮件,ham则是有用邮件。
  2. 以上50个邮件均属带标签,即均可做训练样本,随机抽取其中10个样本作为测试集,即可验证分类精度。
  3. 运用上例中的诸多函数。

主程序如下:

 1 # 将一个大字符串解析为字符列表,并去掉小于两个字符的字符串,转换为小写
 2 def textParse(bigString):
 3     import re
 4     listOfTokens=re.split(r'\w*',bigString)
 5     return [tok.lower() for tok in listOfTokens if len(tok)>2]
 6 
 7 # 垃圾文件测试
 8 def spamTest():
 9     docList=[];classList=[];fullText=[]
10     # 两个文件夹中共50个文件,spam25个垃圾,ham25个有用邮件
11     for i in range(1,26):
12         wordList=textParse(open('email/spam/%d.txt'%i).read())
13         docList.append(wordList)
14         classList.append(1)
15         wordList=textParse(open('email/ham/%d.txt'%i).read())
16         docList.append(wordList)
17         fullText.extend(wordList)
18         classList.append(0)
19     vocabList=createVocabList(docList)
20     trainingSet=range(50) #存0-49个整数
21     testSet=[]
22     # 留存交叉验证:随机选出10个样本,将其作为测试集,其余40作训练集,计算错误率
23     for i in range(10):
24         randIndex=int(random.uniform(0,len(trainingSet))) #生成0-50间的随机数
25         testSet.append(trainingSet[randIndex])
26         del(trainingSet[randIndex])
27     trainMat=[]
28     trainClasses=[]
29     for docIndex in trainingSet:
30         trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
31         trainClasses.append(classList[docIndex])
32     p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))
33     errorCount=0
34     for docIndex in testSet:
35         wordVector=setOfWords2Vec(vocabList,docList[docIndex])
36         if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
37             errorCount+=1
38     print('the error rate is: ',float(errorCount)/len(testSet))
View Code

4 获取区域倾向

内容介绍:

  1. 使用RSS源作为数据集来源。
  2. 两个来源即为两个标签。
  3. 如上例一样可以进行分类,但分类之前需要取出词汇,但一小部分高频词汇是对分类精度有影响的(常用词汇,辅助词汇等)。
  4. 最后还对两个不同源的高频词汇进行分析。
  5. 本文中的rss源不可用,可使用其他源。
 1 # RSS源分类器及高频词去除函数
 2 # 找出排前三十的高频词汇
 3 def calcMostFreq(vocabList,fullText):
 4     import operator
 5     freqDict={}
 6     for token in vocabList:
 7         freqDict[token]=fullText.count(token)
 8     sortedFreq=sorted(freqDict.iteritems(),key=operator.itemgetter(1),reverse=True)
 9     # sorted对可迭代的对象进行排序操作,iteritems()使字典变为可迭代对象,operator.itemgetter(1)使数目为比较元素,true降序
10     return sortedFreq[:30]#输出是一个列表n*2,第一列单词,第二列次数
11 
12 # 几乎和上例一模一样,访问为rss源,而不是文件,且获得排序最高100的单词并将他们移除
13 def localWords(feed1,feed0):
14     import feedparser
15     docList=[];classList=[];fullText=[]
16     minLen=min(len(feed1['entries']),len(feed0['entries']))#取两个源中项目数量最少的
17     for i in range(minLen):
18         wordList=textParse(feed1['entries'][i]['summary'])# 每篇的摘要
19         # append添加一个整体对象,extend将每个元素逐个添加
20         docList.append(wordList)
21         fullText.extend(wordList)
22         classList.append(1)
23         wordList=textParse(feed0['entries'][i]['summary'])
24         docList.append(wordList)
25         fullText.extend(wordList)
26         classList.append(0)
27     vocabList=createVocabList(docList)# 创建字库
28     # 去除高频词汇三十个(会影响分类错误率)
29     top30Words=calcMostFreq(vocabList,fullText)
30     for pairW in top30Words:
31         if pairW[0] in vocabList:
32             vocabList.remove(pairW[0])
33     trainingSet=range(2*minLen)
34     testSet=[]
35     for i in range(20):
36         randIndex=int(random.uniform(0,len(trainingSet)))
37         testSet.append(trainingSet[randIndex])
38         del(trainingSet[randIndex])
39     trainMat=[]
40     trainClasses=[]
41     for docIndex in trainingSet:
42         trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
43         trainClasses.append(classList[docIndex])
44     p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))
45     errorCount=0
46     for docIndex in testSet:
47         wordVector=setOfWords2Vec(vocabList,docList[docIndex])
48         if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
49             errorCount+=1
50     print('the error rate is: ',float(errorCount)/len(testSet))
51     return vocabList,p0V,p1V
52 
53 # 显示最具表征性的词汇
54 def getTopWords(feed0,feed1):
55     import operator
56     vocabList,p0V,p1V=localWords(feed1,feed0)
57     topfeed1=[]
58     topfeed0=[]
59     for i in range(len(p0V)):
60         if p0V[i]>-6.0:
61             topfeed0.append((volcabList[i],p0V[i]))
62         if p1V[i]>-6.0:
63             topfeed1.append((volcabList[i],p0V[i]))
64     sortedFeed0=sorted(topfeed0,key=lambda pair:pair[1],reverse=True)
65     for item in sortedFeed0:
66         print(item[0])
67     sortedFeed1=sorted(topfeed1,key=lambda pair:pair[1],reverse=True)
68     for item in sortedFeed1:
69         print(item[0])
View Code

 5 总结

后两例是对第一例的扩展理解,理解第一例即可对朴素贝叶斯分类的原理有很好的认识。主要参考书为周志华《机器学习》以及peter《python机器学习实战》。

posted @ 2019-04-26 11:03  滇红88号  阅读(530)  评论(0编辑  收藏  举报