优点:在数据较少的情况下仍然有效,可以处理多类别问题。
缺点:对于输入数据的准备方式较为敏感。
1.使用条件概率来分类:
两个概率p1(x,y)和p2(x,y):
如果 p1(x,y)>p2(x,y),则属于类别1,反之属于类别2.上述只是尽可能简化的描述,真正需要比较和计算的是p(c1|x,y)和p(c2|x,y),意义是对于给定的数据点x,y,该数据点来自类别c1和c2的概率,可以shiyoong贝叶斯来交换概率中的条件与结果。
p(ci|x,y) = [p(x,y|ci)p(ci)]/p(x,y)
如此便可以通过三个已知的概率论值来计算未知的概率论值。
2.使用python进行文本分类:
先拆分文本,从文本中获取特征,这些特征就是来自文本的词条,将每一个文本片段表示为一个词条向量,1代表词条出现在片段中,0代表没有出现。
2.1 准备数据:从文本中构建词向量
将文本看成单词向量或词条向量,首先考虑出现在所有文档中的所有单词,在决定将哪些词纳入词汇表,然后必须将每一篇文档转换为词汇表上的向量。
from numpy import *
from math import log
#词表到向量的转换函数
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']]
#1代表侮辱性文字,0代表正常言论
classVec = [0,1,0,1,0,1]
return postingList,classVec
#将多个数据列表整合到单个无重复元素列表中
def createVocabList(dataSet):
vocabSet = set([])
for document in dataSet:
#取两个集合的并集
vocabSet = vocabSet | set(document)
return list(vocabSet)
#将词列表转换为向量
def setOfWord2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
#将词集中对应单词的的索引值置为1
returnVec[vocabList.index(word)]=1
else:print("the word:%s is not in my Vocabulary"%word)
return returnVec
createVocabList()会创建一个包含在所有文档中出现的不重复词的列表。使用了set数据结构,将词条列表传递给set构造函数会返回一个不重复的词表。
2.2训练算法:从词向量计算概率
重写贝叶斯准则,将x,y替换为w,w表示为一个向量,即它由多个数值组成,当前例子中数值的个数与词个数相同。
p(ci|w)=p(w|ci)p(ci)/p(w)
首先可以通过类别i中的文档数/总文档数来计算概率p(ci),接下来计算p(w|ci),如果将w展开为一个个独立特征,那么就可以将上述概率写为p(w0,w1...wn|ci),这里假设所有数值相互独立,条件独立假设可以通过p(w0|ci)p(w1|ci)...p(wn|ci)来计算上述概率。
#朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
#得到概率p(x=1)
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = zeros(numWords)
p1Num = zeros(numWords)
p0Denom = 0.0
p1Denom = 0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
#得到每个单词对应的概率,即在类别中的权重大小
p1Vect = p1Num/p1Denom
p0Vect = p0Num/p0Denom
return p0Vect,p1Vect,pAbusive
输入参数为文档矩阵trainMatrix,以及由每篇文档类别标签所构成的向量trainCategory,首先计算文档属于侮辱性文档的概率p(class=1) ,遍历trainMarix中的所有文档,分别统计该类别中词的总个数和各个词数值出现的次数,最后将次数/总个数得到两个类别的各词的概率。值得注意的是:用一个数组除以浮点数的操作在常规python列表中很难实现,因此借用numpy矩阵。
2.3测试算法:根据现实情况修改分类器
要计算该类别多个概率的乘积以获得文档属于类别的概率,即计算p(w0|ci)p(w1|ci)...p(wn|ci)。如果其中一个概率值为0,最后乘积也为0,可以将所有词出现的次数初始化为1,并将分母初始化为2.
p0Num = ones(numWords);p1Num = ones(numWords);
p0Debom = 2;p1Denom = 2
另外太多很小的数相乘会下溢出,因此可以对乘积取自然对数。
#朴素贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
#分别得到p(y=1|x)和p(y=0|x)的概率
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()
myVocablist = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWord2Vec(myVocablist,postinDoc))
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
testEntry = ['love','my','dalmation']
thisDoc = array(setOfWord2Vec(myVocablist,testEntry))
print(testEntry,'classifed as:',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid','garbage']
thisDoc = array(setOfWord2Vec(myVocablist,testEntry))
print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))
array函数是从常规的python数列和元组创建Numpy矩阵的形式。vec2Classify*p1Vec是求内继,将各个数值与其对应的特征犬只相乘,即得到该词向量的在确定类别下的概率,通过比较在两个类别下的概率大小确定该词向量属于哪个类别。
2.4文档词袋模型
将每个词出现与否作为特征的描述称为词集模型。一个词在词中出现多次这种情况在词集中无法被描述,描述词在词典中出现次数的模型是词袋模型。
# 朴素贝叶斯词袋模型
def bagOfWords2VecMN(vocabList,inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec