前言
朴素贝叶斯是一种十分简单的分类算法,称其朴素是因为其思想基础的简单性,就文本分类而言,他认为词袋中的两两词之间的关系是相互独立的,即一个对象的特征向量中的每个维度都是互相独立的。这是朴素贝叶斯理论的思想基础。
贝叶斯公式推导
朴素贝叶斯分类的正式定义:
- 设x={}为一个待分类项,而每个a为x的一个特征属性
- 有类别集合C={}
- 计算P(|x),P(|x),…,P(|x)
- 如果P(|x)=max{ P(|x),P(|x),…,P(|x)},则x
那么关键就是如何计算第三步中的各个条件概率,我们可以这样计算:
- 找到一个已知分类的待分类项集合,即训练集
- 统计得到在各类别下各个特征属性的条件概率估计,即:
P(),P(),…,P()
P(),P(),…,P()
P(),P(),…,P()
- 如果各个特征属性是条件独立的(或者假设他们之间是相互独立的),根据贝叶斯定理,有如下推导:
因为分母对于所有类别为常数,只要将分子最大化即可,又因为各特征属性是条件独立的,所以有:
根据上述分析,朴素贝叶斯分类的流程可以表示如下:
- 训练数据生成样本集:TF-IDF
- 对每个类别计算P()
- 对每个特征属性计算所有划分的条件概率
- 对每个类别计算P(x|)P()
- 以P(x|)P()的最大项作为x的所属类别
朴素贝叶斯的算法实现
首先创建一个Nbayes_pre.py文件来编写导入的数据和朴素贝叶斯类的代码
- 使用简单的英文语料作为数据集合,其中postingList是训练集文本,classVec是每个文本对应的分类
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','my'],
['stop','posting','stupid','worthless','garbage'],
['mr','licks','ate','steak','how','to','stop','hime'],
['quit','buying','worthless','dog','food','stupid']]
classVec=[0,1,0,1,0,1]#1 is abusive, 0 not
return postingList,classVec
- 下面逐步实现贝叶斯算法,第一步即编写一个贝叶斯算法类,并创建默认的构造方法
class NBayes(object):
def _init_(self):
self.vocabulary=[]#词典
self.idf=0#词典的IDF权重向量
self.tf=0#训练集的权值矩阵
self.tdm=0#P(x│y_i)
self.Pcates={}#P(y_i)是一个类别字典
self.labels=[]#对应每个文本的分类,是一个外部导入的列表
self.doclength=0#训练集文本数
self.vocablen=0#词典词长
self.testset=0#测试集
- 导入和训练数据集,生成算法必须的参数和数据结构
def train_set(self,trainset,classVec):
self.cate_prob(classVec)#计算每个分类在数据集中的概率P(y_i)
self.doclength=len(trainset)
tempset=set()
[tempset.add(word) for doc in trainset for word in doc]#生成词典
self.vocabulary=list(tempset)
self.vocablen=len(self.vocabulary)
self.calc_wordfreq(trainset)#计算词频数据集
self.build_tdm()#按分类累计向量空间的每维值P(x|y_i)
- 计算在数据集中每个分类的概率P(y_i)
def cate_prob(self,classVec):
self.labels=classVec
labeltemps=set(self.labels)#获取全部分类
for labeltemp in labeltemps:
self.labels.count(labeltemp)#统计列表中的重复分类
self.Pcates[labeltemp] =float(self.labels.count(labeltemp))/float(len(self.labels))
- 生成普通的词频向量
def calc_wordfreq(self,trainset):
self.idf=np.zeros([1,self.vocablen])#1x词典数
self.tf=np.zeros([self.doclength,self.vocablen])#训练集文件数x词典数
for indx in xrange(self.doclength):#遍历所有文本
for word in trainset[indx]:#遍历文本中的每个词
#找到文本的词在字典中的位置+1
self.tf[indx,self.vocabulary.index(word)]+=1
for signleword in set(trainset[indx]):
self.idf[0,self.vocabulary.index(signleword)]+=1
- 按分类累计计算向量空间的每维值P(x|y_i)
def build_tdm(self):
self.tdm=np.zeros([len(self.Pcates),self.vocablen])#类别行x词典列
sumlist=np.zeros([len(self.Pcates),1])#统计每个分类的总值
for indx in xrange(self.doclength):
#将同一类别的词向量空间值加总
self.tdm[self.labels[indx]]+=self.tf[indx]
#统计每个分类的总值——是一个标量
sumlist[self.labels[indx]]=np.sum(self.tdm[self.labels[indx]])
self.tdm=self.tdm/sumlist#生成P(x|y_i)
- 将测试集映射到当前词典
def map2vocab(self,testdata):
self.testset=np.zeros([1,self.vocablen])
for word in testdata:
self.testset[0,self.vocabulary.index(word)]+=1
- 预测分类结果,输出预测的分类类别
def predict(self,testset):
if np.shape(testset)[1]!=self.vocablen:#如果测试集长度与词典长度不相等,则推出程序
print("输入错误")
exit(0)
predvalue=0#初始化类别概率
predclass=""#初始化类别名称
for tdm_vect,keyclass in zip(self.tdm,self.Pcates):
#P(x|y_i) P(y_i)
#变量tdm,计算最大分类值
temp=np.sum(testset*tdm_vect*self.Pcates[keyclass])
if temp>predvalue:
predvalue=temp
predclass=keyclass
return predclass
- 算法还可以进行一些改进,将步骤e中的函数替换掉,普通的词频向量改为使用TF-IDF策略,使之有能力修正多种偏差,下面函数以TF-IDF方式生成向量空间
- 评估分类结果,执行我们创建的朴素贝叶斯类,获取执行结果
j. def calc_tfidf(self,trainset):
self.idf=np.zeros([1,self.vocablen])
self.tf=np.zeros([self.doclength,self.vocablen])
for indx in xrange(self.doclength):
for word in trainset[indx]:
self.tf[indx,self.vocabulary.index(word)]+=1
#消除不同句厂导致的偏差
self.tf[indx]=self.tf[indx]/float(len(trainset[indx]))
for signleword in set(trainset[indx]):
self.idf[0,self.vocabulary.index(signleword)]+=1
self.idf=np.log(float(self.doclength)/self.idf)
self.tf=np.multiply(self.tf,self.idf)#矩阵与向量的点乘 TFxIDF
l. import numpy as np
from numpy import *
from Nbayes_pre import *
dataSet,listClasses=loadDataSet()#导入外部数据集
#dataSet:句子的词向量
#listClass:句子所属的类别 【0,1,0,1,0,1】
nb=NBayes()#实例化
nb.train_set(dataSet,listClasses)#训练数据集
nb.map2vocab(dataSet[0])#随机选择一个测试句
print(nb.predict(nb.testset))
不知道为什么显示不了数学公式了非常尴尬,原文链接