實驗一貝葉斯分類器的設計以及應用試驗


實驗目的:
           理解朴素貝葉斯分類器的原理;
           能夠獨立實現貝葉斯分類器的設計;
           能夠評估分類器的精度。
實驗步驟:
1.朴素貝葉斯分類器原理理解
  1. 貝葉斯決策理論
    假設有一個數據集,由兩類組成,對於每個樣本分類如下:

現在有一個新的點new_point(x,y),其分類未知。用p1(x,y)表示點(x,y)屬於紅色分類的概率,p2(x,y)表示該點為藍色的分類的概率、
制定以下規則:

用等價的條件概率表示如下:

將p(red|x)記錄為p(c1|x),p(blue|x) 記錄為p(c2|x),那么貝葉斯公式如下:

出現一個新的需要分類的點時候。我們只需要計算

2. 朴素貝葉斯分類

朴素貝葉斯分類的正式定義如下:

  • 朴素貝葉斯有一個很強的條件假設 * , 當Yi確定時 ,yi的各個特征之間相互獨立。

二、使用朴素貝葉斯進行文本分類(詞集模型)

文本中的特征來自於文本的詞條 (token),一個詞條是字符的任意組合。

1. 准備數據: 從文本中構建詞向量

確定將那些詞納入詞匯集合,然后將每一篇輸入文本轉換為與詞匯表同緯度的向量。
####### 1. 創建實驗樣本,這些文本被切分為一系列詞條集合,將標點從文本中去除。另外返回類別標簽集合。

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
2、創建詞匯表 詞集模型 即包含所有詞的列表
def createVocabList(dataSet):
    vocab_set = set([])
    for document in dataSet:
        vocab_set = vocab_set | set(document)
    
    return list(vocab_set)
3、結合詞匯表 將輸入文檔轉換為文檔向量
### 結合詞匯表 將輸入文檔轉換為文檔向量
### 返回值類似[1,0,1,0 ....]
def setWordsToVect(vocabList,inputSet):
    returnVec = [0] * len(vocabList)
    for word in inputSet: #遍歷輸入的每個詞條
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print("the word:%s not in vocabList" % word)
    
    return returnVec
4、訓練算法
### 訓練算法
def trainNBO(trainMatrix,trainGategory):
    """
    :param trainMatrix 文件的單詞矩陣[[0,1,0,1],....[0,1,1]]
    :param trainGategory 文件對應的標簽類別 [0,1,1...],對應1代表侮辱,0代表不是侮辱
    return:
    : p0Vect: 各單詞在分類0下的概率
    :p1Vect: 各單詞在分類1下的概率
    :pAbusive : 文檔屬於分類1的概率
    """
    numTrainDocs = len(trainMatrix) #文件數
    numWords = len(trainMatrix[0])# 單詞數
    
    pAbusive  = sum(trainGategory)/float(numTrainDocs) #初始化文件數
    #p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
    p0Num = np.ones(numWords); p1Num = np.ones(numWords)
    #p0Denom = 0.0; p1Denom = 0.0
    p0Denom = 2.0; p1Denom = 2.0
    for i in range(numTrainDocs):
        if trainGategory[i] == 1:
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    
    p1Vect = p1Num/p1Denom
    p0Vect = p0Num/p0Denom
    
    return p0Vect, p1Vect,pAbusive
6.
"""
將所有的單詞出現數初始化為1, 將分母初始化為2  將trainNBO()的第4和第五行修改如下: 
    pAbusive  = sum(trainCategory)/float(numTrainDocs) #初始化文件數
    #p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
    p0Num = np.ones(numWords); p1Num = np.ones(numWords)
    #p0Denom = 0.0; p1Denom = 0.0
    p0Denom = 2.0; p1Denom = 2.0
"""
7.朴素貝葉斯分類函數
### 朴素貝葉斯分類函數
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    """
    :param vec2Classify 測試向量文檔
    :param p0Vec:非侮辱詞匯 在詞匯表中單詞的概率
    :param p1Vec: 侮辱性詞匯  
    :param pClass1: 侮辱性的先驗概率
    """
    #做對數映射
    p1 = sum(vec2Classify * p1Vec) + math.log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + math.log(pClass1)
    
    if p1 > p0:
        return 1
    else:
        return 0
8.打印函數
def printClassierResult(sentense,sentenseType):
    print(sentense)
    if sentenseType ==1:
        print("這是侮辱性語句")
    else:
        print("這不是侮辱性語句")
9. 加載測試數據
def loadTestSet():
    testList = [['It`s','worthless','to','stop','my','dog','eating','food'],
                ['Please','help','me','to','solve','this','problem'],
                ['This','dog','is','so','stupid',',','But','that','one','is','so','cute'],
                  ]
    return testList
10. 開始測試
if __name__ == '__main__':
    ## 訓練
    postingList,classVec = loadDataSet()
    vocab_set = createVocabList(postingList)
    messageMatrix = []
    for sentence in postingList:
        message = setWordsToVect(vocab_set,sentence)
        messageMatrix.append(message)
        
    p0Vect,p1Vect,pAbusive = trainNBO(messageMatrix,classVec)
    
    ##test 詞匯集
    testList = loadTestSet()
    for sentence in testList:
        sVec = setWordsToVect(vocab_set,sentence)
        sType = classifyNB(sVec,p0Vect,p1Vect,pAbusive)
        printClassierResult(sentence,sType)
        

運行結果:


修改分類器 詞袋模型
### 使用朴素貝葉斯進行文本的分類(詞袋模型)
### 在詞袋模型中每個單詞可以出現多次,當遇到一個單詞時,就會增加詞向量的對應值,而不是將
### 將對應的一個數值設為1
### 其中詞集模型 setOfWord2Vec()被替換成bagOfWord2Vec()
def bagOfWord2Vec(vocbList,inputSet):
    """
    param:vocabList 詞匯列表
    param: inputSet 文檔
    return:詞匯向量
    """
    returnVec = [0] * len(vocbList)
    for word in inputSet:
        if word in vocbList:
            returnVec[vocbList.index(word)] +=1 #記錄單詞出現出現的次數,而不是出現與否
    return returnVec

####### 添加詞袋模型的測試函數

    ### test 詞袋模型
    
    for sentence in testList:
        sVec = bagOfWord2Vec(vocab_set,sentence)
        sType = classifyNB(sVec,p0Vect,p1Vect,pAbusive)
        printClassierResult(sentence,sType)

運行結果:

評價

1、首先朴素貝葉斯有一個很強的假設:各特征之間有很強的獨立性。但實際上語義之間是有上下文聯系的。比如當一句話中出現太多貶義詞,
    但實際是表達褒義的時候,可能有錯誤分類。比如這里:
![](https://img2020.cnblogs.com/blog/1826521/202004/1826521-20200419134000307-70619174.png)

2、word2vec 這種算法 會考慮上下文,比Embedding效果要好,維度更少,通用性也強。但是由於詞和向量是一一對應的,所以無法解決一詞多義的問題。
    而且這種靜態方法,無法針對特定任務做動態優化。
3.選用詞袋模型,當某個單詞出現多次時,可以增加該單詞在某類別的權重,這里數據太小。實驗效果沒有明顯修正。比如這里:
![](https://img2020.cnblogs.com/blog/1826521/202004/1826521-20200419134000307-70619174.png)
4. 注意這里的修改:
    #p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)
    p0Num = np.ones(numWords); p1Num = np.ones(numWords)
    #p0Denom = 0.0; p1Denom = 0.0
    p0Denom = 2.0; p1Denom = 2.0
這里是避免如果出現訓練集未出現的詞匯,可能導致概率為0的情況,影響分類效果。

課程實驗


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM