《机器学习实战》笔记——朴素贝叶斯

闲来无事最近复习了一下ID3决策树算法,并凭着理解用pandas实现了一遍,加了些自己的理解(链接如下)。相比本篇博文,更简明清晰,更适合复习用。

https://github.com/DianeSoHungry/ShallowMachineLearningCodeItOut/blob/master/Naive%20Bayes.ipynb

 

第一步:分类器的建立、训练、以及测试

运用贝叶斯公式(朴素贝叶斯假设每个特征每个特征都是独立的)可以解决的问题有,已知某些特征,用来判断某情况发生的可能性大小,设置可能性最大的情况作为预测值。

是一种监督算法。

广泛应用于垃圾邮件检测等等。

  1 # _*_coding:utf-8_*_
  2 from numpy import *
  3 
  4 # 4-1 词表到向量的转换函数(实验样本)
  5 def loadDataSet():
  6     postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
  7                    ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
  8                    ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
  9                    ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
 10                    ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
 11                    ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
 12     classVec = [0, 1, 0, 1, 0, 1]  # 1 is abusive, 0 not
 13     return postingList, classVec
 14 
 15 # 返回一个dataSet中所有出现过的词条列表
 16 def createVocabList(dataSet):
 17     vocabSet = set([])
 18     for document in dataSet:
 19         vocabSet = vocabSet | set(document) #用于求两个集合的并集
 20     return list(vocabSet)
 21 
 22 # # 输入参数为词汇表(vocabSet)和某个文档(inputSet),返回的是元素和词汇表元素一一对应的向量returnVec
 23 # # vocabSet中的元素在inputSet中出现过则向量中元素为1,反之为0
 24 def setOfWords2Vec(vocabList, inputSet):
 25     returnVec = [0] * len(vocabList)    # [1,2,3]*3 结果等于[1,2,3,1,2,3,1,2,3]
 26     for word in inputSet:
 27         if word in vocabList:
 28             returnVec[vocabList.index(word)] = 1
 29         else:
 30             print ("the word: %s is not in my Vocabulary!" % word)    # 为什么有这一步?
 31     return returnVec
 32 
 33 # 4-4 朴素贝叶斯词袋模型
 34 # 修改setOfWords2Vec函数
 35 def bagOfWords2Vec(vocabList, inputSet):
 36     returnVec = [0] * len(vocabList)    # [1,2,3]*3 结果等于[1,2,3,1,2,3,1,2,3]
 37     for word in inputSet:
 38         if word in vocabList:
 39             returnVec[vocabList.index(word)] += 1
 40     return returnVec
 41 
 42 # 4-2 朴素贝叶斯分类器训练函数
 43 # 注意:
 44 # trainMatrix不是最原始的文档,而是由原始文档列表得到的矩阵,
 45 # 矩阵的列分别对应了所有出现过的词,行对应了各个不同的句子
 46 # 上面函数的输出returnVec就是trainMatrix其中的一行
 47 # trainCategory为该行是否为侮辱性言论。1为是
 48 def trainNB0(trainMatrix, trainCategory):   #
 49     numTrainDocs = len(trainMatrix) # 有几句话
 50     numWords = len(trainMatrix[0])  # 每句话有几个词条
 51     pAbusive = sum(trainCategory)/float(numTrainDocs)   # trainCategory中元素为1的表示是侮辱性语言
 52     p0Num = zeros(numWords)+0.00000001 # 累计所有非侮辱性言论中,各个词条出现过的次数
 53     p1Num = zeros(numWords)+0.00000001 # 累计所有侮辱性言论中,各个词条出现过的次数 加一个极小量是为了避免在侮辱性言论的条件下,某个词条
 54                                        # 的概率为0的情况,此时,最终结果也会为0,显然不对。
 55     # p0Denom = 0.0   # 书上代码是被我注释掉了,最终是要得到(非)侮辱性言论中所有出现过的词汇的总和(包括重复值),
 56     # p1Demon = 0.0   # 不如在最后将(非)侮辱性言论中每个词汇出现过的次数相加。
 57     for i in range(numTrainDocs):
 58         if trainCategory[i] == 1:
 59             p1Num += trainMatrix[i]
 60             # p1Demon += sum(trainMatrix[i])
 61         else:
 62             p0Num += trainMatrix[i]
 63             # p0Denom += sum(trainMatrix[i])
 64     p1Demon=sum(p1Num)
 65     p0Denom=sum(p0Num)
 66     # p1Vect = p1Num/p1Demon
 67     # p0Vect = p0Num/p0Denom
 68     p1Vect = log(p1Num / p1Demon)   # 利用log()函数避免多个概率连乘过小的问题
 69     p0Vect = log(p0Num / p0Denom)
 70     return p0Vect, p1Vect, pAbusive
 71 
 72 # 4-3 朴素贝叶斯分类函数
 73 # 对于一个测试点,p(ci)几乎不变,p(w|ci)=p(w0|ci)*p(w1|ci)...p(wn|ci)
 74 # 而p(w0|ci)的概率又等于pow( ci发生的条件下,下标为0的特征=1的概率, w0发生的次数)
 75 
 76 def classifyNB(vec2Classify, p0Vec,p1Vec, pClass1):
 77     p1 = sum(vec2Classify * p1Vec) + log(pClass1)
 78     p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
 79     if p1 > p0:
 80         return 1
 81     else:
 82         return 0
 83 
 84 def testingNB():
 85     listOPosts,listClasses = loadDataSet()
 86     myVocabList = createVocabList(listOPosts)
 87     trainMat = []
 88     for postinDoc in listOPosts:
 89         trainMat.append(bagOfWords2Vec(myVocabList, postinDoc))
 90     p0V, p1V, pAb =trainNB0(array(trainMat), array(listClasses))
 91     testEntry = ['love', 'my', 'dalmation']
 92     thisDoc = array(bagOfWords2Vec(myVocabList,testEntry))
 93     print (testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
 94     testEntry = ['stupid','garbage']
 95     thisDoc = array(bagOfWords2Vec(myVocabList,testEntry))
 96     print (testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))
 97 
 98 
 99 # 4-5 文件解析及完整的垃圾邮件测试函数
100 def textParse(bigString):
101     import re
102     listOfTokens = re.split(r'\W*', bigString)  #正则表达式中\W表示\w的相反,后者表示的是字母数字下划线,将正则表达式作为split()函数的第一个参数,比表示以此为分隔符
103     return [tok.lower() for tok in listOfTokens if len(tok) > 2]
104 
105 def spamTest():
106     docList=[]  #共50个元素,每个元素为指向一个文本的引用,有序
107     classList=[]    #共50个元素,与docList元素一一对应,有序
108     fullText=[] #把50个文件内容连起来的一个文本文件
109     for i in range(1,26):   #从第1个txt文件到第25个,依次遍历
110         wordList = textParse(open('email/spam/%d.txt'%i).read())
111         docList.append(wordList)
112         fullText.extend(wordList)
113         classList.append(1) #spam文件里的标签都为1 ham文件里的标签都为0
114         wordList = textParse(open('email/ham/%d.txt'%i).read())
115         docList.append(wordList)
116         fullText.extend(wordList)
117         classList.append(0)
118     vocabList = createVocabList(docList)
119     trainingSet = range(50) #存储的是docList的下标
120     testSet=[]  #存储的是docList的下标
121     for i in range(10):  # 随机选取从训练集里选10个放到测试集
122         randIndex = int(random.uniform(0,len(trainingSet)))
123         testSet.append(trainingSet[randIndex])
124         del(trainingSet[randIndex])
125     trainMat=[]
126     trainClasses=[]
127     for docIndex in trainingSet:
128         trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
129         trainClasses.append(classList[docIndex])
130     p0v,p1v,pSpam = trainNB0(array(trainMat), array(trainClasses))
131
132     errorCount = 0
133     for docIndex in testSet:
134         wordVector = setOfWords2Vec(vocabList, docList[docIndex])
135         if classifyNB(array(wordVector),p0v,p1v,pSpam) != classList[docIndex]:
136             errorCount += 1
137     print"the error rate is: ", float(errorCount) / len(testSet)

到目前为止,已经建好了一个朴素贝叶斯分类器并用txt文件进行训练和测试。

 

第二步:应用——通过婚恋网上的求偶信息判断所在地域

需要从婚恋网上获得实时信息,这需要RSS阅读器,python中最常用的RSS程序库是Universal Feed Parser。下载、安装。

在第一步的代码中,继续加入以下代码,并运行。

 1 # 4-6 RSS源分类器及高频词去除函数
 2 
 3 # 从fullText中找vacabList中每个词条出现的次数,选取次数最多的前30项,形成排好序的字典
 4 def calcMostFreq(vocabList, fullText):
 5     import operator
 6     freqDict = {}
 7     for token in vocabList:
 8         freqDict[token] = fullText.count(token)
 9     sortedFreq = sorted(freqDict.iteritems(), key=operator.itemgetter(1),reverse=True)
10     return sortedFreq[:30]
11 
12 # 训练分类器
13 def localWords(feed1, feed0):   #这里feed1,feed0不是两个不同标签的文本文件的引用,二是指向两个网址
14     import feedparser
15     docList=[]  # 最终用来装所有的文章
16     classList=[]    # docList对应的标签(是哪个网站的)
17     fullText=[] # 选取的所有文章的词(有重复)
18     minLen = min(len(feed1['entries']), len(feed0['entries']))  # 为了在两个网站上取相同数量的文章数
19     for i in range(minLen):
20         wordList = textParse(feed1['entries'][i]['summary'])    # 把feed1中文章简介给切分成词条列表
21         docList.append(wordList)
22         fullText.extend(wordList)
23         classList.append(1)
24         wordList = textParse(feed0['entries'][i]['summary'])
25         docList.append(wordList)
26         fullText.extend(wordList)
27         classList.append(0)
28     vocabList = createVocabList(docList)
29     top30Words = calcMostFreq(vocabList,fullText)
30     for pairW in top30Words:    # 删除30个高频词条,据经验这样可以提高预测结果。因为这样可以减小冗余词汇的影响
31         if pairW[0] in vocabList: vocabList.remove(pairW[0])    # pairW不是一个字符串,而是字典元素。按道理不需要判断的
32     trainingSet = range(2*minLen)
33     testSet = []
34     for i in range(20):
35         randIndex = int (random.uniform(0, len(trainingSet)))
36         testSet.append(trainingSet[randIndex])
37         del(trainingSet[randIndex])
38     trainMat = []
39     trainClasses = []
40     for docIndex in trainingSet:
41         trainMat.append(bagOfWords2Vec(vocabList, docList[docIndex]))   # 书上这块估计是有排版印刷的问题的
42         trainClasses.append(classList[docIndex])
43     p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))
44     errorCount = 0
45     for docIndex in testSet:
46         wordVector = bagOfWords2Vec(vocabList, docList[docIndex])
47         if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
48             errorCount += 1
49     print 'the error rate is: ', float(errorCount)/len(testSet)
50     return vocabList, p0V, p1V
51 
52 import feedparser
53 ny=feedparser.parse('http://newyork.craigslist.org/stp/index.rss')
54 print len(ny['entries'])
55 sf=feedparser.parse('http://sfbay.craigslist.org/stp/index.rss')
56 print len(sf['entries'])
57 vocabList, pSF, pNY = localWords(ny,sf)

 

posted @ 2017-06-22 22:50  DianeSoHungry  阅读(346)  评论(0编辑  收藏  举报