1. 程式人生 > >機器學習實戰之樸素貝葉斯_程式碼註釋

機器學習實戰之樸素貝葉斯_程式碼註釋

#-*- coding: UTF-8 -*-
from numpy import *

def loadDataSet():#建立包含文件的訓練集和各文件對應的標籤列表
postinglist = [['my','dog','has','flea','problems','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#返回建立的文件訓練集和標籤列表 def
createVocablist(dataSet):#建立總詞彙列表,列表中元素為訓練集元素之和,且每個元素只出現一次 vocabSet = set([])#建立空集 for document in dataSet:#遍歷輸入的文件詞彙集 vocabSet = vocabSet | set(document)#取並集 return list (vocabSet) def setOfWords2Vec(vocabList,inputSet):#將某文件(詞向量)中的單詞以是否在總詞彙列表中出現為特徵,轉換為數字矩陣,輸入總詞彙列表和待測詞彙向量 returnVec = [0] * len(vocabList)#初始化返回矩陣,建立與參考詞彙集等長的0矩陣
for word in inputSet:#遍歷待測詞彙列表 if word in vocabList:#如果待測詞彙列表中的單詞出現在總詞彙列表中 returnVec[vocabList.index(word)] = 1 #獲取該單詞在參考詞彙列表中的索引值,並傳遞給返回矩陣,使得返回矩陣與該單詞對應的位置置1 else: print "the word: %s is not in my Vocabulary!" % word return returnVec listOPosts,listClasses = loadDataSet() myVocabList = createVocablist(listOPosts) #print (myVocabList) #print (setOfWords2Vec(myVocabList,listOPosts[0])) #print (setOfWords2Vec(myVocabList,listOPosts[3])) def trainNB0(trainMatrix,trainCategory):#輸入為由文件矩陣轉換成的數字矩陣!!!由i個行向量(文件)組成,格式見p60,另一輸入引數為與輸入文件矩陣對應的類別列表 numTrainDocs = len(trainMatrix)#獲取輸入數字矩陣中列表個數(文件個數) numWords = len(trainMatrix[0])#獲取列表中單詞個數,即列表中元素個數 pAbusive = sum(trainCategory) / float(numTrainDocs)#計算類別概率,sum函式對類別列表元素求和,所得值為非正常的文件(列表)個數(即將其中的1求和) p0Num = ones(numWords)#向量的初始化(拉普拉斯平滑,初始值置1,長度與文件中元素個數相同) p1Num = ones(numWords) p0Denom = 2.0#分母初始化。即正常文件中出現的非正常詞彙的總數(這裡做拉普拉斯平滑初始值為 類別數 * 1) p1Denom = 2.0#非正常文件中出現的非正常詞彙的的總數(拉普拉斯平滑) for i in range(numTrainDocs):#遍歷輸入矩陣,對於其中的列表 if trainCategory[i] == 1:#類別為1,即正常的文件 p1Num += trainMatrix[i]#第i 個文件的向量加到p1,最終得到各特徵出現的總次數的數字矩陣 p1Denom += sum(trainMatrix[i])#將第i 個文件中非正常詞彙的個數加入到總詞彙數中,得到分母 else:#二分類中,除去正常文件,剩下的為非正常文件 p0Num += trainMatrix[i]#類似正常文件操作 p0Denom += sum(trainMatrix[i]) p1Vect = log(p1Num / p1Denom)#計算條件概率,由於概率值很小且logx與x同增減,故可以用log函式將條件概率放大 p0Vect = log(p0Num / p0Denom) return p0Vect,p1Vect,pAbusive#返回正常文件類各特徵的的條件概率,非正常文件各特徵的條件概率,非正常文件的概率 def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):#預測待分類文件所屬的類別,輸入為p0類別各特徵條件概率向量(列表),p1類別各特徵的條件概率向量,非正常文件噗p1的概率 p1 = sum(vec2Classify * p1Vec) + log(pClass1)#這裡需要注意的是使用loga + logb = logab,即原式為概率相乘,使用log函式放大之後等價於概率相加 p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)#二分類,兩類概率相加為1 if p1 > p0:#比較概率值,返回比較大的概率所對應的類別 return 1 else: return 0 def testingNB():#封裝函式 listOPosts,listClasses = loadDataSet()#獲得資料集,類別標籤向量列表 myVocabList = createVocablist(listOPosts)#建立總詞彙列表 trainMat = [] for postinDoc in listOPosts: trainMat.append(setOfWords2Vec(myVocabList,postinDoc))#將各文件轉換為數字向量並放入列表中,構成訓練集數字矩陣 p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))#獲得p0類別中各概率矩陣,p1類別中各概率矩陣,以及非正常文件的概率,(輸入為矩陣!!!) testEntry = ['love','my','dalmation']#測試詞彙向量(文件) thisDoc = array(setOfWords2Vec(myVocabList,testEntry))#將測試詞彙向量轉換為與參考向量等特徵數的數字向量,並轉換為numpy陣列 print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)#輸出結果,測試向量的類別 testEntry = ['stupid','garbage']#測試詞彙向量 thisDoc = array(setOfWords2Vec(myVocabList,testEntry))# print testEntry,'classfied as: ',classifyNB(thisDoc,p0V,p1V,pAb) print testingNB() def textParse(bigString):#切分文當,輸入為一個包含數字,字母,符號字元的字串 import re ListOftokens = re.split(r'\W*',bigString)#正則表示式 return [tok.lower() for tok in ListOftokens if len(tok) > 2]#過濾掉長度小於3的字元 def spamTest(): docList = []#初始化中間變數 classList= []#初始化類別列表 fullText = []#初始化總詞彙列表 for i in range(1,26):#遍歷ham和spam中的25個檔案 wordList = textParse(open('email/spam/%d.txt' % i).read())#讀取非正常文件的第i 個檔案,並得到詞彙向量,放入列表中 docList.append(wordList)#將得到的詞彙向量放入大的訓練集列表 fullText.extend(wordList)#每次都將得到的字元放入總詞彙列表,fulltext列表包含的元素為詞彙(可以重複) classList.append(1)#開啟的是spam檔案,每開啟一個 不正常文件數的類別加1 wordList = textParse(open('email/ham/%d.txt' % i).read())#讀取正常文件的第i個檔案,並切分後得到詞彙向量放入列表 docList.append(append(wordList))#將詞彙向量放入文件列表 fullText.extend(wordList)#得到的所有詞彙加入到總詞彙列表 classList.append(0)#開啟的是ham檔案,每在文件列表中新增一個詞彙向量,類別0加一 vocabList = createVocablist(docList)#得到唯一的總詞彙列表 trainingSet = range(50)#生成一個元素為[0,1,2,L,50]的列表(索引列表) testSet = []#定義空的測試集 for i in range(10):#選出10個詞彙向量作為測試向量組成測試集 randIndex = int(random.uniform(0,len(trainingSet)))#numpy中random函式的uniform功能是從一個均勻分佈[low,high)中隨機取樣,得到一個隨機索引值 testSet.append(trainingSet[randIndex])#將得到的值作為從訓練集中選取好的測試向量的索引值並新增到測試集列表 del(trainingSet[randIndex])#為了避免重複,將選出的作為測試向量的索引值從訓練集中刪除,防止二次選出和在交叉驗證中被選入訓練集 trainMat = []#新訓練集初始化 trainClasses = []#新訓練集中詞彙向量對應表標籤列表的初始化 for docIndex in trainingSet:#遍歷訓練集的索引值(剩餘40個,測試集已經取出) trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))#將舊的訓練集中的詞彙向量全部取出,轉化成為數字向量 trainClasses.append(classList[docIndex])#對應的標籤新增到類別列表 p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))#將訓練集轉換成的數字列表和對應標籤列表變成numpy陣列,作為輸入 errorCount = 0#錯分類數量初試化 for docIndex in testSet:#遍歷測試詞彙集列表 wordVector = setOfWords2Vec(vocabList,docList[docIndex])#將測試集詞彙向量轉換成數字向量 if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:#如果測試得到的類別的與實際類別不一致,錯分類數目加1 errorCount += 1 print 'the error rate is: ',float(errorCount)/len(testSet)#計算錯誤率 #使用樸素貝葉斯分類器從個人廣告中獲取區域傾向 def calcMostFreq(vocabList,fullText):#找出出現頻數最多的詞彙 import operator freqDict = {}#定義新的頻數字典 for token in vocabList: freqDict[token] = fullText.count(token)#對於每個cocabList中的單詞,計算其在總詞彙列表中出現的次數,比作為值賦值給對應的鍵 sortedFreq = sorted(freqDict.iteritems(),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):#此for迴圈將兩類的每個字串文件切分並放入詞彙集列表,格式為[[],L,[]].其中每個字串文件對應的類別放入類別列表 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) vocabList = createVocablist(docList)#得到獨一無二的詞彙列表,即參考詞彙集列表 top30Words = calcMostFreq(vocabList,fullText)#選出出現頻數最高的前30個詞彙 for pairW in top30Words:#遍歷頻數列表,如果其中的單詞出現在參考集詞彙列表中,將該詞刪掉 if pairW[0] in vocabList: vocabList.remove(pairW[0]) trainingSet = range(2 * minLen)#生成與詞彙集列表文件數等長的列表 testSet = [] for i in range(20):#生成20個隨機索引 randIndex = int(random.uniform(0,len(trainingSet))) testSet.append(trainingSet[randIndex])#將隨機索引對應的訓練集中的文件新增到測試集 del(trainingSet[randIndex])#將新增到測試集中的文件從訓練集中刪去 trainMat = [] trainingClassess = [] for docIndex in trainingSet:#訓練集剩下的文件作為新的訓練集,將其中的文件轉換成數字向量(詞袋模型) trainMat.append(bagofwords2VecMN(vocabList,docList[docIndex])) trainingClassess.append(classList[docIndex]) p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainingClassess))#將訓練集和訓練列表轉換成numpy陣列,訓練得到模型 errorCount = 0#初始化錯分類數量 for docIndex in testSet: wordVector = bagOfWords2VecMN(vocabList,docList[docIndex])#將測試集中的向量轉換成數字向量(詞袋模型) if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:#將分類器得到的分類結果與文件的實際類別做對比,如果不等,錯誤數加1 errorCount += 1 print 'the error rate is:',float(errorCount) / len(testSet)#計算錯誤率 return vocabList,p0V,p1V #選出出現頻率較高的詞彙 def getTopWords(ny,sf): import operator vocabList,p0V,p1V = localWords(ny,sf) topNY = [] topSF = [] for i in range(len(p0V)):#設定閾值,選出大於該閾值的概率 if p0V[i] > -6.0: topSF.append((vocabList[i],p0V[i]))#將大於該閾值的詞彙和概率值以元祖的方式新增到一個列表中 if p1V[i] > -6.0: topSF.append((vocabList[i],p1V[i])) sortedSF = sorted(topSF,key=lambda pair:pair[1],reverse = True)#降序排序 print "SF**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**NY**" for item in sortedNY: print item[0]