樸素貝葉斯算法文本分類應用

樸素貝葉斯的中心思想,在於利用各類別在訓練樣本中的分佈以及類別中各特徵元素的分佈,計算後驗概率,使用極大似然法判斷測試樣本所屬。出於該原理,使用該算法實現文本分類的侷限性較多,例如訓練集中各類樣本的比例不能相差過大,比例較大的樣本類別會獲得更高的劃分可能性;其次,該算法假設詞與詞之間相互獨立,共享權重,忽視了詞與詞之間的關聯性,面臨共指消解 (同一實體不同表述) 的問題,因此只能用於諸如垃圾郵件識別的簡單分類。

以下代碼來自鄭捷所著《NLP漢語自然語言處理,原理與實踐》

import numpy as np
class NaiveBayes(object):
    '''
    算法原理:
    	- 訓練
        	i.借用TF-IDF中TF的概念生成詞頻矩陣TF
        	ii.計算各個分類的邊緣概率P(yi)
        	iii.計算各個分類的後驗詞頻分佈P(x|yi)
        - 預測
        	i.計算測試詞頻TF
        	ii.對每個分類計算TF*P(x|yi)*P(yi),以最大項作爲預測類別
    '''
    def __init__(self):
        self.train = []    #訓練集
        self.label = []    #訓練集標籤
        self.vocab = []    #詞集
        self.tf = None    #TF矩陣(row:訓練集數量 col:詞集詞頻)
        self.idf = None    #IDF向量(詞集長度)
        self.prob = {}    #P(yi)
        self.con_prob = None    #P(x|yi) (row:類別 col:詞集詞頻)
    def fit(self,train,label):
        '''導入訓練集,生成算法參數'''
        assert isinstance(train,list)
        assert isinstance(label,list)
        assert len(train) == len(label)
        self.train += train
        self.label += label
        vocab = set()
        [vocab.add(word) for text in train for word in text];    #將詞語導入詞集
        self.vocab = list(vocab)
        self.cal_prob()    #計算分類的邊緣概率P(yi)
        self.cal_tfidf()    #計算TF-IDF
        self.cal_con_prob()    #計算後驗概率分佈:P(x|yi)
    def cal_prob(self):
        '''針對每個分類計算P(yi)'''
        for y in set(self.label):
            self.prob[y] = float(self.label.count(y)/len(self.label))    #計算每個分類在數據集中的概率:P(yi)
    def cal_tfidf(self):
        '''生成TF矩陣和IDF向量'''
        self.tf = np.zeros((len(self.train),len(self.vocab)))
        self.idf = np.zeros(len(self.vocab))
        for idx in range(len(self.train)):    
            for word in self.train[idx]:
                self.tf[idx,self.vocab.index(word)] += 1
            self.tf[idx] = self.tf[idx]/len(train[idx])    #消除不同句長導致的偏差
            for word in set(self.train[idx]):
                self.idf[self.vocab.index(word)] += 1
        self.idf = np.log(len(self.train)/self.idf)
    def cal_con_prob(self):
        '''計算後驗概率分佈:P(x|yi)'''
        self.con_prob = np.zeros((len(self.prob),len(self.vocab)))
        con_sum = np.zeros((len(self.prob),1))    #統計每個分類的總值
        for idx in range(len(self.train)):
            self.con_prob[self.label[idx]] += self.tf[idx]    #將同一類別的TF矩陣按列加總
        for y in self.prob.keys():
            con_sum[y] = np.sum(self.con_prob[y])    #統計每個分類的概率分佈總值
        self.con_prob = self.con_prob/con_sum    #歸一化生成P(x|yi)
    def predict(self,test): 
        '''針對每個分類計算TF*P(x|yi)*P(yi),輸出最大值所在分類作爲預測分類'''
        assert isinstance(test,list)
        assert isinstance(test[0],str)
        if len(set(test)-set(self.vocab)) > 0:    #如果測試集包含詞集裏沒有的詞,則退出程序
            raise ValueError('測試集中包含訓練集中未出現過的詞,請重新輸入')
        test_tf = np.zeros([1,len(self.vocab)])
        for word in test:
            test_tf[0,self.vocab.index(word)] += 1    #生成測試集TF矩陣
        test_tf /= len(self.vocab)
        pred_prob = []
        for y in self.prob.keys():
            pred_prob += [np.sum(test_tf * self.con_prob[y] * self.prob[y])]    #計算計算TF*P(x|yi)*P(yi)
        return np.argmax(pred_prob)
if __name__ == '__main__':
    train = [['我們','常常','仰望','和','羨慕','別人','的','幸福'],
             ['一','回頭','卻','發現','自己','也','正','被','仰望','和','羨慕','着'],
             ['其實','每個','人','都','是','幸福','的'],
             ['只是','你','的','幸福','常常','在','別人','眼裏']]
    label = [0,1,2,1]
    test = train[0]
    model = NaiveBayes()
    model.fit(train,label)    #模型訓練
    pred = model.predict(test)    #模型預測
    print('Prediction result: %s'%pred)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章