贝叶斯分类器的分类原理是通过某对象的先验概率,利用贝叶斯公式计算出其后验概率,即该对象属于某一类的概率,选择具有最大后验概率的类作为该对象所属的类。
介绍一下先验概率:是指根据以往经验和分析得到的概率,就是我们可以通过我们已经得到的训练集得到的概率
后验概率:就是我们要求得、要预测的概率,并且通过这种概率去估计样本的可能类别。
贝叶斯分类器的原理就是基于这个贝叶斯公式 。
我们把x看成一个新的样本的特征,w看成样本的可能结果 (就是可能存在的类别)左边的公式的意义就是在x的条件下出现w这种情况的概率。也就是我们所说的后验概率,这个概率可以通过右边的项求得。
对于右边的式子我们可以看出 p(x) 对于所有的 w 来说是一个常数,我们需要关心的就是分子上的两项的大小(就是利用先验概率对分子作出一个合理的估计)
朴素贝叶斯分类器与贝叶斯分类器的原理一致,但是朴素贝叶斯公式有两个默认的前提条件 :
1. 各个特征之间相互独立
2. 各个特征同等重要
认为每个特征之间不存在依赖关系根据相互独立事件的概率公式可以得到朴素的贝叶斯公式
由于p(yi) 的概率都是一样的所以我们关心的还是右边的概率的大小,估计的方法与上面的一致,就是用最大似然法进行估计。
首先先介绍一下为什么需要拉普拉斯修正,因为我们的样本集有限,对于某些离散的值可能并没有出现,这样的话会导致乘积的概率为0,严重影响了我们最终的分类结果,显然不是我门想要的结果,这样就出现了拉普拉斯修正方法。
拉普拉斯修正方法 : 就是对于一个离散的值我们在使用的时候不是直接输出它的概率,而是对概率值进行“平滑” 处理。即默认所有的特征都出现过一次,将概率改成下面的形式 其中 N 是全体特征的总数。
D是指的这一类的总数目。
这样就避免了概率值为0的情况。
由于贝叶斯分布需要对很多个很小的数作乘法,所以可能会出现下溢的情况,所以我们在进行处理的时候可以对概率的乘积取自然对数,根据自然对数函数的单调性,不会改变最终的大小关系,但是很好的防止了下溢出的问题。
import numpy as np
import math
# 使用词集法进行贝叶斯分类
# 构造数据集,分类是侮辱性 or 非侮辱性
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 is abusive, 0 not
return postingList, classVec
# 创建一个包涵所有词汇的列表 , 为后面建立词条向量使用
def createlist (dataset) :
vovabset = set ([])
for vec in dataset :
vovabset = vovabset | set (vec)
return list (vovabset)
# 将词条转化为向量的形式
def changeword2vec (inputdata, wordlist) :
returnVec = [0] * len (wordlist)
for word in inputdata :
if word in wordlist :
returnVec[wordlist.index(word)] = 1
return returnVec
# 创建贝叶斯分类器
def trainNBO (dataset, classlebels) :
num_of_sample = len (dataset)
num_of_feature = len (dataset[0])
pAusuive = sum (classlebels) / num_of_sample # 侮辱性语言的概率
p0Num = np.ones (num_of_feature)
p1Num = np.ones (num_of_feature)
p0tot = num_of_feature
p1tot = num_of_feature
for i in range (num_of_sample) :
if classlebels[i] == 1 :
p1Num += dataset[i]
p1tot += sum (dataset[i])
else :
p0Num += dataset[i]
p0tot += sum (dataset[i])
p0Vec = p0Num / p0tot
p1Vec = p1Num / p1tot
for i in range (num_of_feature) :
p0Vec[i] = math.log (p0Vec[i])
p1Vec[i] = math.log (p1Vec[i])
return p0Vec, p1Vec, pAusuive
# 定义分类器
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + log(pClass1) #element-wise mult
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
# 测试代码
dataset,classlebels = loadDataset ()
wordlist = createlist (dataset)
print (wordlist)
print (changeword2vec (dataset[0], wordlist))
trainmat = []
for temp in dataset :
trainmat.append (changeword2vec (temp,wordlist))
p0V, p1V, pAb = trainNBO (trainmat, classlebels)
print (p0V)
print (p1V)
print (pAb)