畢業論文寫不下去,就逃避來學這個
萬事開頭難,要勇敢邁出第一步
加油。
========================================================================================
貝葉斯的原理不贅述啦,網上還是有很多資料的
建立一個資料集,書中是以文檔分類的例子來講
def loadDataSet(): postingList=[['my','dog','has','flea','problem','help','please'],\ ['maybe','not','take','him','to','dog','park','stupid'],\ ['my','dalmation','is','so','cute','I','love','him'],\ ['stop','posting','stupid','worthless','garbage'],\ ['mr','licks','ate','my','steak','how','to','stop','him'],\ ['quit','buying','worthless','dog','food','stupid']] classVec=[0,1,0,1,0,1] return postingList,classVec
上面這個函數就建立了一個小資料集,包含六篇文檔,每篇文檔有各自的分類(此例僅有0和1兩類)
def createVocabList(dataset): vocabSet=set([]) for document in dataset: vocabSet=vocabSet|set(document) #迴圈對資料集內的每個檔案提取word,set用於去重 #求並集 return list(vocabSet)
該函數將文檔集轉換為一個詞彙庫(vocabulary),裡麵包含在文檔集內的所有word
貝葉斯的文檔分類都是基於詞彙庫將文檔轉換成(特徵)向量的,值就0和1表示存在或不存在
def setOfWords2Vec(vocabList,inputSet): returnVec=[0]*len(vocabList) #建立一個所含元素都是0的向量 for word in inputSet: if word in vocabList: returnVec[vocabList.index(word)]=1 else:print("the word: %s is not in my Vocabulary!" %word) return returnVec#該函數首先建立一個與詞彙表等長的向量#輸出表示判斷文檔中的單詞在詞彙表中是否出現#從而將文檔轉換為詞向量
樸素貝葉斯分類器訓練函數:
def trainNB0(trainMatrix,trainCategory): numTrainDocs=len(trainMatrix) #擷取訓練集的文檔個數 numWords=len(trainMatrix[0]) #由第一行的個數獲得vocabulary的長度 pAbusive=sum(trainCategory)/float(numTrainDocs) #表示類別的機率,此例中僅限類別為0和1的狀況 p0Num=zeros(numWords) p1Num=zeros(numWords) #pXNum是一個與Vocabulary等長的向量,用於統計對應word出現的次數 p0Denom=0.0 p1Denom=0.0 #pXDenom表示第X類內單詞的總數 for i in range(numTrainDocs): if trainCategory[i]==1: p1Num+=trainMatrix[i] p1Denom+=sum(trainMatrix[i]) else: p0Num+=trainMatrix[i] p0Denom+=sum(trainMatrix[i]) p1Vec=p1Num/p1Denom p0Vec=p0Num/p0Denom #vocabulary中的某個詞在某類別裡頭出現的頻率 return p0Vec,p1Vec,pAbusive
#首先搞清楚參數的意思
#結合前幾個函數:postingList表示文檔的集合,每一行表示一篇文檔,行數即文檔數
#classVec向量內值的個數與文檔數相同,表示各文檔的分類
#createVocabList函數把這些文檔整合起來求得不含重複word的vocabulary
#setOfWords2Vec函數把一篇文檔的word對應到vocabulary中,變成一個向量
#本函數的第一個參數表示每篇轉化到vocabulary對應的向量,為n*m,n是文檔數,m是vocabulary的長度
#trainCategory是一個向量,是每篇文檔對應的類別
測試用的代碼:
from numpy import *import bayeslistPost,listClass=bayes.loadDataSet()myVoc=bayes.createVocabList(listPost)trainMat=[]for postinDoc in listPost: trainMat.append(bayes.setOfWords2Vec(myVoc,postinDoc))p0V,p1V,pAb=bayes.trainNB0(trainMat,listClass)print(myVoc)print(p0V)print(p1V)print(pAb)
這裡樸素貝葉斯分類器訓練函數的輸出:
vocabulary裡的word在個類別中出現的機率(先驗機率)
每個類別出現的機率(先驗機率)
此例中pAb結果為0.5,表示0和1兩類是等機率出現的
根據現實情況修改:
1.初始化問題
貝葉斯進行文檔分類時,需要多個機率的乘積以獲得文檔屬於某個類別的機率
即:分別在每個類內對文檔內的每個WORD的機率相乘,以獲得整個文檔對應該類別的機率
但是如果某個機率值為0,則整個機率值也為0。所以書中將所有單詞出現數初始化為1,分母初始化為2
p0Num=ones(numWords) p1Num=ones(numWords) #pXNum的個數被初始化為1 p0Denom=2.0 p1Denom=2.0
2.下溢出
由於有很多個很小的數相乘,容易造成下溢出,最後會四捨五入得0.
解決的方法是:對乘積取對數
ln(a*b)=ln(a)+ln(b)
具體代碼中為:
p1Vec=log(p1Num/p1Denom) p0Vec=log(p0Num/p0Denom)
最後是整合上面的步驟,用於進行分類
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1): p1=sum(vec2Classify*p1Vec)+log(pClass1) p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1) if p1>p0: return 1 else: return 0
針對檢測向量,對每個類別的機率進行計算,機率大的為分類結果
def testingNB(): listPost,listClass=loadDataSet() myVoc=createVocabList(listPost) trainMat=[] for postinDoc in listPost: trainMat.append(setOfWords2Vec(myVoc,postinDoc)) p0V,p1V,pAb=trainNB0(trainMat,listClass) testEntry=['love','my','dalmation'] thisDoc=array(setOfWords2Vec(myVoc,testEntry)) print(testEntry,' classified as ',classifyNB(thisDoc,p0V,p1V,pAb)) testEntry=['stupid','garbage'] thisDoc=array(setOfWords2Vec(myVoc,testEntry)) print(testEntry,' classified as ',classifyNB(thisDoc,p0V,p1V,pAb))
整合上述步驟,同時用了兩個測試案例
檢測結果:
使用樸素貝葉斯過濾垃圾郵件
def textParse(bigString): import re listOfTokens=re.split(r'\W*',bigString) #使用中Regex提取 return [token.lower() for token in listOfTokens if len(token) >2]
</pre>此處,我犯了個錯,就是Regex那一塊,打的小寫w,所以結果錯誤。怎麼犯這麼愚蠢的錯誤<p></p><p><span style="background-color:rgb(240,240,240)"></span></p><pre code_snippet_id="1627130" snippet_file_name="blog_20160329_12_57207" name="code" class="python">def spamTest(): docList=[];classList=[];fullText=[] for i in range(1,26): wordList=textParse(open('email\spam\%d.txt' %i).read()) docList.append(wordList) fullText.append(wordList) classList.append(1) #正例 wordList=textParse(open('email\ham\%d.txt' %i).read()) docList.append(wordList) fullText.append(wordList) classList.append(0) #反例 vocabulary=createVocabList(docList) trainingSet=list(range(50)) testSet=[] for i in range(10): randIndex=int(random.uniform(0,len(trainingSet))) #random模組用於產生隨機數 #random.uniform(a,b)用於產生制定範圍內的隨機浮點數 testSet.append(trainingSet[randIndex]) del trainingSet[randIndex] #隨機播放10個文檔作為測試集,其餘作為訓練集 trainMat=[];trainClasses=[] for docIndex in trainingSet: trainMat.append(setOfWords2Vec(vocabulary,docList[docIndex])) trainClasses.append(classList[docIndex]) #將選中的訓練集逐個整合在一起 p0V,p1V,pSpam=trainNB0(trainMat,trainClasses) errorCount=0 for docIndex in testSet: wordVector=setOfWords2Vec(vocabulary,docList[docIndex]) if(classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]): errorCount+=1 #如果分類結果與原類別不一致,錯誤數加1 print('the error rate is:',float(errorCount)/len(testSet))
</pre>修改了一個地方:按照原文的話抱一個錯就是在trainingSet的地方<p></p><p><span style="background-color:rgb(240,240,240)">del(trainingSet[randIndex])TypeError: 'range' object doesn't support item deletion</span></p><p><span style="background-color:rgb(240,240,240)">於是,我在初始化的時候,把它改成了List型</span></p><p><span style="background-color:rgb(240,240,240)"><img src="https://img-blog.csdn.net/20160329104816823?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /></span></p><p><span style="background-color:rgb(240,240,240)"></span></p><p><span style="background-color:rgb(240,240,240)"></span><pre name="code" class="python">def calcMostFreq(vocabulary,fulltext): import operator freqDict={} for token in vocabulary: freqDict[token]=fulltext.count(token) sortedFreq=sorted(freqDict.items(),key=operator.itemgetter(1),reverse=True) return sortedFreq[:30] #出現頻率前30的詞
def localWords(feed1,feed0): import feedparser docList=[];classList=[];fullText=[] minlen=min(len(feed1['entries']),len(feed0['entries'])) for i in range(minlen): wordList=textParse(feed1['entries'][i]['summary']) docList.append(wordList) fullText.extend(wordList) classList.append(1) wordList=textParse(feed0['entries'][i]['summary']) docList.append(wordList) fullText.extend(wordList) classList.append(0) #兩個RSS源作為正反例 vocabulary=createVocabList(docList) #建立詞彙庫 top30Words=calcMostFreq(vocabulary,fullText) #獲得出現頻率最高的30個 for pairW in top30Words: if pairW[0] in vocabulary:vocabulary.remove(pairW[0]) #去除前30的單詞 trainingSet=list(range(2*minlen));testSet=[] for i in range(20): randIndex=int(random.uniform(0,len(trainingSet))) testSet.append(trainingSet[randIndex]) del(trainingSet[randIndex]) #隨機播放訓練和測試集;測試集為20個 trainMat=[];trainClass=[] for docIndex in trainingSet: trainMat.append(bagOfWords2VecMN(vocabulary,docList[docIndex])) trainClass.append(classList[docIndex]) #將訓練集內的文檔轉換成頻數特徵 p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClass)) errorCount=0 for docIndex in testSet: wordVector=bagOfWords2VecMN(vocabulary,docList[docIndex]) if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]: errorCount+=1 print('the error rate is: ',float(errorCount)/len(testSet)) return vocabulary,p0V,p1V
其中還是修改了
trainingSet=list(range(2*minlen))
不知道其他學習的同學們有沒有遇到這個問題,這麼處理對不對。
測試用的代碼:
import feedparserny=feedparser.parse('http://newyork.craigslist.org/stp/index.rss')sf=feedparser.parse('http://sfbay.craigslist.org/stp/index.rss')vocabulary,pSF,pNY=bayes.localWords(ny,sf)
結果是因隨機抽取的測試集和訓練集不一樣會發生變化。
最具表徵性詞彙顯示:
def getTopWord(ny,sf): import operator vocabulary,p0V,p1V=localWords(ny,sf) topNY=[];topSF=[] for i in range(len(p0V)): if p0V[i]>-6.0:topSF.append((vocabulary[i],p0V[i])) if p1V[i]>-6.0:topNY.append((vocabulary[i],p1V[i])) #按照排序選擇 sortedSF=sorted(topSF,key=lambda pair:pair[1],reverse=True) #pair:pair[1]表示按每個元素的第二個參數排序 print("SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF") for item in sortedSF: print(item[0]) sortedNY=sorted(topNY,key=lambda pair:pair[1],reverse=True) print("NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY") for item in sortedNY: print(item[0])
=========================================================================================
下載安裝feedsparse
下載地址:點擊開啟連結
安裝方法:首先將路徑轉換到該檔案夾下
然後輸入指令python setup.py install