朴素贝叶斯是基于条件概率的一种算法,之所以叫朴素是因为有两个假设条件:1.特征之间相互独立2.每个特征同等重要
朴素贝叶斯分类器(文本分类为例)有两种实现方式:1.贝努利模型——每个词等权重,只看出不出现,不考虑出现多少次2.多项式模型——考虑每个词出现的次数
优点:在数据较少的情况下仍然有效,可以处理多类别问题。
缺点:对于输入数据的准备方式较为敏感。
适用于数据类型:标称型数据。
使用Python进行文本分类
准备数据:从文本中构建词向量
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)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print "the word: %s is not in my Vocabulary!" % word
return returnVec
第一个函数相当于是提供了一个测试数据,第二个函数可以将输入的列表元素全部包含在一起并保证重复的词也只出现一次,第三个函数则显示输入的语句中的词在词汇表中的出现情况,出现的1,没出现的0。
故一旦给定一篇文档,该文档就会转化为词向量。
训练算法:从词向量计算概率
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #几条文本
numWords = len(trainMatrix[0]) #第一条文本多长
pAbusive = sum(trainCategory)/float(numTrainDocs) #类别为1的概率
p0Num = ones(numWords); p1Num = ones(numWords) #初始化求概率的分子分母变量 p0Denom = 2.0; p1Denom = 2.0 #change to 2.0 for i in range(numTrainDocs): if trainCategory[i] == 1: #如果文档是1 p1Num += trainMatrix[i] #分子按位置累加 p1Denom += sum(trainMatrix[i]) #计算单词总数目 else: p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i])
#防止太多很小的数相乘造成下溢,对乘积取对数
p1Vect = log(p1Num/p1Denom) #每个类别的每个单词的数目除以该类别的总数目得条件概率
p0Vect = log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive #返回两个向量和一个概率
p0Vect是一个向量,元素是每个词在该类别中出现的概率,p1Vect同上。 pAbusive是文档属于1的概率。
构建完整的分类器
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):#输入是要分类的向量,使用numpy数组计算两个向量相乘的结果,对应元素相乘,然后将词汇表中所有值相加,将该值加到类别的对数概率上。比较分类向量在两个类别中哪个概率大,就属于哪一类
p1 = sum(vec2Classify*p1Vec) + log(pClass1)
p0 = sum(vec2Classify*p0Vec) + log(1-pClass1)
if p1 > p0:
return 1
else:
return 0
def testingNB():#这是一个测试函数
listOPosts,listClasses = loadDataSet()#1
myVocabList = createVocabList(listOPosts)#2
trainMat = []
for postinDoc in listOPosts:#3
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))#这个是把训练文档中所有向量都转换成和词汇表类似的1,0结构
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))#4,经过四步就把训练样本训练好了,得到了想要的概率
testEntry = ['love','my','dalmation']
thisDoc = array(setOfWords2Vec(myVocabList,testEntry))#这个还是把词汇表和测试向量输入。
print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
testEntry = ['stupid','garbage']
thisDoc = array(setOfWords2Vec(myVocabList,testEntry))
print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
将每个词的出现与否作为一个特征,这被描述为词集模型,但一个词在文档中出现不止一次,就要使用词袋模型,在词袋中,每个单词可以出现多次。修改setOfWord2Vec():
def bagOfWords2VecMN(vocabList,inputSet):#这是词袋功能,就是若相同就加一,可以计算有几个相同的,上面那个只是相同就等于1,对一个文档中有相同词不好操作
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
#else:print "the word:%s is not in my Vocabulary!" %word
return returnVec