朴素贝叶斯
定理:
某晚,C准备收拾东西接女朋友,那么小C要不要带伞呢。
已知:天气预报说今日降水概率为50%–P(A)
晚高峰堵车的概率为80%–P(B)
如果下雨,晚高峰堵车的概率是95%–P(B|A)
小C向窗外看去,看到了堵车,则根据贝叶斯定理:
P(A|B)=(P(B|A)*P(A))/P(B)
求得下雨的概率为0.5*0.95/0.8=0.59375,较大概率下雨,拿伞
应用:
过去七天中,3天有雨,4天没雨,用数组表示就是:y=[0,1,1,0,1,0,0]。
其它信息包括刮风、闷热、多云等信息。
刮北风 | 闷热 | 多云 | 天气预报有雨 | |
---|---|---|---|---|
第一天 | 否 | 是 | 否 | 是 |
第二天 | 是 | 是 | 是 | 否 |
第三天 | 否 | 是 | 是 | 否 |
第四天 | 否 | 否 | 否 | 是 |
第五天 | 否 | 是 | 是 | 否 |
第六天 | 否 | 是 | 否 | 是 |
第七天 | 是 | 否 | 否 | 是 |
用0表示否,赢1表示是,得到一个数组:
X=[0,1,0,1],[1,1,1,0],[0,1,1,0],[0,0,0,1],[0,1,1,0],[0,1,0,1],[1,0,0,1]
代码实现:
导入numpy
import numpy as np
X = np.array([[0,1,0,1],
[1,1,1,0],
[0,1,1,0],
[0,0,0,1],
[0,1,1,0],
[0,1,0,1],
[1,0,0,1]])
y = np.array([0,1,1,0,1,0,0])
counts = {}
# 对不同分了i计算每个特征值为1的数量
for label in np.unique(y):
counts[label] = X[y == label].sum(axis=0)
print(counts)
运行结果:{0: array([1, 2, 0, 4]), 1: array([1, 3, 3, 0])}
这个结果的意思是,当y=0时,即没有下雨的4天当中,有一天刮了被封,有两天比较闷热,而没有出现多云的情况,但这四天中天气预报全部播报为有雨。同时,在y=1时,也就是下雨的三天当中有1天刮了北风,3天全都比较闷热,且三天全部出现了多云的现象,而这三天天气预报都是没有雨。
那么对于朴素贝叶斯,它会根据上述计算来进行推理。它会认为,如果某一天天气预报没有播报有雨,但出现了多云的情况,它会倾向于把这一天放到‘下雨’这一分类中。
# 导入贝努力贝叶斯
from sklearn.naive_bayes import BernoulliNB
clf = BernoulliNB()
clf.fit(X,y)
# 要进行预测的这一天没有刮风也不闷热
#但是多云,天气预报说没有雨
Next_Day=[[0,0,1,0]]
pre = clf.predict(Next_Day)
if pre == [1]:
print('要下雨啦,收衣服了!')
else:
print('放心,今天是个艳阳天')
运行结果: 要下雨啦,收衣服了!
可以看出,朴素贝叶斯分类器把这一天放到了会下雨的分类中。
那么朴素贝叶斯的准确率怎么样,用predict_proba方法测试
print(clf.predict_proba(Next_day))
[[0.13848881 0.86151119]]
意思是,不下雨的概率为13.8%,下雨的概率为86.2%,预测结果还不错。
但是如果在scikit-learn官网上查看文档,会发现一段很搞笑的描述–虽然朴素贝叶斯是相当好的分类器,但对于预测具体的数值并不是很擅长,因此predict_proda给出的预测概率,大家不要太当真。
其它方法:
-
贝努力朴素贝叶斯
这种方法比较适合符合贝努力分布的数据集,贝努力分布也称为“二项分布或者”0-1“分布,比如抛硬币游戏,硬币落下来只有两种结果:正面或反面,这种情况下我们就称抛硬币的结果是贝叶斯分布。如果用复杂的数据集交给贝努力贝叶斯,结果就会遍得不同。
# 导入是数据集生成工具
from sklearn.datasets import make_blobs
#导入数据集拆分工具
from sklearn.model_selection import train_test_split
#生成样本数量为500,分类为5的数据集
X, y = make_blobs(n_samples=500, centers=5, random_state=8)
#将数据集拆分成训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y,random_state=8)
# 使用贝努力贝叶斯拟合数据
nb = BernoulliNB()
nb.fit(X_train, y_train)
print(f'模型得分{nb.score(X_test,y_test)}')
运行结果: 模型得分0.544
可以看出对于手工生成的数据,贝努力贝叶斯得分很差。
通过通过图像来了解以贝努力朴素贝叶斯的工作过程。
import matplotlib.pyplot as plt
import numpy as np
# 限定横轴与纵轴的最大值
x_min, x_max = X[:,0].min() - 0.5, X[:,0].max()+0.5
y_min, y_max = X[:,1].min()- 0.5, X[:,0].max()+0.5
# 用不同颜色的背景色表示不同的分类
xx, yy = np.meshgrid(np.arange(x_min, x_max,.02),
np.arange(y_min,y_max,.02))
z = nb.predict(np.c_[(xx.ravel(), yy.ravel())]).reshape(xx.shape)
plt.pcolormesh(xx,yy,z,cmap=plt.cm.Pastel1)
# 将训练集和测试集用散点图表示
plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolors='k')
plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,marker='*',edgecolor='k')
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
# 定义图题
plt.title('Classifier:BernoulliNB')
# 图片
plt.show()
此时朴素贝叶斯分类比较简单,所以在多特征多分类时,贝努力贝叶斯就不能再使用,应该考虑高斯贝叶斯。
-
高斯朴素贝叶斯
顾名思义就是假设样本的特征符合高斯分布,或者符合正态分布时所用的算法。接下来用高斯分布对数据集进行拟合。
# 导入高斯贝叶斯
from sklearn.naive_bayes import GaussianNB
# 使用高斯贝叶斯拟合数据
gnb = GaussianNB()
gnb.fit(X_train,y_train)
print(f'模型得分为:{gnb.score(X_test,y_test)}')
运行结果:模型得分:0.968
准确率达到了96.8%。再用图像进行演示。
z = nb.predict(np.c_[(xx.ravel(), yy.ravel())]).reshape(xx.shape)
plt.pcolormesh(xx,yy,z,cmap=plt.cm.Pastel1)
# 将训练集和测试集用散点图表示
plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolors='k')
plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,marker='*',edgecolor='k')
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
# 定义图题
plt.title('Classifier:GaussianNB')
# 图片
plt.show()
结果分析:高斯朴素贝叶斯的分类边界比贝努力贝叶斯的分类边界要复杂的多,也基本上把数据点都放进了正确的分类当中了。
事实上,高斯朴素贝叶斯也确实能够胜任大部分的分类任务,这是因为在自然科学和社会科学领域,有大量的现象都是呈现出正态分布的状态。
-
多项式朴素贝叶斯
主要用于拟合多项式分布的数据集。需要注意的是多项式朴素贝叶斯要求输入的X值必须是正直,所以需要对输入的值进行归一化处理。MinMaxScaler的作用默认将数据转化到0~1。
# 导入多项式朴素贝叶斯
from sklearn.naive_bayes import MultinomialNB
# 导入数据预处理工具
from sklearn.preprocessing import MinMaxScaler
# 使用数据预处理工具使数据全部为非负值
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
#使用多项式朴素贝叶斯拟合经过预处理之后的数据
mnb = MultinomialNB()
mnb.fit(X_train_scaled,y_train)
print(f'模型得分:{mnb.score(X_test_scaled,y_test)}')
运行结果:模型得分:0.32
准确率比贝努力朴素贝叶斯还低。
画图看一下
z = mnb.predict(np.c_[(xx.ravel(), yy.ravel())]).reshape(xx.shape)
plt.pcolormesh(xx,yy,z,cmap=plt.cm.Pastel1)
# 将训练集和测试集用散点图表示
plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolors='k')
plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,marker='*',edgecolor='k')
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
# 定义图题
plt.title('Classifier:MultinomialNB')
# 图片
plt.show()
可以看出多项式朴素贝叶斯分类能i非常差,大部分数据点放到了错误的位置上。
这是因为,多项式朴素贝叶斯只适合对非负离散数值特征进行分类,典型的例子就是对转化为向量后的文本数据进行分类。
可以看出多项式朴素贝叶斯分类能i非常差,大部分数据点放到了错误的位置上。
这是因为,多项式朴素贝叶斯只适合对非负离散数值特征进行分类,典型的例子就是对转化为向量后的文本数据进行分类。
注:本文为参考《深入浅出python机器学习》做的个人笔记,经过个人理解与简单修改。