目录
贝叶斯决策理论
进行文本分类
准备数据:从文本中构建词向量
训练算法:从词向量计算概率
测试算法:根据现实情况修改分类器
文档词袋类型
使用贝叶斯过滤垃圾邮件
贝叶斯决策理论
比较一个确定的点属于不同类别的概率,哪个概率大,属于哪一类。
优点:在数据较少的情况下仍然有效,可以处理多类别问题。
缺点:对于输入数据的准备方式较为敏感。
适用数据类型:标称型数据
一般过程:
1.收集数据
2.准备数据:需要数值型或布尔型数据
3.分析数据:有大量特征时,使用直方图效果更好
4.训练算法:计算不同的独立特征的条件概率
5.测试算法:计算错误率
6.使用算法:一个常见的朴素贝叶斯应用是文档分类。
贝叶斯公式:
- P(A|B)是已知B发生后A的条件概率,也由于得自B的取值而被称作A的后验概率,表示事件B发生后,事件A发生的置信度。
- P(A)是A的先验概率或边缘概率,表示事件A发生的置信度。
- P(B|A)是已知A发生后B的条件概率,也由于得自A的取值而被称作B的后验概率,也被称作似然函数。
- P(B)是B的先验概率或边缘概率,称为标准化常量。
- P(B|A)P(B)称为标准似然比,表示事件B为事件A发生提供的支持程度。
最大似然估计:完全从样本入手,使得观测数据(样本)发生概率最大的参数,即P(X|θ)最大的参数θ就是最好的参数,如抛硬币10次6次正,最大似然估计认为抛一次为正的概率为0.6
最大后验概率估计:事先知道抛硬币为正的概率是0.5,认为使P(X|θ)P(θ)取最大值的θ就是最好的θ,因此以0.5和最大似然估计计算得到θ=0.57
贝叶斯估计:在最大后验估计的基础上,不是估计θ的值,而是估计一个范围,约为0.5625
参考自:贝叶斯估计、最大似然估计、最大后验概率估计 | SnailTyan (noahsnail.com)
进行文本分类
要从文本中获取特征,需要先拆分文本。具体的特征词条可以是URL、IP地址或者任意字符串,1表示词条出现,0表示未出现。
准备数据:从文本中构建词向量
从文本中构建词向量,将句子转化成向量。
以在线社区留言板为例,我们要屏蔽侮辱性言论,侮辱类词汇为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]
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的列表
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1 #某词汇出现过,0变成1
else:
print(f'the word: {word} is not in my Vocabulary!')
return returnVec #输出一个0或1组成的列表,表示数据集中所有出现过的词汇 在某个数据中是否出现(1,0)
正常情况下不会出现 某词汇在集合中不存在的情况
listOPosts,listClasses = loadDataSet() myVocabList = createVocabList(listOPosts) print(setOfWords2Vec(myVocabList,listOPosts[3]))
输出:[0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
训练算法:从词向量计算概率
#输入参数为文档矩阵trainMatrix(即上面函数输出的returnVec),和先验的每篇文档类别标签所构成的向量trainCategory
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix) #训练数据量
numWords = len(trainMatrix[0]) #每个数据要训练多少个词
pAbusive = sum(trainCategory)/float(numTrainDocs)#p(class=1),p(class=0)=1-p(class=1)
p0Num = np.zeros(numWords)
p1Num = np.zeros(numWords)
p0Denom = 0.0
p1Denom = 0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i] #向量形式统计class=1中所有词出现的次数[2,3,4,0...]
p1Denom += sum(trainMatrix[i]) #单数形式统计class=1中所有词出现的次数9
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num/p1Denom #class=1中每个词出现占所有词出现总次数的比例,即p(wi|c=1)
p0Vect = p0Num/p0Denom
return p0Vect,p1Vect,pAbusive
trainMat = [] #是数据集中所有数据行 用我们的数据集合表示的列表[[1,0,1,0...],[],[]...]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
p0v,p1v,pab = trainNB0(trainMat,listClasses)
p0v=
pab=0.5
测试算法:根据现实情况修改分类器
要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(w0|c=1)p(w1|c=1)p(w2|c=1)。如果其中一个概率值为0,那么最后乘积也是0,所以将所有词出现的初始化为1,总数初始为2。
p0Num = np.ones(numWords)
p1Num = np.ones(numWords)
p0Denom = 2.0
p1Denom = 2.0
另一个问题是下溢出,即计算结果太小会近似为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
测试:
def testingNB():
listOPosts,listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat = [] #是数据集中所有数据行 用我们的数据集合表示的列表[[1,0,1,0...],[],[]...]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
p0v,p1v,pab = trainNB0(trainMat,listClasses)
testEntry = ['love','my','dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList,testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0v,p1v,pab))
testEntry = ['stupid','garbage']
thisDoc = np.array(setOfWords2Vec(myVocabList,testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0v,p1v,pab))
结果:
文档词袋类型
词集模型:每个词出现与F否
词袋模型:每个词出现次数
对函数sefOfWords2Vec修改:
def bagOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1 #某词汇出现过,+1
else:
print(f'the word: {word} is not in my Vocabulary!')
return returnVec
使用贝叶斯过滤垃圾邮件
准备数据:切分文本
#准备数据
def textParse(bigString):
listOfTokens = re.split(r'W*',bigString)
return [tok.lower() for tok in listOfTokens if len(tok)>2]
def spamTest():
docList = []
classList = []
fullText = []
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList = textParse(open('email/ham/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)
trainingSet = list(range(50)) #共50个样本
testSet = []
for i in range(10): #随机取10个样本做测试集,存入testSet
randIndex = int(np.random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex]) #trainingSet中剩下的是训练集
trainMat = []
trainClass = []
for docIndex in trainingSet:
trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
trainClass.append(classList[docIndex])
p0v,p1v,pspam = trainNB0(np.array(trainMat),np.array(trainClass))
errorcount = 0
for docIndex in testSet:
wordVector = setOfWords2Vec(vocabList,docList[docIndex])
if classifyNB(np.array(wordVector),p0v,p1v,pspam)!=classList[docIndex]:
errorcount+=1
print(f'error rate:{float(errorcount)/len(testSet)}')
一直输出0.6!正则表达式的问题!改成‘/w’就好了!
由于测试集是随机抽取10封,因此,多次运行程序,结果不同,多为0,偶尔为0.1、0.2



