機械学習-素朴ベイズ分類


今日は図書館で一日勉強して、素朴なベイズの基本原理を理解しました.だから文章を書いて印象を深める.もちろんブログをお勧めします:ACdreamers-素朴ベイズ分類
一、ベイズの定理
条件の確率:
P(c|x⃗ )=P(x⃗ c)P(x⃗ )
ベイズの定理:
P(c|x⃗ )=P(c)P(x⃗ |c)P(x⃗ )
証明は次のとおりです.
P(c|x⃗ )=P(x⃗ c)P(x⃗ )
P(x⃗ |c)=P(x⃗ c)P(c)
二式を連立して消去する
P(x⃗c)はベイズ定理を得た.
二、素朴ベイズ分類器
ベイズ定理に基づいて確率P(c|x⃗)を推定する主な困難は,クラス条件確率P(x⃗|c)がすべての属性上の連合確率であり,限られた訓練サンプルから直接推定することが困難であることが分かった.この障害を回避するために,素朴ベイズ分類器は「属性条件独立性仮定」を採用した:既知のカテゴリに対して,すべての属性が互いに独立していると仮定した.
属性条件の独立性の仮定に基づいて、ベイズの定理は次のように書き換えることができます.
P(c|x⃗ )=P(c)P(x⃗ |c)P(x⃗ )=P(c)P(x⃗ )∏i=1dP(xi|c)
ここでdは属性数であり、xiはxのi番目の属性の値である.
素朴ベイズ分類原理
与えられた分類対象項目について,この項目が現れる条件の下で,各カテゴリが現れる確率を解き,分類対象項目は確率が最も大きいクラスに属する.
三、素朴なベイズを使って迷惑メールをフィルタリングする
イベントの定義:-c 0:迷惑メールではありません-c 1:迷惑メールです-w
以上より,すべてのP(ci|w⃗)を求め,そのイベントciが分類結果である最大のものを見つける必要があることが分かった.
トレーニングアルゴリズム
素朴ベイズ分類器によると:
P(ci|w⃗ )=P(ci)P(w⃗ |ci)P(w⃗ )=P(ci)P(w⃗ )∏j=1dP(wj|ci)
分類されるデータごとに
P(ci)と
P(w⃗ ) .訓練アルゴリズムによって得られるのは
∏dj=1P(wj|ci)
テストアルゴリズム
P(ci|w⃗)の値を計算し、その中で最も大きいものを取り、分類結果を得る.テストサンプルセットの結果と比較します.最後にエラー率を求める
コード#コード#
import numpy as np
import re, os, random

#  inputset        len(vocabList)   
def setOfWord2Vec(vocabList, inputset):
    returnVec = [0] * len(vocabList)
    for word in inputset:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
    return returnVec

#     filename      ,        
def file2vec(filename):
    returnVec = []
    fr = open(filename, 'r')
    regEx = re.compile("\W+")
    text = fr.read()
    returnVec.extend(regEx.split(text))
    fr.close()
    return [word.lower() for word in returnVec if len(word) > 2]

#      
def createVocabList(dataSet):
    returnVec = set([])
    for word in dataSet:
        returnVec |= set(word)
    return list(returnVec)

#     
def trainNB0(trainMatrix, trainCategory):
    numTrainMatrix = len(trainMatrix)
    numTrainWord = len(trainMatrix[0])
    pAbvious = sum(trainCategory) / float(numTrainMatrix)
    p0Num, p1Num = np.ones(numTrainWord), np.ones(numTrainWord)
    p0Denom, p1Denom = 2.0, 2.0
    for i in range(numTrainMatrix):
        #         ,   p1Num
        if trainCategory[i] == 1:
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p0Vect, p1Vect = np.log(p0Num / p0Denom), np.log(p1Num / p1Denom)
    return p0Vect, p1Vect, pAbvious

#   
def classifyNB(testSet, p0Vec, p1Vec, pAbvious):
    p0 = sum(testSet * p0Vec) + np.log(1.0 - pAbvious)
    p1 = sum(testSet * p1Vec) + np.log(pAbvious)
    if p0 > p1:
        return 0
    else:
        return 1


def spamTest():
    #       ,    ,
    docList, classList = [], []
    for i in range(1, 26):
        wordList = file2vec("spam/%d.txt" % i)
        docList.append(wordList)
        classList.append(1)
        wordList = file2vec("ham/%d.txt" % i)
        docList.append(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)
    trainingSet, testSet = list(range(50)), []
    #        
    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(setOfWord2Vec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V, p1V, pSpam = trainNB0(np.array(trainMat), trainClasses)
    errorCount = 0
    for index in testSet:
        word = setOfWord2Vec(vocabList, docList[index])
        if classifyNB(word, p0V, p1V, pSpam) != classList[index]:
            errorCount += 1
    print ("the error rate is:", float(errorCount) / len(docList))


if __name__ == '__main__':
    spamTest()

計算の際に上オーバーフローと下オーバーフローの問題を考慮し,それぞれ対応する処理を行った.具体的に『機械学習実戦』4.5.3節に参加する
このアルゴリズムに基づいて,データセットがランダムに分割され,ランダム結果の最大誤り率が4%(必ずしも正確ではない)であるため,複数回のテスト(同じデータセット)を行った.
まとめ
利点:データが少ない場合でも有効であり、多種類の問題と欠点を処理できる:入力データの準備方式に敏感にデータ型を使用する:公称型データ
余談を言う
どうしてCSDNのmarkdownコードのブロックはプレビューの时とてもきれいな感じがします...どうして発表した后にとてもみっともない感じがします....ロードされたスタイルシートは違いますか....