機器學習實戰代碼詳解(四)樸素貝葉斯

#coding=utf-8
from numpy import *
#--------詞表到向量對轉換函數---------
#創建實驗樣本
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]  #1代表侮辱性文字,0代表正常言論
    return postingList, classVec
#創建包含在所有文檔中不出現重複詞對列表
def createVocabList(dataSet):
    vocabSet = set([])                          #創建一個空的集合
    for document in dataSet:
        vocabSet = vocabSet | set(document)     #求並集
    return list(vocabSet)
#獲取文檔向量,向量的每一個元素爲1或者0,分別表示詞表中的單詞在輸入文檔中是否出現
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    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

#--------樸素貝葉斯分類器訓練函數---------
#計算p(wi|c1), p(wi|c0)
def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix)                      #訓練樣本的數量
    numWords = len(trainMatrix[0])                       #訓練特徵數量
    pAbusive = sum(trainCategory)/float(numTrainDocs)    #任意文檔歸屬侮辱性文檔對 概率
    p0Num = ones(numWords); p1Num = ones(numWords)     #初始化概率,特徵出現次數初始化爲0
    p0Demon = 2.0; p1Demon = 2.0                        #沒出現過對概率爲0.5
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:        #文檔歸屬爲侮辱性文檔
            p1Num += trainMatrix[i]      #某個單詞在侮辱性文檔中的次數加1
            p1Demon += sum(trainMatrix[i])  #侮辱性文檔中總的單詞數量加1
        else:                            #文檔歸屬爲非侮辱性文檔
            p0Num += trainMatrix[i]      #某個單詞在非侮辱性文檔中的次數加1
            p0Demon += sum(trainMatrix[i])  #侮辱性非文檔中總的單詞數量加1
                                   #加log是防止小數連乘得到一個極小數
    p1Vect = log(p1Num/p1Demon)    #p1Num/p1Demon對應單詞在侮辱性文檔中出現的概率,即p(wi|c1),i= 0,....n
    p0Vect = log(p0Num/p0Demon)    #p0Num/p0Demon對應單詞在非侮辱性文檔中出現的概率,即p(wi|c0),i= 0,....n
    return p0Vect, p1Vect, pAbusive  #貝葉斯分類器訓練結果
#分類函數
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)  #//log(p(w|ci) * p(ci)) = log(p(w|ci))+ log(p(i))
    p0 = sum(vec2Classify * p0Vec) + log(1 - pClass1)
    if p1 > p0: return 1
    else: return 0
#測試函數
def testingNB():
    listOposts, listClasses = loadDataSet()  #創建訓練樣本
    myVocabList = createVocabList(listOposts)   #創建包含在所有文檔中不出現重複詞對列表,即創建特徵
    trainMat = []      #獲取文檔向量,向量的每一個元素爲1或者0,分別表示詞表中的單詞在輸入文檔中是否出現
    for postinDoc in listOposts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V, p1V, pAb = trainNB0(array(trainMat), array(listClasses))   #訓練貝葉斯分類器
    testEntry = ['love', 'my', 'dalmation']     #創建測試樣本
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry)) #獲取測試樣本特徵向量
    print  testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb) #輸出分類結果
    testEntry = ['stupid', 'garbage']           #創建測試樣本
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))     #獲取測試樣本特徵向量
    print  testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb) #輸出分類結果

#詞袋模型,詞袋中每個單詞可以出現多次,而在setOfWords2Vec詞集模型中,每個單詞只出現一次
def bagOfWords2VecMN(vocabList, inputSet):
    returnVec = [0]*len(vocabList)      #初始化特徵向量,每個單詞出現次數初始化爲0
    for word in inputSet:               #計算input的特徵向量
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    return returnVec

#-----------文件解析及完整對垃圾郵件測試函數--------------
#切分本文
def textParse(bigString):
    import re
    listOfTokens = re.split(r'\W*', bigString)     #用除字母以及數字以外的任何字符分割
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]   #獲取字符數量大於2個的單詞,並將字母全部小寫化

def spamTest():
    #讀取貝葉斯訓練樣本
    docList = []; classList = []; fullText = []
    for i in range(1, 26):
        wordList = textParse(open('email/spam/%d.txt' % i).read())   #讀取文本
        docList.append(wordList)                #構建文本列表
        fullText.extend(wordList)
        classList.append(1)                     #標籤列表
        wordList = textParse(open('email/ham/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)         #構建詞向量
    trainingSet = range(50); testSet = []
    #隨機構建貝葉斯分類器測試樣本
    for i in range(10):
        randIndex = int(random.uniform(0, len(trainingSet)))    
        testSet.append(trainingSet[randIndex])      #隨機選擇文檔加入測試文檔
        del(trainingSet[randIndex])                 #將選入測試文檔的文檔從訓練文檔中剔除
    trainMat = []; trainClasses = []
    for docIndex in trainingSet:
        trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))   #創建訓練文檔對詞向量
        trainClasses.append(classList[docIndex])                        #標籤向量
    p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))    #貝葉斯訓練器訓練
    errorcount = 0
    for docIndex in testSet:
        wordVector = setOfWords2Vec(vocabList, docList[docIndex])       #測試文檔詞特徵向量構建
        if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:#測試
            errorcount += 1         #統計錯誤率
    print 'the error rate is: ', float(errorcount)/len(testSet)





**總結** 
1. 使用概率有時比使用硬規則更爲有效,貝葉斯概率及貝葉斯準則提供了一種利用已知值來估計未知概率的有效方法 
2. 可以通過特徵之間對條件獨立性假設,降低對數據量的需要。儘管條件獨立性假設並不正確,但是樸素貝葉斯仍然是一種有效的分類器 
3. 利用現代編程語言實現樸素貝葉斯時需要考慮很多實際因素。下溢就是其中一個問題,它可以通過對概率取對數來解決。詞袋模型在解決文檔分類問題上比詞集模型有所提高。還有其他一些方面的改進,比如說移除停用詞,當然也可以花大量事件對切分器進行優化。   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章