一、贝叶斯公式
贝叶斯公式是一种基于概率的统计推断方法,用于计算在给定先验概率的情况下,通过新的证据来更新后验概率。它可以用于在已知某个事件发生的前提下,计算另一个事件发生的概率。
先验概率:即基于统计的概率,是基于以往历史经验和分析得到的结果,不需要依赖当前发生的条件。
后验概率:则是从条件概率而来,由因推果,是基于当下发生了事件之后计算的概率,依赖于当前发生的条件。
贝叶斯公式的数学表达式如下:
P(A|B) = P(AB) / P(B) = (P(B|A) * P(A)) / P(B)
其中,P(A|B) 表示在事件 B 发生的条件下,事件 A 发生的概率;P(B|A) 表示在事件 A 发生的条件下,事件 B 发生的概率;P(A) 表示事件 A 发生的先验概率;P(B) 表示事件 B 发生的先验概率。
二、朴素贝叶斯分类器
朴素贝叶斯分类器是一种基于贝叶斯公式和特征独立性假设的分类算法。它假设每个特征在给定类别下独立地对分类结果产生影响,因此称为“朴素”。
朴素贝叶斯分类器的基本思想是通过已知的训练样本数据来估计每个类别下各个特征的条件概率,并利用贝叶斯公式来计算给定特征条件下的后验概率,从而进行分类。
具体步骤如下:
- 准备训练数据集,包含已知的样本数据和对应的类别标签。
- 根据训练数据集计算每个类别的先验概率 P(C),即每个类别出现的概率。
- 对于每个特征,计算在每个类别下的条件概率 P(X|C),即给定类别下该特征出现的概率。
- 对于一个新的样本数据,计算该样本属于每个类别的后验概率 P(C|X)。
- 根据后验概率选择概率最大的类别作为分类结果。
朴素贝叶斯分类器(Naïve Bayes Classifier)采用了“属性条件独立性假设”,即每个属性独立地对分类结果发生影响。贝叶斯公式可重写为
其中d为属性数目,x_i 为 x 在第i个属性上的取值。
朴素贝叶斯分类器的训练器的训练过程就是基于训练集D估计类先验概率P(c),并为每个属性估计条件概率 P(x_i│c)。 令D_c表示训练集D中第c类样本组合的集合,则类先验概率:
对离散属性,令D_c,x_i表示D_c中在第 i 个属性上取值为x_i的样本组成的集合,则条件概率P(x_i│c)可估计为:
对连续属性,可考虑概率密度函数,假定p(x_i│c)~N(μ_c,i,σ_c,i^2),其中μ_c,i和σ_c,i^2分别是第 c类样本在第i个属性上取值的均值和方差,则有:
优点:
- 高效性:在处理大规模数据时,朴素贝叶斯分类器具有较高的计算效率。
- 简单性:朴素贝叶斯分类器的实现相对简单,而且不需要太多的参数调整。
- 适用性:朴素贝叶斯分类器适用于各种领域,特别是文本分类和垃圾邮件过滤等应用。
缺点:
- “朴素”假设:朴素贝叶斯分类器假设特征之间是独立的,这可能导致一些特征相关性的信息损失。
- 零概率问题:如果某个特征在训练样本中没有出现过,那么在计算条件概率时会得到零概率,这会影响分类的准确性。
三、拉普拉斯修正
拉普拉斯修正是一种常用的朴素贝叶斯分类器的平滑技术。在朴素贝叶斯分类器中,为了计算先验概率和条件概率,在训练集中出现的每个特征值的次数需要统计。然而,有时候某些特征值在训练集中没有出现,导致概率为零,这会影响到分类器的准确性。
为了解决这个问题,可以使用拉普拉斯修正。拉普拉斯修正的基本思想是在计算概率时为所有特征值的计数加上一个常数(通常为1),这样即使某个特征值在训练集中没有出现,仍然会有一个非零的概率。
令 N 表示训练集 D 中可能的类别数,N_i表示第i个属性可能的取值数,则贝叶斯公式可修正为:
通过拉普拉斯修正,可以有效避免概率为零的问题,提高朴素贝叶斯分类器的准确性。
四、垃圾邮件分类
垃圾邮件分类是朴素贝叶斯分类器的一个常见应用领域。朴素贝叶斯分类器可以根据邮件的特征(如词频、词语出现的概率等)来判断邮件是属于垃圾邮件还是正常邮件。
在垃圾邮件分类中,首先需要构建一个训练集,包含已经标记好的垃圾邮件和正常邮件。然后,通过计算每个特征在垃圾邮件和正常邮件中的条件概率,利用贝叶斯公式计算邮件属于垃圾邮件和正常邮件的概率,最后比较两个概率的大小,将邮件分类为垃圾邮件或正常邮件。
代码实现:
def load_file(path):
cab=[]
for i in range(1, 25):
data=open(path %i)
for line in data.readlines():
cab.append(line.strip().split(','))
cab_f=[]
for i in range(len(cab)):
for j in range(len(cab[i])):
if cab[i][j]!='':
cab_f.append(cab[i][j].strip())
cab_final=[]
for i in cab_f:
for j in i.split(' '):
cab_final.append(j)
return cab_final
def bayes(test):
path1='D:/Email/Training/normal/%d.txt'
path2='D:/Email/Training/spam/%d.txt'
normal_data=load_file(path1)
spam_data=load_file(path2)
# 计算p(x|C1)=p1与p(x|C2)=p2
p1=1.0;p2=1.0
for i in range(len(test)):
x=0.0
for j in normal_data:
if test[i]==j:
x=x+1.0
p1=p1*((x+1.0)/(len(normal_data)+2.0)) #拉普拉斯平滑
for i in range(len(test)):
x=0.0
for j in spam_data:
if test[i]==j:
x=x+1.0
p2=p2*((x+1.0)/(len(spam_data)+2.0)) #拉普拉斯平滑
pc1 = len(normal_data) / (len(normal_data)+len(spam_data))
pc2 = 1 - pc1
if p1*pc1>p2*pc2:
return 'normal'
else:
return 'spam'
def test(path):
data=open(path)
cab=[]
for line in data.readlines():
cab.append(line.strip().split(','))
cab_f = []
for i in range(len(cab)):
for j in range(len(cab[i])):
if cab[i][j] != '':
cab_f.append(cab[i][j].strip())
cab_final = []
for i in cab_f:
for j in i.split(' '):
cab_final.append(j)
return bayes(cab_final)
if __name__=='__main__':
print(test('D:/Email/test/normal.txt'))
print(test('D:/Email/test/spam.txt'))
sum1=0;sum2=0
#再试试训练集
for i in range(1,25):
if test('D:/Email/Training/normal/%d.txt' %i)=='normal':
sum1=sum1+1
for i in range(1,25):
if test('D:/Email/Training/spam/%d.txt' %i)== 'spam':
sum2=sum2+1
print('normal分类正确率:',sum1/24)
print('spam分类正确率:', sum2/24)