使用朴素贝叶斯的一般流程为:
- 收集数据;
- 准备数据:需要数值型或布尔型数据
- 分析处理数据:绘制特征,特征选择
- 训练算法:计算不同的独立特征的条件概率
- 测试算法;
- 使用算法:这里是利用朴素贝叶斯进行文档分类
要从文本中获取特征,首要的是拆分文本。文本的特征来源于词条(token),一个词条可以是字符的任意组合。每一个文本片段表示为一个词条向量,向量中的值为1表示该词条在文档中出现,0表示该词条未出现。这样文本就看做单词向量或词条向量,句子即被转化为向量。
数据准备:从文本中构建词向量
"""词表到向量的转换函数""" 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] #上述六句话(词表)类型向量,1代表侮辱性言论,0代表正常言论 return postingList,classVec """创建一个包含在所有文档中出现的不重复词的列表""" def createVocabList(dataSet): vocabSet=set([]) #创建一个空集 for document in dataSet: vocabSet=vocabSet | set(document) #创建并集 return list(vocabSet) """判断词汇表中的单词是否在输入文档中出现""" def setOfWords2Vec(vocabList,inputSet): returnVec=[0]*len(vocabList) #创建一个长度和词汇表一样的全0向量 #循环遍历,查看文档inputSet中的单词是否出现在词汇表中 for word in inputSet: if word in vocabList: returnVec[vocabList.index(word)]=1 #将输出向量中相应的位置置为1 else: print("{}在词汇表中没有出现".format(word)) return returnVec #返回向量训练算法:从单词向量中计算概率
现在知道的信息有:
- 某一个单词是否出现在文档中
- 该文档所属的类别
"""朴素贝叶斯训练器函数""" def trainNB0(trainMatrix,trainCategory): #输入参数为文档矩阵和每篇文档类别标签所构成的向量 #注意这里的文档矩阵实际上是词汇表中的单词在每一个文档中是否出现的判断矩阵,是由setOfWords2Vec函数求得的 numTrainDocs=len(trainMatrix) #训练的文档数 numWords=len(trainMatrix[0]) #词汇表中包含的所有单词数 pAbusive=sum(trainCategory)/float(numTrainDocs) #计算侮辱性文档的概率,因为1为侮辱,0为正常,所以sum侮辱性的数目 #初始化概率 p0Num=zeros(numWords) #由所有单词数来初始化用于计数正常单词数的向量 p1Num=zeros(numWords) #由所有单词数来初始化用于计数侮辱性单词数的向量 p0Denom=0.0 #正常文档的总词数 p1Denom=0.0 #侮辱性文档的总词数 for i in range(numTrainDocs): #循环遍历文档 if trainCategory[i]==1: #如果该文档标签被定义为侮辱性文档 p1Num+=trainMatrix[i] #就将trainMatrix中的向量值加到向量p1Num中,因为侮辱性词语值为1,正常词语值为0 p1Denom+=sum(trainMatrix[i]) #增加侮辱性文档的总词汇数 else: p0Num+=trainMatrix[i] p0Denom+=sum(trainMatrix[i]) p1Vect=p1Num/p1Denom #侮辱性词汇的概率 p0Vect=p0Num/p0Denom return p0Vect,p1Vect,pAbusive
然而有一个问题,由于朴素贝叶斯假定每个特征是相互独立的,故若在某一分类(侮辱性/正常)下某一词汇出现的概率为0,则概率的乘积就会为0,因此要进行“平滑处理”,常见的办法就是拉普拉斯修正。这里我们可以将所有词的出现数初始化为1,并将坟墓初始化为2。代码做如下修改:
p0Num=ones(numWords) #由所有单词数来初始化用于计数正常单词数的向量 p1Num=ones(numWords) #由所有单词数来初始化用于计数侮辱性单词数的向量 p0Denom=2.0 #正常文档的总词数 p1Denom=2.0 #侮辱性文档的总词数
另一个问题是,很多很小的概率相乘结果容易溢出,所以修改代码为:
p1Vect=log(p1Num/p1Denom) #侮辱性词汇的概率 p0Vect=log(p0Num/p0Denom)
构建朴素贝叶斯分类器
根据朴素贝叶斯计算出来的概率,对文档进行分类。
"""构建朴素贝叶斯分类器函数""" def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1): p1=sum(vec2Classify*p1Vec)+log(pClass1) p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1) if p1>p0: return 1 else: return 0