这章主要讲解朴素贝叶斯的分类操作,贝叶斯定理是概率论一个重要部分
由条件概率:P(A∩B) = P(A)P(B|A)=P(B)P(A|B)
和全概率公式 P(A)=P(AB1)+P(AB2)+...+P(ABn)),其中A与Bn的关系为交)。
推导出来:P(A|B)=P(B|A)*P(A)/P(B)
在生活中,我们也经常用到,这里就不展开数学推导了,有兴趣的同学可以百度,接下来我们跟着书里面的代码走起。
1、假设上一周的天气有4个特征:刮北风、闷热、多云、天气预报有雨
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 = {} # 设置一个空字典,把分类统计进去
for label in np.unique(y):
counts[label] = X[y == label].sum(axis = 0)
counts
{0: array([1, 2, 0, 4]), 1: array([1, 3, 3, 0])}
可以发现,预报有雨,但是都没有下雨,没有预报有雨的反而下雨了
# 使用贝努力贝叶斯进行拟合,因为这个符合二项式分布
from sklearn.naive_bayes import BernoulliNB
clf = BernoulliNB()
clf.fit(X,y)
# 如果今天是 没有北风、不闷热,没有预报有雨,但是多云,是否会下雨
today = [[0,0,1,0]]
today_predict = clf.predict(today)
if today_predict == 1:
print('要下雨啦')
else:
print('没事,不会下雨的')
print('概率:',clf.predict_proba(today))
要下雨啦
概率: [[0.13848881 0.86151119]]
可以发现有86%的可能会下雨
刚刚用的是二项式分布,我们再试试更复杂的数据集
##使用测试集生成数据,进行贝努利贝叶斯测试
from sklearn.datasets import make_blobs
from sklearn.naive_bayes import BernoulliNB
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, test_size = 0.25, random_state = 8)
# 调整参数移动分类界限
bl = BernoulliNB(binarize=3)
bl.fit(X_train, y_train)
print('得分 = {:.3f}'.format(bl.score(X_test, y_test)))
得分 = 0.592
得分有点低,我们通过可视化来看看分类情况
# 用matplotlib 进行可视化
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(20,10))
#限定X Y 轴的最大值和最小值
x_min, x_max = X[:,0].min() - 1, X[:,0].max() + 1
y_min, y_max = X[:,1].min() - 1, X[:,1].max() + 1
#用不同的颜色表示不同的类别
xx, yy = np.meshgrid(np.arange(x_min, x_max,0.02),
np.arange(y_min,y_max,0.02))
z = bl.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, edgecolor = 'k')
plt.scatter(X_test[:,0], X_test[:,1], c = y_test, cmap = plt.cm.cool, edgecolor = 'k',marker = '*',s = 150)
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.title('Classifier: BernoulliNB')
plt.show()
可以发现分类界限就在 3 ,可见贝努利贝叶斯不合适分类复杂的数据
2、我们接下来用高斯朴素贝叶斯来拟合一下,高斯朴素贝叶斯适用于 当特征值符合高斯正态分布的数据
## 高斯朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
gnb.fit(X_train, y_train)
print('得分:', gnb.score(X_test, y_test))
# 进行可视化
z1 = gnb.predict(np.c_[xx.ravel(),yy.ravel()]).reshape(xx.shape)
plt.figure(figsize = (10,8))
plt.pcolormesh(xx, yy, z1, cmap = plt.cm.Pastel1)
plt.scatter(X_train[:,0], X_train[:,1], c = y_train, cmap = plt.cm.cool, edgecolor = 'k')
plt.scatter(X_test[:,0], X_test[:,1], c = y_test, cmap = plt.cm.cool, edgecolor = 'k', marker = '*', s = 150)
plt.title('Classifier : GaussianNB')
plt.show()
得分: 0.968
可以发现高斯朴素贝叶斯的拟合效果会好很多,因为在现实生活中,很多特征也都是符合正态分布的。
3、接下来我们看看另一种贝叶斯模型:多项式朴素贝叶斯
什么是多项式分布呢,0和1就是二项式分布,那像骰子一样6个数的,就是多项式分布了,不过需要注意,多项式朴素贝叶斯的特征值需是非负值。
# 使用多项式朴素贝叶斯
from sklearn.naive_bayes import MultinomialNB
# 使用多项式朴素贝叶斯,需要将 X 值转化为 非负值 使用自带的 MinMaxScaler 对原始数据进行预处理
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)
mnb_scores = mnb.score(X_test_scaled, y_test)
print('多项式朴素贝叶斯得分:{:.3f}'.format(mnb_scores))
# 多项式朴素贝叶斯可视化
z = mnb.predict(np.c_[xx.ravel(),yy.ravel()]).reshape(xx.shape)
# 区域分颜色
plt.figure(figsize = (10,8))
plt.pcolormesh(xx,yy,z,cmap = plt.cm.Pastel1)
#画散点
plt.scatter(X_train[:,0], X_train[:,1], c = y_train, cmap = plt.cm.cool, edgecolor = 'k')
plt.scatter(X_test[:,0], X_test[:,1], c = y_test, cmap = plt.cm.cool,marker = '*', s = 150, edgecolor = 'k')
plt.title('Classifier MultinomialNB')
plt.show()
多项式朴素贝叶斯得分:0.320
可见多项式分布也不适合以上的样本数据。
多项式朴素贝叶斯只适合用于对非负离散型数值进行分类,典型例子为 转化为向量后的文本数据进行分类,后面也会有文章讲到。
4、实战:肿瘤分类
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
print(cancer.keys())
print('标签:',cancer.target_names,'\n 特征',cancer.feature_names)
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])
标签: ['malignant' 'benign']
特征 ['mean radius' 'mean texture' 'mean perimeter' 'mean area'
'mean smoothness' 'mean compactness' 'mean concavity'
'mean concave points' 'mean symmetry' 'mean fractal dimension'
'radius error' 'texture error' 'perimeter error' 'area error'
'smoothness error' 'compactness error' 'concavity error'
'concave points error' 'symmetry error' 'fractal dimension error'
'worst radius' 'worst texture' 'worst perimeter' 'worst area'
'worst smoothness' 'worst compactness' 'worst concavity'
'worst concave points' 'worst symmetry' 'worst fractal dimension']
以上都是一些医学方面的描述。
因为是连续型数据,推荐使用高斯朴素贝叶斯,我们也可以用三个模型一起测试一下
from sklearn.naive_bayes import MultinomialNB,BernoulliNB,GaussianNB
from sklearn.model_selection import train_test_split
# 拆分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, test_size = 0.25, random_state = 8)
#可以看看训练集和测试集数据的形状
print('训练集数据情况:', X_train.shape)
print('测试集数据情况:', X_test.shape)
#顺便看看有没有非负值
print(cancer.data[cancer.data < 0])
训练集数据情况: (426, 30)
测试集数据情况: (143, 30)
[]
可见没有非负值,无需转化特征值
# 使用多项式朴素贝叶斯进行拟合
mnb = MultinomialNB()
mnb.fit(X_train, y_train)
# 查看得分情况
print('训练集得分:{:.3f}'.format(mnb.score(X_train, y_train)))
print('测试集得分:{:.3f}'.format(mnb.score(X_test, y_test)))
训练集得分:0.899
测试集得分:0.874
#使用贝努利贝叶斯进行拟合
bnb = BernoulliNB()
bnb.fit(X_train, y_train)
# 查看得分情况
print('训练集得分:{:.3f}'.format(bnb.score(X_train, y_train)))
print('测试集得分:{:.3f}'.format(bnb.score(X_test, y_test)))
训练集得分:0.638
测试集得分:0.594
#使用高斯朴素贝叶斯进行拟合
gnb = GaussianNB()
gnb.fit(X_train, y_train)
# 查看得分情况
print('训练集得分:{:.3f}'.format(gnb.score(X_train, y_train)))
print('测试集得分:{:.3f}'.format(gnb.score(X_test, y_test)))
训练集得分:0.948
测试集得分:0.937
果然还是高斯朴素贝叶斯的拟合效果要好
现在随机抽取一个样本进行测试,书本抽的是312,我这里抽取第300个
sample_one = cancer.data[300]
print('贝努利贝叶斯得出的结果是:',bnb.predict([sample_one]))
print('多项式朴素贝叶斯得出的结果是:',mnb.predict([sample_one]))
print('高斯朴素贝叶斯得出的结果是:',gnb.predict([sample_one]))
print('真实结果是:',cancer.target[300])
贝努利贝叶斯得出的结果是: [1]
多项式朴素贝叶斯得出的结果是: [0]
高斯朴素贝叶斯得出的结果是: [0]
真实结果是: 0
5、学习曲线
from sklearn.model_selection import learning_curve, ShuffleSplit
# 定义一个函数绘制学习曲线
def plot_learning_curve(estimator, title, X, y, ylim = None, cv = None, n_jobs = 1, train_sizes = np.linspace(0.1,1,5)):
plt.figure(figsize = (10,8))
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
# 设置轴标签
plt.rcParams['font.sans-serif']=['FangSong']
plt.rcParams['axes.unicode_minus'] = False
plt.xlabel('测试样本')
plt.ylabel('得分')
train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv = cv, n_jobs = n_jobs, train_sizes = train_sizes)
train_scores_mean = np.mean(train_scores, axis = 1)
test_scores_mean = np.mean(test_scores,axis = 1)
plt.grid()
plt.plot(train_sizes,train_scores_mean, 'o-', c = 'r', label = '训练集得分')
plt.plot(train_sizes,test_scores_mean, 'o-', c = 'g', label = '交叉验证得分')
plt.legend(loc = 'best')
return plt
title = '高斯朴素贝叶斯学习曲线'
cv = ShuffleSplit(n_splits = 10, test_size = 0.2, random_state = 0)
estimator = GaussianNB()
#调用函数
plot_learning_curve(estimator, title, X, y, ylim = (0.9,1.01), cv = cv, n_jobs = 4)
plt.show()