目录
一、基础概率知识
先验概率:即基于统计的概率,是基于以往历史经验和分析得到的结果,不需要依赖当前发生的条件(即不考虑特征条件)。
后验概率:则是从条件概率而来,由因推果,是基于当下发生了事件之后计算的概率,依赖于当前发生的条件。
条件概率:记事件A发生的概率为P(A),事件B发生的概率为P(B),则在B事件发生的前提下,A事件发生的概率即为条件概率,记为P(A|B)。
相互独立:如果P(A,B)=P(A)P(B)则称事件A与事件B相互独立。
联合概率:联合概率表示两个事件共同发生的概率,例如事件A与事件B同时发生,则表示为P(A,B)或P(AB)。
二、朴素贝叶斯介绍
朴素贝叶斯算法的核心思想是通过考虑特征概率来预测分类,即对于给出的待分类样本,求解在此样本出现的条件下各个类别出现的概率,哪个最大,就认为此待分类样本属于哪个类别。朴素贝叶斯是一种分类算法,经常被用于文本分类,它的输出结果是某个样本属于某个类别的概率。
之所以被称为“朴素”,主要在于它做出了一个假设,即每个特征是相互独立的。朴素贝叶斯算法的核心假设是特征之间的独立性,也就是说,每个特征对于分类结果的贡献是相互独立的。尽管这个假设在现实世界中往往不成立,但朴素贝叶斯算法仍然在许多实际问题中表现良好。它具有计算简单、速度快的优点,并且对于高维数据和大规模数据集也能有效地进行分类。
三、朴素贝叶斯公式计算及拉普拉斯平滑系数
朴素贝叶斯公式
由条件概率公式推导而来的朴素贝叶斯:
案例:判断是否为好瓜
样本数 | 甜度 | 色泽 | 是否为好瓜 |
---|---|---|---|
1 | 高糖 | 乌黑 | 否 |
2 | 中糖 | 浅白 | 是 |
3 | 低糖 | 青绿 | 是 |
4 | 高糖 | 青绿 | 是 |
5 | 中糖 | 乌黑 | 是 |
6 | 低糖 | 浅白 | 否 |
7 | 高糖 | 浅白 | 是 |
求低糖且乌黑的西瓜是好瓜的概率?
思路:
求是否为好瓜,转化成数学问题就是
可以套用朴素贝叶斯公式计算:
P(是好瓜|低糖,乌黑)= P(低糖,乌黑|是好瓜)* P(是好瓜)/ P(低糖,乌黑)
在案例表格中,P(低糖,乌黑|是好瓜)、P(低糖,乌黑)结果均为0,导致无法计算结果,但朴素贝叶斯能够解决此问题,只要假定特征与特征之间独立。
根据 朴素 的思想,计算概率:
P(低糖,乌黑)=P(低糖)*P(乌黑)= (2/7)*(2/7)=4/49
P(低糖,乌黑|是好瓜)= P(低糖|是好瓜)*P(乌黑|是好瓜)=(1/5)*(1/5)=1/25
P(是好瓜|低糖,乌黑)= P(低糖,乌黑|是好瓜)* P(是好瓜)/ P(低糖,乌黑)
= (1/25)*(5/7)/(4/49)=7/20
拉普拉斯平滑系数
当某个特征在给定类别下没有出现过时,根据朴素贝叶斯算法的计算公式,该特征对应的条件概率会变为零,从而导致整个后验概率为零,影响了分类结果的准确性。于是这就需要拉普拉斯平滑系数。
拉普拉斯平滑(也称为加法平滑或加1平滑)是一种常用的平滑技术,它通过在计算条件概率时为每个特征值添加一个小的常数(通常是1)来避免概率为零的情况。
对于离散特征,统计每个特征值在给定类别下的样本数量。对于连续特征,可以将特征值进行离散化,然后统计离散后的特征值在给定类别下的样本数量。
计算公式:
对于离散特征:条件概率 = (特征值的计数 + 1) / (该类别下的总样本数量 + 特征值的个数)。
对于连续特征:可以假设特征值符合某种概率分布(如高斯分布),然后通过估计分布的参数来计算条件概率。
四、Python代码实现
1、导入相关库及准备数据集
import numpy as np
datas = [
['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],
['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '好瓜'],
['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],
['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '好瓜'],
['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],
['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '好瓜'],
['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '好瓜'],
['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '好瓜'],
['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '坏瓜'],
['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '坏瓜'],
['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '坏瓜'],
['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '坏瓜'],
['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '坏瓜'],
['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '坏瓜'],
['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '坏瓜'],
['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '坏瓜'],
['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '坏瓜']
]
labels = ['好瓜', '坏瓜']
features = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']
2、计算先验概率
def calculate_prior(datas):
total_samples = len(datas) #总样本数
labels = [data[-1] for data in datas] # 访问数据最后一个元素作为标签
unique_labels = set(labels) #唯一的类别标签集合
prior_probabilities = {} # 存储先验概率的字典
for label in unique_labels:
label_count = labels.count(label) # 统计该类别标签在列表中出现的次数
prior_probabilities[label] = label_count / total_samples # 计算该类别的先验概率
return prior_probabilities
print(calculate_prior(datas))
结果展示:
{'好瓜': 0.47058823529411764, '坏瓜': 0.5294117647058824}
思路:
朴素贝叶斯算法中,计算先验概率时通常只需考虑标签,而不需要每个特征分开计算。先验概率是指在未观察到任何特征值的情况下,某一类别出现的概率,只与类别本身有关,而与特征无关。
代码分析:
-
统计总样本数:首先计算数据集中样本的总数,通过
len(datas)
获取数据集datas
的长度,即总样本数total_samples
。 -
提取标签:将数据集中每个样本的标签提取出来,这里是取每个样本的最后一个元素作为标签,通过
data[-1] for data in datas
取出所有的标签,并存储在labels
列表中。 -
确定唯一标签类别:通过获取
labels
列表中的唯一值,也就是每个类别的唯一标签,存储在unique_labels
集合中。 -
计算先验概率:遍历每个唯一的类别标签,统计该类别在
labels
中出现的次数,计算出该类别的先验概率,并存储在prior_probabilities
字典中。计算先验概率的公式为:该类别出现的次数 / 总样本数。 -
返回结果:最后返回存储了每个类别及其先验概率的字典
prior_probabilities
。
3、计算各个特征的条件概率
def calculate_conditional(datas, feature, feature_value, label):
# 计算给定特征在给定类别下的条件概率
# param datas: 数据集,包含特征和类别标签
# param feature: 特征列索引
# param feature_value: 特征取值
# param label: 类别标签
matching_samples = 0 # 匹配样本数
total_samples = 0 #此类别的数量
for data in datas:
if data[-1] == label and data[feature] == feature_value:
matching_samples += 1
datas=np.array(datas)
conditional_probability = (matching_samples + 1) / (total_samples + len(set(datas[:, feature]))) # 使用了拉普拉斯平滑系数
return conditional_probability
print(calculate_conditional(datas,1,"硬挺","好瓜"))
结果:
0.09090909090909091
思路:
统计每个特征在每个类别下的出现次数,然后计算每个特征在每个类别下的条件概率。
代码分析:
-
首先获取数据集中的总样本数
total_samples
,并初始化matching_samples
变量为0,用于计算匹配样本数。 -
遍历数据集中的每个样本,并检查样本的类别标签和特征取值是否和传入的参数
label
和feature_value
匹配。若匹配则matching_samples
加1。 -
在遍历完所有数据后,计算给定特征在给定类别下的条件概率
conditional_probability
。其中,使用了拉普拉斯平滑系数,分子为匹配样本数加上1,分母为总样本数加上特征取值的不重复数量。 -
最后函数返回计算得到的条件概率值。
4、计算后验概率
构建测试样本:
tests = [
['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', ],
['乌黑', '硬挺', '沉闷', '清晰', '凹陷', '硬滑', ]
]
后验概率:
def calculate_posterior(datas, labels, tests):
# 计算先验概率
prior_probabilities = calculate_prior(datas)
# 初始化后验概率列表
posterior_probabilities = []
for test in tests:
posterior = {} # 存储当前测试样本的后验概率
for label in labels:
# 初始化后验概率为先验概率
posterior[label] = prior_probabilities[label]
# 计算每个特征的条件概率,并乘以后验概率
for i, feature_value in enumerate(test):
conditional_prob = calculate_conditional(datas, i, feature_value, label)
posterior[label] *= conditional_prob
# 归一化后验概率
total_posterior = sum(posterior.values())
for label in labels:
posterior[label] /= total_posterior
posterior_probabilities.append(posterior)
return posterior_probabilities
结果:
p = calculate_posterior(datas, labels, tests)
for i, test in enumerate(tests):
print("测试样本:", test)
for label in labels:
print("类别", label, "的相对后验概率:", p[i][label])
print()
测试样本: ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑']
类别 好瓜 的相对后验概率: 0.9441965051408125
类别 坏瓜 的相对后验概率: 0.055803494859187355
测试样本: ['乌黑', '硬挺', '沉闷', '清晰', '凹陷', '硬滑']
类别 好瓜 的相对后验概率: 0.770492060257395
类别 坏瓜 的相对后验概率: 0.22950793974260497
思路:
后验概率可以通过朴素贝叶斯计算,当条件概率需要考虑多个特征时,对于给定的观测数据 X,分别计算每个特征在每个类别下的条件概率 P(X1|Y), P(X2|Y), ..., P(Xn|Y)。根据特征条件独立性假设,将各特征条件概率相乘得到 P(X|Y)。在实际计算中,对比较不同类别的后验概率时,这个值是相同的,可以忽略掉。在朴素贝叶斯分类中,我们只需比较不同类别的后验概率的相对大小,而并不需要计算具体的概率值。因此,P(A|B) = P(B|A) * P(A) / P(B)通常会省略了除数值P(B)的计算。
代码分析:
-
通过 calculate_prior(datas) 函数计算先验概率:该部分不在代码中给出,但可以理解为根据训练集 datas 来计算每个类别的先验概率,并将结果存储在 prior_probabilities 字典中。
-
初始化后验概率列表 posterior_probabilities:用来存储所有测试样本的后验概率。
-
对于每个测试样本 test:
- 初始化 posterior 字典,用来存储当前测试样本的后验概率。
- 遍历每个类别 label:
a. 将后验概率初始化为先验概率 prior_probabilities[label]。
b. 遍历测试样本中的每个特征值 feature_value,并获取特征的索引 i:
- 计算特征值 feature_value 在给定类别 label 下的条件概率 conditional_prob,通过函数 calculate_conditional(datas, i, feature_value, label) 计算得到。
- 将条件概率乘以后验概率 posterior[label]。
-
对后验概率进行归一化:将每个类别的后验概率除以总后验概率,以确保后验概率的总和为1。最后得到的好瓜坏瓜的概率是相对概率。
5、分类预测
选择具有最大后验概率的类别作为预测结果。即,将测试样本分配给具有最高后验概率的类别。
for i, test in enumerate(tests):
print("测试样本:", test)
predict_p=max(labels, key=lambda label: p[i][label])
print("分类结果:",predict_p)
for label in labels:
print("类别", label, "的后验概率:", p[i][label])
print()
结果:
测试样本: ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑']
分类结果: 好瓜
类别 好瓜 的后验概率: 0.9087221095334685
类别 坏瓜 的后验概率: 0.09127789046653145
测试样本: ['乌黑', '硬挺', '沉闷', '清晰', '凹陷', '硬滑']
分类结果: 好瓜
类别 好瓜 的后验概率: 0.6639004149377593
类别 坏瓜 的后验概率: 0.3360995850622407
思路:
贝叶斯的决策理论,假设特征之间相互独立,并且每个特征对于决策结果的影响是相互独立的。基于这些假设,朴素贝叶斯分类器可以计算给定特征条件下每个决策结果的后验概率,并选择具有最高后验概率的决策结果作为最终的预测结果。
与
进行比较,选择概率大的那一项
五、总结
朴素贝叶斯作为有监督学习,擅长做分类工作,基于独立性假设,即每个特征之间是相互独立的。这个假设在现实数据中往往不成立,但朴素贝叶斯算法仍然在实际问题中表现良好。
朴素优缺点: