- .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
- decision_tree_1.mp4
- essay1_ch.txt
- essay1_en.txt
- essay2_ch.txt
- essay2_en.txt
- essay3_ch.txt
- essay3_en.txt
- foo.csv
- iris.csv
- mnist.npz
- model.h5
- model.png
- nn_media1.mp4
- nn_media2.mp4
- nn_media3.mp4
- nn_media4.mp4
- nn_media5.mp4
- nn_media6.mp4
- search-Copy1.py
- search.py
- Untitled.ipynb
02.04 贝叶斯分析(学生版).ipynb @master — view markup · raw · history · blame
2.4 贝叶斯分析¶
贝叶斯分析是一种根据概率统计知识对数据进行分析的方法,属于统计学分类的范畴。
2.4.1 贝叶斯公式¶
想一想
频率学派 和 贝叶斯学派各自的主张是什么?
贝叶斯公式:
$$P(A|B) = \frac{P(B|A)P(A)}{P(B)}$$中的各项分别代表什么意思?
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))
扩展内容¶
化验结果为阳性就代表你真的患病了吗?¶
某同学 A 身体不舒服,去医院作了验血检查,看他是否得了 X 疾病,检查结果居然为阳性,他吓了一跳,赶紧上网查询。他看到网上有资料说,实验总是有误差的,这种实验有“百分之一的假阳性率和百分之一的假阴性率”。也就是说,在确实得了 X 疾病的人里面, 会有 1% 的人是假阴性,99%的人是真阳性, 也就是会有 1% 的几率被误诊为没病。而没得病的人去做检查,有 1% 的人是假阳性,99% 的人是真阴性,也就是会有 1% 的几率被误诊为有病。 于是,他认为,既然误检的概率这么低,那么他确实患病的概率应该是非常高的。
可是,医生却告诉他,他被感染的概率只有 0.09 左右。这是怎么回事呢?
医生说:“不用害怕。99% 是测试的准确性,不是你得病的概率。你忘了考虑一件事:这种疾病的患病比例是很小的,1000个人中只有一个人有这种病。”
医生的计算方法是这样的:因为测试的误报率是 1%,1000个人将有 10 个被报为“假阳性”,而根据 X 病在人口中的比例(1/1000=0.1%),也就是说 1000 个人里真阳性只有1个。所以,大约 11 个测试为阳性的人中才有一个是真阳性(有病)的人,因此,同学被感染的几率是大约1/11,即0.09(9%)。
动手练
$A$ : 普通人患 X 病
$B$ : 化验结果为阳性
$P(A)$ 普通人患 X 的病概率 1/1000
$P(B)$ 化验结果为阳性的总可能性
$P(A|B)$:检测结果为阳性时,一个人患 X 病的概率
$P(B|A)$:一个人患 X 病,其检测结果为阳性的概率, 99%
根据贝叶斯公式,计算 $P(A|B)$
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 维向量对应着一个标签。
!mkdir -p ~/.keras/datasets
!cp ./mnist.npz ~/.keras/datasets/mnist.npz
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:(在此处填写你的答案。)