朴素贝叶斯算法文本分类应用

朴素贝叶斯的中心思想,在于利用各类别在训练样本中的分布以及类别中各特征元素的分布,计算后验概率,使用极大似然法判断测试样本所属。出于该原理,使用该算法实现文本分类的局限性较多,例如训练集中各类样本的比例不能相差过大,比例较大的样本类别会获得更高的划分可能性;其次,该算法假设词与词之间相互独立,共享权重,忽视了词与词之间的关联性,面临共指消解 (同一实体不同表述) 的问题,因此只能用于诸如垃圾邮件识别的简单分类。

以下代码来自郑捷所著《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)

你可能感兴趣的:(算法,自然语言处理)