- .gitignore
- 01.01 python 基础.ipynb
- 01.02 python 进阶.ipynb
- 01.03 机器学习常用的包.ipynb
- 01.04 Keras MNIST Playground.ipynb
- 02.01 基于搜索的问题求解(学生版).ipynb
- 02.01 基于搜索的问题求解.ipynb
- 02.02 决策树(学生版).ipynb
- 02.02 决策树.ipynb
- 02.03 回归分析(学生版).ipynb
- 02.03 回归分析.ipynb
- 02.04 贝叶斯分析(学生版).ipynb
- 02.04 贝叶斯分析.ipynb
- 02.05 神经网络学习(学生版).ipynb
- 02.05 神经网络学习.ipynb
- _overview.md
- data_sample.png
- essay1_ch.txt
- essay1_en.txt
- essay2_ch.txt
- essay2_en.txt
- essay3_ch.txt
- essay3_en.txt
- iris.csv
- mnist.npz
- model.png
- search.py
- SimHei.ttf
02.04 贝叶斯分析(学生版).ipynb @7439c2a — view markup · raw · history · blame
2.4 贝叶斯分析¶
贝叶斯分析是一种根据概率统计知识对数据进行分析的方法,属于统计学分类的范畴。
2.4.1 贝叶斯公式¶
- 频率学派
- 贝叶斯学派
贝叶斯概率计算公式表达: 后验概率 =
条件概率:
$P(A|B)$:
$P(A|B)$:
$P(B|A)$:
$P(B|A)$:
由于:
$$P(B|A){P(A)}=P(A|B){P(B)}={P(A ∩ B)}$$可得贝叶斯公式:
$$P(A|B) = \frac{P(B|A)P(A)}{P(B)}$$其中:
- $P(A)$ 是事件 $A$ 发生的先验概率,与事件 $B$ 是否发生无关;
- $P(B|A)$是事件 $A$ 发生前提下,事件 $B$ 发生的概率,也称为似然概率;
- $P(B)$ 是事件 $B$ 发生的先验概率,也称为标准化常量;
- $P(A|B)$是事件 $B$ 发生前提下,事件 $A$ 发生的概率,也是 $A$ 的后验概率。
2.4.2 贝叶斯推断¶
贝叶斯推断是一种基于贝叶斯公式进行分析的统计学方法。
小例子:根据邮件中的 “红包” 字样判别该邮件是不是垃圾邮件
# 广告邮件的数量
ad_number = 4000
# 正常邮件的数量
normal_number = 6000
# 所有广告邮件中,出现 “红包” 关键词的邮件的数量
ad_hongbao_number = 1000
# 所有正常邮件中,出现 “红包” 关键词的邮件的数量
normal_hongbao_number = 6
# 用户收到广告邮件的先验概率为
P_ad = ad_number / (ad_number + normal_number)
print("用户收到广告邮件的先验概率为 " + str(P_ad))
# 用户收到正常邮件的先验概率为
P_normal = normal_number / (ad_number + normal_number)
print("用户收到正常邮件的先验概率为 " + str(P_normal))
# 红包出现的概率
P_hongbao = (normal_hongbao_number + ad_hongbao_number) / (
ad_number + normal_number)
print("邮件包含红包的先验概率为 " + str(P_hongbao))
# 广告邮件中出现 “红包” 关键词的条件概率
P_hongbao_ad = ad_hongbao_number / ad_number
print("广告邮件中出现 “红包” 关键词的条件概率为 " + str(P_hongbao_ad))
# 正确邮件中出现 “红包” 关键词的条件概率
P_hongbao_normal = normal_hongbao_number / normal_number
print("正常邮件中出现 “红包” 关键词的条件概率为 " + str(P_hongbao_normal))
# 根据贝叶斯定理可得
# 当邮件中出现 “红包” ,其为广告邮件的后验概率
P_ad_hongbao = P_ad * P_hongbao_ad / P_hongbao
print("当邮件中出现 “红包” ,其为广告邮件的后验概率为 " + str(P_ad_hongbao))
# 当邮件中出现 “红包” ,其为正常邮件的后验概率
P_normal_hongbao = P_normal * P_hongbao_normal / P_hongbao
print("当邮件中出现 “红包” ,其为正常邮件的后验概率为 " + str(P_normal_hongbao))
2.4.3 朴素贝叶斯分类器¶
一种常用的分类算法,其基本假设为 。
小例子:预测同学会不会在某店铺订餐。
目标:根据某同学的订单记录,如果向他推荐一家“价位低、口味偏甜、距离远”的店铺,判断他会下单吗?
数据:该同学的下单记录如下
店铺价位 | 店铺口味 | 店铺距离 | 是否下单 |
---|---|---|---|
高 | 偏甜 | 近 | 是 |
高 | 清淡 | 近 | 否 |
高 | 偏辣 | 远 | 否 |
高 | 偏甜 | 远 | 否 |
低 | 偏甜 | 近 | 是 |
低 | 偏甜 | 近 | 是 |
低 | 清淡 | 远 | 否 |
低 | 偏辣 | 远 | 是 |
该同学在收到8次推荐后,下单4次和没有下单4次,则其“下单”,“不下单”的概率:
$$P(下单) = \frac{4}{8}=0.5$$
$$P(不下单) = \frac{4}{8}=0.5$$
该同学对 “价位低、口味偏甜、距离远” 这次推荐的 “下单” 或 “不下单” 的似然概率为(注意基本假设是店铺价位、口味、距离这些特质中间互相独立,互不影响):
$$ \begin{align} &P(价位=低,口味=偏甜,距离=远|下单)\\ =&P(价位=低|下单)×P(口味=偏甜|下单)×P(距离=远|下单)\\ =&\frac{3}{4}×\frac{3}{4}×\frac{1}{4}\\ ≈ & 0.141 & \\ & \\ & P(价位=低,口味=偏甜,距离=远|不下单)\\ =&P(价位=低|不下单)×P(口味=偏甜|不下单)×P(距离=远|不下单)\\ =&\frac{1}{4}×\frac{1}{4}×\frac{3}{4}\\ ≈ &0.047 \end{align} $$根据贝叶斯公式,可以得到该同学在一家“价格低、口味偏甜、距离远”的店铺,
下单的后验概率为:
$$ \begin{align} &P(下单|价位=低,口味=偏甜,距离=远)\\ =&P(下单)×P(价位=低,口味=偏甜,距离=远|下单)\\ =&0.5×0.141\\ = &0.0705 \end{align} $$不下单的后验概率为: $$ \begin{align} &P(不下单|价位=低,口味=偏甜,距离=远)\\ =&P(不下单)×P(价位=低,口味=偏甜,距离=远|不下单)\\ =&0.5×0.047\\ =&0.0235 \end{align} $$
由此可见,该同学这次会下单的概率大于不下单的概率。
上面的计算过程进行了一些简化,本来应该计算如下两个公式:
$$ \begin{align} &P(下单|价位=低,口味=偏甜,距离=远)\\ =&\frac{P(下单)×P(价位=低,口味=偏甜,距离=远|下单)}{P(价位=低,口味=偏甜,距离=远)}\\ \end{align} $$$$ \begin{align} &P(不下单|价位=低,口味=偏甜,距离=远)\\ =&\frac{P(不下单)×P(价位=低,口味=偏甜,距离=远|不下单)}{P(价位=低,口味=偏甜,距离=远)}\\ \end{align} $$上述两个计算公式分母相同,对计算结果不影响,因此就从计算过程中略去了。
实践与体验¶
利用朴素贝叶斯分类器解决 MNIST 手写体数字识别问题¶
MNIST 是一个手写体数据集,它包含了各种各样的手写体数字图像及其对应的数字标签。其中每幅手写体图像的大小为 28×28 ,共有 784 个像素点,可记为一个 784 维的向量,每个 784 维向量对应着一个标签。
import warnings
warnings.filterwarnings("ignore")
import numpy as np
from tensorflow.keras.datasets import mnist
from sklearn.naive_bayes import BernoulliNB
import matplotlib.pyplot as plt
2.读取 MNIST 训练集和测试集。
print("读取数据中 ...")
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape(train_images.shape[0], 784)
test_images = test_images.reshape(test_images.shape[0], 784)
print('读取完毕!')
我们使用下面的方法来查看其中几张图片。
def plot_images(imgs):
"""绘制几个样本图片
:param show: 是否显示绘图
:return:
"""
sample_num = min(9, len(imgs))
img_figure = plt.figure(1)
img_figure.set_figwidth(5)
img_figure.set_figheight(5)
for index in range(0, sample_num):
ax = plt.subplot(3, 3, index + 1)
ax.imshow(imgs[index].reshape(28, 28), cmap='gray')
ax.grid(False)
plt.margins(0, 0)
plt.show()
plot_images(train_images)
3.根据 MNIST 训练集训练朴素贝叶斯分类器
print("初始化并训练贝叶斯模型...")
classifier_BNB = BernoulliNB()
classifier_BNB.fit(train_images,train_labels)
print('训练完成!')
4.根据训练出的分类器对 MNIST 测试集中的图片进行识别,得到预测值。
print("测试训练好的贝叶斯模型...")
test_predict_BNB = classifier_BNB.predict(test_images)
print("测试完成!")
5.将测试图片的预测值与实际值相比较,计算并输出分类器的正确率。
accuracy = sum(test_predict_BNB==test_labels)/len(test_labels)
print('贝叶斯分类模型在测试集上的准确率为 :',accuracy)
6.对实验结果进行分析比较,列出 0-9 不同数字识别的准确率,比较其差异。
# 记录每个类别的样本的个数,例如 {0:100} 即 数字为 0 的图片有 100 张
class_num = {}
# 每个类别预测为 0-9 类别的个数,
predict_num = []
# 每个类别预测的准确率
class_accuracy = {}
for i in range(10):
# 找到类别是 i 的下标
class_is_i_index = np.where(test_labels == i)[0]
# 统计类别是 i 的个数
class_num[i] = len(class_is_i_index)
# 统计类别 i 预测为 0-9 各个类别的个数
predict_num.append(
[sum(test_predict_BNB[class_is_i_index] == e) for e in range(10)])
# 统计类别 i 预测的准确率
class_accuracy[i] = round(predict_num[i][i] / class_num[i], 3) * 100
print("数字 %s 的样本个数:%4s,预测正确的个数:%4s,准确率:%.4s%%" % (
i, class_num[i], predict_num[i][i], class_accuracy[i]))
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(rc={'figure.figsize': (12, 8)})
np.random.seed(0)
uniform_data = predict_num
ax = sns.heatmap(uniform_data, cmap='YlGnBu', vmin=0, vmax=150)
ax.set_xlabel('真实值')
ax.set_ylabel('预测值')
plt.show()
通过热力图,我们看到 3 经常被错认为 5 和 8, 4 和 9 经常互相错认。
我们看看真实标签为 9,但是预测为 4 的错认的照片
def get_imgs(images, true_labels, predict_labels, true_label,
predict_label):
"""
从全部图片中按真实标签和预测标签筛选出图片
:param images: 一组图片
:param true_labels: 每张图片的标签
:param predict_labels: 模型预测的每张图片的标签
:param true_label: 希望取得的图片的真实标签
:param predict_label: 希望取得的图片的预测标签
:return:
"""
# 所有类别为 true_label 的样本的 index 值
true_label_index = set(np.where(true_labels == true_label)[0])
# 所有预测类别为 predict_label 的样本的 index 值
predict_label_index = set(np.where(predict_labels == predict_label)[0])
# 取交集,即为真实类别为 true_label, 预测结果为 predict_label 的样本的 index 值
res = list(true_label_index & predict_label_index)
return images[res]
imgs = get_imgs(test_images, test_labels, test_predict_BNB, 9, 4)
plot_images(imgs)
问题 1:你在上面的试验中观察到了什么?在下方列出模型对 0-9 不同数字识别的准确率,并比较其差异。
答案 1:(在此处填写你的答案。)