文章目录
- 贝叶斯定理
- 问题背景
- 朴素贝叶斯
- 朴素贝叶斯分类算法原理
- 朴素贝叶斯分类算法步骤
- 给定示例数据
- 极大似然估计
- 贝叶斯估计
- 朴素贝叶斯的三种常见模型
- 多项式模型
- 伯努利模型
- 高斯模型
贝叶斯定理
问题背景
当知道事件 B B B 发生的情况下事件 A A A 发生的概率 P ( A ∣ B ) P(A \mid B) P(A∣B) ,如何求 P ( B ∣ A ) P(B \mid A) P(B∣A) ?
根据条件概率公式可以得到:
P
(
B
∣
A
)
=
P
(
A
B
)
P
(
A
)
(1a)
P(B \mid A)=\frac{P(AB)}{P(A)} \tag{1a}
P(B∣A)=P(A)P(AB)(1a)
P
(
A
B
)
=
P
(
B
∣
A
)
×
P
(
A
)
(1b)
P(AB)=P(B \mid A) \times P(A) \tag{1b}
P(AB)=P(B∣A)×P(A)(1b)
同理:
P
(
A
∣
B
)
=
P
(
A
B
)
P
(
B
)
(2a)
P(A \mid B)=\frac{P(AB)}{P(B)} \tag{2a}
P(A∣B)=P(B)P(AB)(2a)
P
(
A
B
)
=
P
(
A
∣
B
)
×
P
(
B
)
(1b)
P(AB)=P(A \mid B) \times P(B) \tag{1b}
P(AB)=P(A∣B)×P(B)(1b)
联立得贝叶斯定理公式:
P
(
B
∣
A
)
=
P
(
A
B
)
P
(
A
)
=
P
(
A
∣
B
)
×
P
(
B
)
P
(
A
)
(3)
P(B \mid A)=\frac{P(AB)}{P(A)}=\frac{P(A \mid B) \times P(B)}{P(A)} \tag{3}
P(B∣A)=P(A)P(AB)=P(A)P(A∣B)×P(B)(3)
这里的
P
(
A
)
,
P
(
B
)
P(A),P(B)
P(A),P(B)都是依据原有数据集可知的,称为先验概率;而
P
(
B
∣
A
)
P(B|A)
P(B∣A)是通过贝叶斯定理求出来的,称为后验概率。
在机器学习的背景下,调整贝叶斯公式如下:
P
(
类别
∣
特征
)
=
P
(
特征
∣
类别
)
×
P
(
类别
)
P
(
特征
)
(4)
P(\text{类别} \mid \text{特征})=\frac{P(\text{特征} \mid \text{类别}) \times P(\text{类别})}{P(\text{特征})} \tag{4}
P(类别∣特征)=P(特征)P(特征∣类别)×P(类别)(4)
公式
(
4
)
(4)
(4) 利用先验概率,即特征和类别的概率;再利用不同类别中各个特征的概率分布,最后计算得到后验概率,即各个特征分布下的预测不同的类别。
朴素贝叶斯
朴素贝叶斯中的「朴素」,即条件独立,表示其假设预测的各个属性都是相互独立的,每个属性独立地对分类结果产生影响,条件独立在数学上的表示为: P ( A B ) = P ( A ) × P ( B ) P(AB)=P(A) \times P(B) P(AB)=P(A)×P(B) 。
显然,不同类别之间不一定是完全独立的关系,朴素贝叶斯算法是简化后的算法,但会牺牲一定的分类准确率。
朴素贝叶斯分类算法原理
P
(
类别
∣
特征
)
=
P
(
特征
∣
类别
)
×
P
(
类别
)
P
(
特征
)
(4)
P(\text{类别} \mid \text{特征})=\frac{P(\text{特征} \mid \text{类别}) \times P(\text{类别})}{P(\text{特征})} \tag{4}
P(类别∣特征)=P(特征)P(特征∣类别)×P(类别)(4)
公式
(
4
)
(4)
(4) 利用先验概率,即特征和类别的概率;再利用不同类别中各个特征的概率分布,最后计算得到后验概率,即各个特征分布下的预测不同的类别。
对于每个特征,其预测的不同类别中概率最高的就是这个特征的分类的类别,达到分类的目的。对于每种特征来说, P ( 特征 ) P(\text{特征}) P(特征)都是一样的,只需要比较 P ( 特征 ∣ 类别 ) × P ( 类别 ) P(\text{特征} \mid \text{类别}) \times P(\text{类别}) P(特征∣类别)×P(类别)大小即可。
朴素贝叶斯分类算法步骤
-
第 1 步:设 X = { a 1 , a 2 , a 3 , … , a n } X = \left \{ a_{1},a_{2},a_{3},…,a_{n} \right \} X={a1,a2,a3,…,an} 为预测数据,其中 a i a_{i} ai 是预测数据的特征值。
-
第 2 步:设 Y = { y 1 , y 2 , y 3 , … , y m } Y = \left \{y_{1},y_{2},y_{3},…,y_{m} \right \} Y={y1,y2,y3,…,ym} 为类别集合。
-
第 3 步:计算 P ( y 1 ∣ x ) P(y_{1}\mid x) P(y1∣x) , P ( y 2 ∣ x ) P(y_{2}\mid x) P(y2∣x) , P ( y 3 ∣ x ) P(y_{3}\mid x) P(y3∣x) , … … …, P ( y m ∣ x ) P(y_{m}\mid x) P(ym∣x) 。
-
第 4 步:寻找 P ( y 1 ∣ x ) P(y_{1}\mid x) P(y1∣x) , P ( y 2 ∣ x ) P(y_{2}\mid x) P(y2∣x) , P ( y 3 ∣ x ) P(y_{3}\mid x) P(y3∣x) , … … …, P ( y m ∣ x ) P(y_{m}\mid x) P(ym∣x) 中最大的概率 P ( y k ∣ x ) P(y_{k}\mid x) P(yk∣x) ,则 x x x 属于类别 y k y_{k} yk。
给定示例数据
import pandas as pd
def create_data():
# 生成示例数据
data = {"x": ['r', 'g', 'r', 'b', 'g', 'g', 'r', 'r', 'b', 'g', 'g', 'r', 'b', 'b', 'g'],
"y": ['m', 's', 'l', 's', 'm', 's', 'm', 's', 'm', 'l', 'l', 's', 'm', 'm', 'l'],
"labels": ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B']}
data = pd.DataFrame(data, columns=["labels", "x", "y"])
return data
data = create_data()
极大似然估计
如何求 P ( 特征 ∣ 类别 ) × P ( 类别 ) P(\text{特征} \mid \text{类别}) \times P(\text{类别}) P(特征∣类别)×P(类别)?
如何求 P ( 类别 ) P(\text{类别}) P(类别)?
P
(
y
i
=
c
k
)
=
∑
i
=
1
N
I
(
y
i
=
c
k
)
N
,
k
=
1
,
2
,
3
,
…
,
m
(5)
P(y_{i}=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})}{N},k=1,2,3,…,m \tag{5}
P(yi=ck)=N∑i=1NI(yi=ck),k=1,2,3,…,m(5)
这个很好理解,就是每种类别
y
i
y_i
yi的数量
I
I
I占总样本
N
N
N的比值。
# 先验概率求解
def get_P_labels(labels):
# P(\text{类别}) 先验概率计算
labels = list(labels) # 转换为 list 类型
P_label = {} # 设置空字典用于存入 label 的概率
label_name=list(set(labels))
for label in label_name:
P_label[label] = labels.count(
label) / float(len(labels)) # p = count(y) / count(Y)
return P_label
P_labels = get_P_labels(data["labels"])
# {'A': 0.5333333333333333, 'B': 0.4666666666666667}
如何求 P ( 特征 ∣ 类别 ) P(\text{特征} \mid \text{类别}) P(特征∣类别)?
首先我们将特征按序号合并生成一个 NumPy 数组。
import numpy as np
train_data = np.array(data.drop("labels",axis=1))
'''
array([['r', 'm'],
['g', 's'],
['r', 'l'],
['b', 's'],
['g', 'm'],
['g', 's'],
['r', 'm'],
['r', 's'],
['b', 'm'],
['g', 'l'],
['g', 'l'],
['r', 's'],
['b', 'm'],
['b', 'm'],
['g', 'l']], dtype=object)
'''
得到每一个类别的索引:
labels = data["labels"]
label_index = []
for y in P_labels.keys():
temp_index = []
# enumerate 函数返回 Series 类型数的索引和值,其中 i 为索引,label 为值
for i, label in enumerate(labels):
if (label == y):
temp_index.append(i)
else:
pass
label_index.append(temp_index)
# [[0, 1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]]
得到
A
A
A 和
B
B
B 的索引,其中是
A
A
A 类别为前
8
8
8 条数据,
B
B
B 类别为后
7
7
7 条数据。
在得到类别的索引之后,接下来就是找到我们需要的特征的索引, 以
A
A
A 类别中
r
r
r特征 为例。
r_index = [i for i, feature in enumerate(
train_data[:, 0]) if feature == 'r'] # 效果等同于求类别索引中 for 循环
# [0, 2, 6, 7, 11]
计算出 P ( r ∣ A ) P(r|A) P(r∣A) 。
x_label = set(x_index) & set(label_index[0])
print('既符合 x = r 又是 A 类别的索引值:', x_label)
# 既符合 x = r 又是 A 类别的索引值: {0, 2, 6, 7}
x_label_count = len(x_label)
print('先验概率 P(r|A):', x_label_count / float(len(label_index[0])))
# 先验概率 P(r|A): 0.5
将上述流程转化为一个函数:
def get_P_fea_lab(P_label, features, data):
# P(\text{特征}∣种类) 先验概率计算
P_fea_lab = {}
train_data = data.iloc[:, 1:]
train_data = np.array(train_data)
labels = data["labels"]
for each_label in P_label.keys():
label_index = [i for i, label in enumerate(
labels) if label == each_label] # labels 中出现 y 值的所有数值的下标索引
# features[0] 在 trainData[:,0] 中出现的值的所有下标索引
for j in range(len(features)):
feature_index = [i for i, feature in enumerate(
train_data[:, j]) if feature == features[j]]
# set(x_index)&set(y_index) 列出两个表相同的元素
fea_lab_count = len(set(feature_index) & set(label_index))
key = str(features[j]) + '|' + str(each_label)
P_fea_lab[key] = fea_lab_count / float(len(label_index))
return P_fea_lab
features = ['r', 'm']
get_P_fea_lab(P_labels, features, data)
'''
{'r|A': 0.5,
'm|A': 0.375,
'r|B': 0.14285714285714285,
'm|B': 0.42857142857142855}
'''
可以得到当特征 x x x 和 y y y 的值为 r r r 和 m m m 时,在不同类别下的先验概率。
完整代码
def classify(data, features):
# 朴素贝叶斯分类器
# 求 labels 中每个 label 的先验概率
labels = data['labels']
P_label = get_P_labels(labels)
P_fea_lab = get_P_fea_lab(P_label, features, data)
P = {}
P_show = {} # 后验概率
for each_label in P_label:
P[each_label] = P_label[each_label]
for each_feature in features:
key = str(each_label)+'|'+str(features)
P_show[key] = P[each_label] * \
P_fea_lab[str(each_feature) + '|' + str(each_label)]
P[each_label] = P[each_label] * \
P_fea_lab[str(each_feature) + '|' +
str(each_label)] # 由于分母相同,只需要比较分子
print(P_show)
features_label = max(P, key=P.get) # 概率最大值对应的类别
return features_label
classify(data, ['r', 'm'])
# {"A|['r', 'm']": 0.1, "B|['r', 'm']": 0.02857142857142857}
# 这里类别A的概率大于B,故[r,m]特征分为A类别
贝叶斯估计
在做极大似然估计时,若类别中缺少一些特征,则就会出现概率值为 0 的情况。此时,就会影响后验概率的计算结果,使得分类产生偏差。于是引入贝叶斯估计。
贝叶斯估计的数学表达式为:
P
(
y
i
=
c
k
)
=
∑
i
=
1
N
I
(
y
i
=
c
k
)
+
λ
N
+
k
λ
(6)
P(y_{i}=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})+\lambda }{N+k\lambda} \tag{6}
P(yi=ck)=N+kλ∑i=1NI(yi=ck)+λ(6)
其中 λ ≥ 0 \lambda \geq 0 λ≥0 等价于在随机变量各个取值的频数上赋予一个正数,当 λ = 0 \lambda=0 λ=0 时就是极大似然估计。在平时常取 λ = 1 \lambda=1 λ=1,这时称为拉普拉斯平滑。 k k k取值为类别数目。
朴素贝叶斯的三种常见模型
多项式模型
上述过程就是多项式模型,特征离散,参数估计方法采用贝叶斯估计。
伯努利模型
伯努利模型中每个特征的取值只能是 1 和 0。
高斯模型
处理连续的特征变量,采用高斯模型。高斯模型是假设连续变量的特征数据是服从高斯分布的,高斯分布函数表达式为:
P
(
x
i
∣
y
k
)
=
1
2
π
σ
y
k
,
i
e
x
p
(
−
(
x
−
μ
y
k
,
i
)
2
2
σ
y
k
2
,
i
)
P(x_{i}|y_{k})=\frac{1}{\sqrt{2\pi}\sigma_{y_{k},i}}exp(-\frac{(x-\mu_{y_{k},i}) ^{2}}{2\sigma ^{2}_{y_{k}},i})
P(xi∣yk)=2πσyk,i1exp(−2σyk2,i(x−μyk,i)2)
- μ y k , i \mu_{y_{k},i} μyk,i 表示类别为 y k y_{k} yk 的样本中,第 i i i 维特征的均值。
- σ y k 2 , i \sigma ^{2}_{y_{k}},i σyk2,i 表示类别为 y k y_{k} yk 的样本中,第 i i i 维特征的方差。