一、朴素贝叶斯概述
朴素贝叶斯是机器学习中一种基于概率理论的简单分类算法。它的名字来源于它所依赖的朴素贝叶斯定理,以及它的一个关键假设——特征之间的条件独立性,这使得它在某些情况下表现得非常出色,尤其是在处理大量特征的文本分类问题时。
1.朴素贝叶斯定理
朴素贝叶斯算法的核心是应用朴素贝叶斯定理,该定理描述了在给定某些观测数据的情况下,一个假设的概率。数学上,朴素贝叶斯定理可以表示为:
其中:
- P(A∣B) 是在事件B发生的条件下事件A发生的概率。
- P(B∣A) 是在事件A发生的条件下事件B发生的概率。
- P(A) 和P(B) 分别是事件A和事件B发生的概率。
2.朴素假设
朴素贝叶斯算法的“朴素”之处在于它假设所有特征都是相互独立的,即一个特征的存在不会影响其他特征。这个假设通常在现实中是不成立的,但朴素贝叶斯算法仍然在很多情况下表现良好。
3.算法步骤
-
收集数据:首先,你需要一个标记的数据集来训练模型。
-
特征提取:对于每个类别,计算每个特征的概率分布。
-
应用朴素贝叶斯定理:对于新的数据点,计算它属于每个类别的概率,然后使用朴素贝叶斯定理来更新这些概率。
-
分类决策:选择具有最高后验概率的类别作为新数据点的类别。
示例:
需要计算和比较的是p(c1 | x,y)和p(c2 | x,y)。这些符号所代表的具体意义是:给定某个由x、y表示的数据点,那么该数据点来自类别c1的概率是多少?数据点来自类别c2的概率又是多少?可以使用贝叶斯准则来交换概率中条件与结果。具体地,应用贝叶斯准则得到:
使用这些定义,可以定义贝叶斯分类准则为:
□如果P(c1|x,y)>P(c2|x,y),那么属于类别c1;
□如果P(c1|x,y)<P(c2|x,y),那么属于类别c2。
4.优缺点
优点:
- 简单、快速,特别是在数据集很大时。
- 需要的内存少。
- 对缺失数据不太敏感。
- 适合分类特征多的文本分类问题。
缺点:
- 朴素假设可能不成立,这可能导致分类效果不佳。
- 需要大量的数据来估计准确的条件概率。
二、先验概率、条件概率、后验概率
在朴素贝叶斯分类器中,先验概率、条件概率和后验概率是三个核心概念,它们共同构成了朴素贝叶斯定理的基础。
1. 先验概率
先验概率是指在考虑任何额外信息之前,某个事件发生的概率。在朴素贝叶斯分类器中,先验概率通常指的是我们对于每个类别的初始信念。例如,在垃圾邮件分类问题中,我们可能已经知道大约70%的邮件是垃圾邮件,那么“邮件是垃圾邮件”的先验概率就是0.7。
2. 条件概率
条件概率是在某个事件已经发生的条件下,另一个事件发生的概率。用数学符号表示,如果我们用A表示事件“邮件是垃圾邮件”,用B表示事件“邮件包含‘免费’这个词”,那么“在A发生的条件下B发生的概率”可以写作P(B∣A)。在朴素贝叶斯分类器中,我们需要计算的是特征在各个类别下的条件概率。
3. 后验概率
后验概率是在已知某些其他条件或数据的情况下,某个假设的概率。在朴素贝叶斯分类器中,后验概率是我们的目标,即给定观测数据,某个类别的概率。用数学符号表示,如果我们用A表示类别,用B表示观测数据,则后验概率表示为P(A∣B)。
4.朴素贝叶斯分类器中的计算
在朴素贝叶斯分类器中,我们通常使用以下步骤来计算后验概率:
-
计算先验概率:确定每个类别的先验概率,通常基于训练数据中各类别的频率。
-
计算条件概率:对于每个类别,计算给定类别下每个特征的条件概率。朴素贝叶斯的朴素假设在这里发挥作用,即假设所有特征都是条件独立的。
-
应用朴素贝叶斯定理:使用先验概率和条件概率,通过朴素贝叶斯定理计算后验概率。
-
做出决策:选择具有最高后验概率的类别作为预测结果。
三、朴素贝叶斯分类器实践
1.收集数据集
这次实验采用的是区分是否是好瓜的数据集,训练数据集如下:
#求解顺序:先验概率、条件概率、后验概率
# 定义训练数据和标签
traindata = [
["青绿", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", "是"],
["乌黑", "蜷缩", "沉闷", "清晰", "凹陷", "硬滑", "是"],
["乌黑", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", "是"],
["青绿", "蜷缩", "沉闷", "清晰", "凹陷", "硬滑", "是"],
["浅白", "蜷缩", "浊响", "清晰", "凹陷", "硬滑", "是"],
["青绿", "稍蜷", "浊响", "清晰", "稍凹", "软粘", "是"],
["乌黑", "稍蜷", "浊响", "稍糊", "稍凹", "软粘", "是"],
["乌黑", "稍蜷", "浊响", "清晰", "稍凹", "硬滑", "是"],
["乌黑", "稍蜷", "沉闷", "稍糊", "稍凹", "硬滑", "否"],
["青绿", "硬挺", "清脆", "清晰", "平坦", "软粘", "否"],
["浅白", "硬挺", "清脆", "模糊", "平坦", "硬滑", "否"],
["浅白", "蜷缩", "浊响", "模糊", "平坦", "软粘", "否"],
["青绿", "稍蜷", "浊响", "稍糊", "凹陷", "硬滑", "否"],
["浅白", "稍蜷", "沉闷", "稍糊", "凹陷", "硬滑", "否"],
["乌黑", "稍蜷", "浊响", "清晰", "稍凹", "软粘", "否"],
["浅白", "蜷缩", "浊响", "模糊", "平坦", "硬滑", "否"],
["青绿", "蜷缩", "沉闷", "稍糊", "稍凹", "硬滑", "否"]
]
labels=["色泽", "根蒂", "敲声", "纹理", "脐部", "触感", "好瓜"]
2.第一步:计算先验概率
(1)代码
#第一步:求先验概率
def calculate_prior(train_data):
prior = {}
for sample in train_data:
label = sample[-1] # 获取样本的类别标签
if label not in prior:
prior[label] = 0 # 若类别标签不在先验概率字典中,则初始化计数为0
prior[label] += 1 # 统计每个类别的样本数量
for i in prior:
prior[i]=prior[i]/len(train_data) #各类别的数量与样本总数之比即为当前类别的先验概率
return prior # 返回先验概率字典
我们只需遍历样本获取样本的类别标签,并令字典中该类别对应的值增一来更新对应类别数量,最后再循环遍历一次字典,将对应的值更改为键对应的值即类别对应的数量与样本总数之比作为先验概率。
(2)运行结果
3.第二步:计算条件概率
(1)代码
#第二步:求条件概率
def calculate_conditional(train_data, labels):
conditional = {} #存放条件概率
total = {} #存放所有的类别对应数量
for sample in train_data:
if sample[-1] not in total:
total[sample[-1]] = 0
total[sample[-1]] += 1 #统计各类别数量
for sample in train_data:
for i, feature in enumerate(sample[:-1]):
label = sample[-1] # 获取样本的类别标签
if labels[i] not in conditional:
conditional[labels[i]] = {} # 若特征标签不在条件概率字典中,则初始化为一个空字典
if feature not in conditional[labels[i]]:
conditional[labels[i]][feature] = {'是': 0, '否': 0} # 在这里同时初始化 '是' 和 '否'
if label not in conditional[labels[i]][feature]:
conditional[labels[i]][feature][label] = 0 # 若类别标签不在特征对应的字典中,则初始化计数为0
conditional[labels[i]][feature][label] += 1 # 统计每个特征在每个类别下的样本数量
for i in conditional:
for j in conditional[i]:
for k in total:
conditional[i][j][k] = conditional[i][j][k] / total[k] if total[k] != 0 else 0 #计算最终的条件概率即P(A|B)=P(AB)/P(B)=AB都有的数量与B的数量之比
return conditional # 返回条件概率字典
思路见注释
(2)运行结果
4.第三步:计算后验概率并判断分类结果
(1)代码
#第三步:计算后验概率并判断类别
def predict_sample(sample, prior, conditional, labels):
probabilities = {}
for label in prior:
probabilities[label] = prior[label] # 初始化后验概率为先验概率
for i, feature in enumerate(sample):
if feature in conditional.get(labels[i], {}):
count = conditional[labels[i]][feature].get(label, 0) # 获取特征在给定类别下的条件概率
probabilities[label] *= count # 更新后验概率
else:
probabilities[label] *= 0 # 若特征未在训练数据中出现,则置后验概率为0
predict_label = max(probabilities, key=probabilities.get) # 选择后验概率最大的类别作为预测结果
return predict_label # 返回预测结果
要注意的是在计算后验概率时我们只做了各条件概率与先验概率的乘积而没有除以特征的概率,原因是计算两种分类的后验概率除以的是共同的分母,这里省去除以的分母,直接用各条件概率与先验概率的乘积进行最后的类别判断。
(2)运行结果
四、拉普拉斯平滑技巧修正
1.简介
拉普拉斯平滑通常用于解决贝叶斯分类器等算法中可能出现的概率为零的情况。
修正的基本思想是在概率估计中添加一个小的常数,以防止零概率值的出现。具体而言,对于一个类别(或特征)的概率估计,拉普拉斯平滑将该类别的计数值加上一个常数,同时对所有类别的计数值都进行了调整,以确保概率的总和仍然为1。
在分类问题中,修正的公式通常如下所示:
𝑃(𝑌=𝑦𝑖∣𝑋=𝑥𝑗)=(𝑛𝑦𝑖+1)/(𝑁+𝑘)
其中:
- nyi 是类别 yi 在数据集中的出现次数(或者是某个特征在某个类别中出现的次数)。
- N 是总的样本数(或者是某个类别中样本的总数)。
- k 是类别(或特征)的总数。
- 1 是拉普拉斯修正的常数项。
这种修正可以有效地解决零计数问题,同时也有助于更好地泛化到未见过的数据。
2.演示
将朴素贝叶斯分类器实践中的预测样本test_sample=['青绿','蜷缩','沉闷','清晰','凹陷','硬滑']中的沉闷特征修改为清脆,即test_sample=['青绿','蜷缩','清脆','清晰','凹陷','硬滑']。
进行拉普拉斯平滑技巧修正前:
由于训练集中类别‘是’的所有样本中没有清脆的特征,所以P(清脆|是)的条件概率为0,导致最终类别为‘是’的后验概率为0,最终会判断为’否‘即不是好瓜。
进行拉普拉斯平滑技巧修正:
修正后结果:
五、实验总结
在本次实验中,我们通过一个具体的例子——区分好瓜与否的数据集,深入探讨了朴素贝叶斯分类器的工作原理和实现过程。实验分为几个关键步骤:计算先验概率、条件概率、后验概率,并使用这些概率进行分类预测。此外,我们还学习了拉普拉斯平滑技巧,以解决概率估计中可能出现的零概率问题。
-
先验概率的计算:我们首先计算了各类别的先验概率,即在没有任何额外信息的情况下,每个类别发生的概率。这是通过统计训练数据集中每个类别出现的次数并除以总样本数得到的。
-
条件概率的计算:接着,我们计算了每个特征在各个类别下的条件概率。这是朴素贝叶斯算法的核心,它依赖于特征之间的条件独立性假设。我们通过统计每个特征在每个类别下的样本数量,并将其除以该类别的样本总数来计算条件概率。
-
后验概率的计算与分类预测:利用先验概率和条件概率,我们计算了新样本的后验概率,并根据后验概率的最大值来预测样本的类别。这一步骤体现了朴素贝叶斯分类器的决策过程。
-
拉普拉斯平滑技巧的应用:在实验中,我们遇到了由于训练数据中某些特征从未出现而导致的条件概率为零的问题。为了解决这个问题,我们引入了拉普拉斯平滑技巧,它通过在每个类别的计数中添加一个小常数来避免零概率,并确保所有概率之和为1,从而提高了模型的泛化能力。
-
实验结果与分析:通过实验,我们发现朴素贝叶斯分类器在处理具有大量特征的分类问题时,尤其是在文本分类领域,表现出色。然而,它的性能受限于特征条件独立性的假设,这在现实世界中往往不成立。此外,实验还展示了拉普拉斯平滑技巧在处理数据稀疏性问题时的有效性。
通过本次实验,我们不仅学习了朴素贝叶斯分类器的理论知识,还通过实践加深了对其工作原理的理解。这为我们日后在机器学习领域的研究和应用打下了坚实的基础。