举个最简单的二分类例子:有两类(w1, w2),有样本 x ,现问:xv属于w1,还是w2?
即求:p(w1 / x)与p(w2 / x),
这就是利用概率进行分类!
其中:
分子相同,故只用比较分母即可,其中:
p(w1)与p(w2)为w的先验概率;
p(w1 / x)、 p(w2 / x)为x在w上的后验概率
p(x / w1)、 p(x / w2)为x在w上的条件概率
因此概率分类的关键是如何通过求条件概率!
朴素贝叶斯分类器 (naÏve Bayes classifier)采用:“属性条件独立性假设”:对已知类别,假设所有属性相互独立。换言之,假设每个属性独立地对分类结果发生影响。
故上式可写成:
其中 d 为属性数目, x i x_i xi为 x x x 在第 i i i 个属性上的取值。p(c)为样本中标签为c的样本数占总样本数的比值。
对离散属性而言:
D c , x i D_{c,x_i} Dc,xi, 表示 D c D_c Dc 中在第 i i i 个属性上取值为 x i x_i xi 的样本组成的集合。
垃圾邮件分类问题:
标签 c i , i = 1 , 2 c_i,i={1,2} ci,i=1,2: c 1 c_1 c1 (正常邮件), c 2 c_2 c2(垃圾邮件),输入邮件为 w w w,邮件有d个属性值{x1, x2, x3, …xd}
由上述可知求 P ( c 1 ∣ w ) P(c_1 | w) P(c1∣w)、 P ( c 2 ∣ w ) P(c_2|w) P(c2∣w)
即求: P ( w ∣ c 1 ) P(w |c_1) P(w∣c1)、 P ( w ∣ c 2 ) P(w|c_2) P(w∣c2)
Python的sklearn包中有现成的朴素贝叶斯分类类可以调用(多项式的朴素贝叶斯分类):
from sklearn.naive_bayes import MultinomialNB
这是搜狗2020校招的一道算法题:
编写Naïve Bayes分类模型对邮件文本进行分类,判断该邮件是不是垃圾邮件(二分类)。我们已经通过数据预处理,将原始的邮件文本数据转化为分类器可用的数据向量形式,具体:数据表示为整型数向量x=(x1,x2,…,xd)。d是数据特征向量的维数,每个输入数据样本的格式为:
Label x1 x2 … xd
其中Label为0或者1的整型数字(0表示正常邮件,1表示垃圾邮件);
x1 x2 … xd是离散化后的特征,表示为从0开始的自然数;
维度d小于20;
如果Label=?,则表示希望输出的预测类别值(需要预测的类别一定已在对应的训练数据中已经出现过)。
这里采用了 l o g log log,将连乘变为了连加,效果一样:
import math
def trainNB(traindata, trainlabel):
# 训练集大小
lenstrain = len(traindata)
# 特征属性维度
lensvec = len(traindata[0])
# 训练集中标签为0的样本概率
p0 = sum(trainlabel)/lenstrain
# 采用拉普拉斯修正
p0d, p1d = [1]*lensvec, [1]*lensvec
p0sum, p1sum = 2.0, 2.0
for i in range(lenstrain):
if trainlabel[i]==1:
for j in range(lensvec):
p1d[j] += traindata[i][j]
p1sum += sum(traindata[i])
else:
for j in range(lensvec):
p0d[j] += traindata[i][j]
p0sum += sum(traindata[i])
p0vecpro = [math.log(p0d[i]/p0sum) for i in range(lensvec)]
p1vecpro = [math.log(p1d[i]/p1sum) for i in range(lensvec)]
return p0vecpro, p1vecpro, p0
def test(testdata, p0vecpro, p1vecpro, p0):
lenstest = len(testdata)
p0test = 0
p1test = 0
for i in range(lenstest):
p0test += p0vecpro[i]*testdata[i]
p1test += p1vecpro[i]*testdata[i]
p0test += math.log(p0)
p1test += math.log(1-p0)
if p0test>p1test:
return 0
else:
return 1
traindata, trainlabel, testdata = [], [], []
M, N, d = map(int, input().split("\t"))
for i in range(M):
line = [int(j) for j in input().split("\t")]
traindata.append(line[1:])
trainlabel.append(line[0])
for i in range(N):
line = [int(j) if j!="?" else j for j in input().split("\t")]
testdata.append(line[1:])
p0vecpro, p1vecpro, p0 = trainNB(traindata, trainlabel)
for i in range(N):
print(test(testdata[i], p0vecpro, p1vecpro, p0))