参考博客:朴素贝叶斯基础篇之言论过滤器 (po主Jack-Cui,《——大部分内容转载自
参考书籍:《机器学习实战》——第四章4.5
以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。过滤这类内容是一个很常见的需求。对此问题建立两个类型:侮辱类和非侮辱类,使用1和0分别表示(本demo最终构建了一个二分类器)。
我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。简单起见,我们先假设已经将本文切分完毕,存放到列表中,并对词汇向量进行分类标注。
准备数据包括3块:导入数据,创建词汇表,构建词向量
本demo的数据直接假设已经将文档切分成词条。数据包括6个切分好的文档词条和6个文档对应分类。
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):
vocabList = set([]) #创建一个空的set集合
for data in dataset: #遍历每个文档句子
vocabList = vocabList | set(data) #取与之前的词汇表的交集,目的在于去重
return list(vocabList) #返回list形式
本demo的目标是计算一篇文档在侮辱类c1和非侮辱类c2下的概率并比较两概率,预测该文档为最大概率的类
根据一般贝叶斯条件概率公式和朴素贝叶斯独立性的要求,可以得到概率公式
文档w (包含词汇w1~wn) 属于ci类 的概率p (ci|w) = p(w | ci) * p(ci) / p(w) = p(w1|ci)*...*p(wn|ci) * p(ci) / p(w)
因为我们只是要比较各类下文档w的概率,而分子p(w)都相同,在代码中计算可以省略,所以代码中的计算公式如下
p (ci|w) = p(w | ci) * p(ci) = p(w1|ci)*...*p(wn|ci) * p(ci)
本demo是个二分类。知道p1就可以用1-p1来计算p0,所以代码直接这样计算了。多分类需要稍加改动。
P(c1) = P1 = 训练集类标签为1的数量 / 训练集总数 = 侮辱类数量/ 训练集总数
即pAbuses = float(sum(trainCategory)) / float(numTrainDocs)
P(c0) = P0 = 训练集类标签为0的数量 / 训练集总数 = 1 - p1
p(wi | ci)该类下该单词出现的概率= 该类下该单词出现的次数 / 该类的单词总数,代码中为
p(w | ci) = p1Num / p1Denom
'''计算p(wi|ci) 和 p1
该类下,该单词出现的概率
需要计算每一类每个单词出现的次数(分子) 和 每一类出现过的总单词数(分母)
————————————————————————————————————————
参数:trainMatrix 训练集数据矩阵,多个doc的词汇表向量
trainCategory 训练集类矩阵
'''
def trainNB(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #文档数目
numWords = len(trainMatrix[0]) #词汇表单词总数
pAbuses = float(sum(trainCategory)) / float(numTrainDocs) # p1
p1Num = ones(numWords)
p0Num = ones(numWords) #记录每个单词在该类出现的次数,是一个向量
p1Denom = 2.0
p0Denom = 2.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])
p1Vec = log(p1Num / p1Denom)
p0Vec = log(p0Num / p0Denom)
return p0Vec,p1Vec,pAbuses
'''计算文档属于某个类别i的概率:p = p(w0|ci)p(w1|ci)p(w2|ci)~p(wn|ci)*p(ci)'''
def classiftNB(vec2classify,p0vec,p1vec,pclass1):
p1 = sum(vec2classify * p1vec) + log(pclass1)
p0 = sum(vec2classify * p0vec) + log(1 - pclass1)
if p1 > p0:
print "p1=%f" % p1
return 1
else:
print "p0=%f" % p0
return 0
#!/usr/bin/env python
#_*_coding:utf-8_*_
from numpy import *
'''
文本分类
'''
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):
vocabList = set([])
for data in dataset:
vocabList = vocabList | set(data)
return list(vocabList)
'''词汇转向量'''
def setOfWord2Vec(vocabList,dataset):
returnVec = [0] * len(vocabList)
for word in dataset:
if word in vocabList:
returnVec[vocabList.index(word)] = 1 #单词出现标1
else:
print "sorry this word %s is not in our vocablist" % word
return returnVec
'''计算p(wi|ci)
该类下,该单词出现的概率
需要计算每一类每个单词出现的次数(分子) 和 每一类出现过的总单词数(分母)
'''
def trainNB(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbuses = float(sum(trainCategory)) / float(numTrainDocs)
p1Num = ones(numWords)
p0Num = ones(numWords) #记录每个单词在该类出现的次数,是一个向量
p1Denom = 2.0
p0Denom = 2.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])
p1Vec = log(p1Num / p1Denom)
p0Vec = log(p0Num / p0Denom)
return p0Vec,p1Vec,pAbuses
'''计算文档属于某个类别i的概率:p = p(w0|ci)p(w1|ci)p(w2|ci)~p(wn|ci)*p(ci)'''
def classiftNB(vec2classify,p0vec,p1vec,pclass1):
p1 = sum(vec2classify * p1vec) + log(pclass1)
p0 = sum(vec2classify * p0vec) + log(1 - pclass1)
if p1 > p0:
print "p1=%f" % p1
return 1
else:
print "p0=%f" % p0
return 0
if __name__ == '__main__':
postingList, classVec = loadDataSet()
vocabList = createVocablist(postingList)
word2Vec = []
for data in postingList:
word2Vec.append(setOfWord2Vec(vocabList,data))
p0Vec, p1Vec, pAbuses = trainNB(word2Vec,classVec)
testList = ['love','my','dalmation']
test2Vec = setOfWord2Vec(vocabList,testList)
classResult = classiftNB(test2Vec,p0Vec,p1Vec,pAbuses)
if classResult == 1:
print "该文档分类为 侮辱性"
else:
print "该文档分类为 正常"