『機械学習実戦』学習ノート(三)——素朴ベイズ

4148 ワード

第4章の内容「確率論に基づく分類方法——素朴ベイズ」は3つの例を逐次漸進的に説明した.
  • 簡単な文分類(abusive or not)
  • スパムフィルタ
  • 個人広告から地域傾向
  • を取得する.

    簡単な文の分類

  • トレーニングセットとテストセット
  • を取得
  • トレーニングセットのすべてのサンプルを分析し、テストセットの語彙リストvocabListと各サンプルの記述ベクトル、すなわちvocabListの中の語がこのサンプルに現れるかどうか、現れると対応する値は1であり、そうでなければ0である.
  • 素朴ベイズ式に基づいて試験セットの各サンプルの事後確率を計算し、各サンプルの予測分類
  • を得る.
    注意と改善が必要な2つの場所
  • 後験確率を計算する際には、複数の確率値を乗算する必要があるため、いずれかの確率値が0になると、結果は0になる(意味がない).これを避けるために分子numeratorを1に初期化し,分母denominatorを2に初期化した.
  • 一般的には、ほとんどの確率値は小さく、多くの小さな数が乗算されるとunderflowの現象、すなわちpythonでの結果は0になる.従って、対数をとる方式で複数の小確率値の乗算を複数の小確率値が対数を取った結果の加算に変換することができる.
  • import numpy as np
    import math
    def loadDataSet():
        postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                       ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                       ['my', 'dalmatian', '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 is abusive, 0 is not
        return postingList, classVec
    # create a list of all the unique words in all of our documents
    def createVocabList(dataSet):
        vocabSet = set([])
        for document in dataSet:
            vocabSet = vocabSet | set(document)
     # create the union of two sets
        return list(vocabSet)
    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:', word, 'is not in my Vocabulary!')
        return returnVec
    '''
    def bagOfWords2Vec(vocabList, inputSet):
        returnVec = [0] * len(vocabList)
        for word in inputSet:
            if word in vocabList:
                returnVec[vocabList.index(word)] += 1
        return returnVec
    '''
    def trainNB0(trainMatrix, trainCategory):
        numTrainDocs = len(trainMatrix)
        numWords = len(trainMatrix[0])
        pAbusive = sum(trainCategory) / float(numTrainDocs)
        # numerator / denominator
        p0Num = np.ones(numWords)
        p1Num = np.ones(numWords)
        p0Denom = 2.0
        p1Denom = 2.0
        for i in range(numTrainDocs):
            # vector addition
            if trainCategory[i] == 1:
                p1Num += trainMatrix[i]
                p1Denom += sum(trainMatrix[i])
            else:
                p0Num += trainMatrix[i]
                p0Denom += sum(trainMatrix[i])
        # to avoid underflow based on the equation log(a * b) = log(a) + log(b)
        p0Vect = np.log(p0Num / p0Denom)
        p1Vect = np.log(p1Num / p1Denom)
        return p0Vect, p1Vect, pAbusive
    def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
        # vec2Classify is a vector to classify
        p1 = sum(vec2Classify * p1Vec) + math.log(pClass1)
        p0 = sum(vec2Classify * p0Vec) + math.log(1.0 - pClass1)
        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(trainMat, listClasses)
        testEntry = ['love', 'my', 'dalmatian']
        thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
        print(testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
        testEntry = ['stupid', 'garbage']
        thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
        print(testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
    

    個人広告から地域傾向を得る


    更新対象