自助做app的网站,app模拟制作,北京网站建设 博客,emlog与wordpress区别目录 sklearn中的贝叶斯分类器
前言
1 分类器介绍
2 高斯朴素贝叶斯GaussianNB
2.1 认识高斯朴素贝叶斯
2.2 高斯朴素贝叶斯建模案例
2.3 高斯朴素贝叶斯擅长的数据集
2.3.1 三种数据集介绍
2.3.2 构建三种数据
2.3.3 数据标准化
2.3.4 朴素贝叶斯处理数据
2.4 高斯…目录 sklearn中的贝叶斯分类器
前言
1 分类器介绍
2 高斯朴素贝叶斯GaussianNB
2.1 认识高斯朴素贝叶斯
2.2 高斯朴素贝叶斯建模案例
2.3 高斯朴素贝叶斯擅长的数据集
2.3.1 三种数据集介绍
2.3.2 构建三种数据
2.3.3 数据标准化
2.3.4 朴素贝叶斯处理数据
2.4 高斯朴素贝叶斯的拟合效果与运算速度
2.4.1 交叉验证的概念
2.4.2 ShuffleSplit和learning_curve
2.4.3 交叉验证分析
3 概率模型的评估指标
3.1 前言
3.2 布里尔分数Brier Score
3.3 对数似然函数Log Loss
3.4 可靠性曲线 reliability curve
3.4.1 基础知识
3.4.2 模型评估
1 朴素贝叶斯评估
2 其它模型
3.5 预测概率的直方图
3.6 校准可靠性曲线
3.6.1 基础知识
3.6.2 分析贝叶斯模型
3.6.3 SVC校准效果
4 其它贝叶斯
4.1 多项式朴素贝叶斯MultinomialNB
1 如何判定数据符合多项式朴素贝叶斯
2 MultinomialNB语法格式
3 代码实现
1 基础知识
2 连续型数据处理
2 分类型数据
4.2 伯努利贝叶斯
1 BernoulliNB语法格式
2 代码例子
4.3 类别贝叶斯CategoricalNB
1 CategoricalNB语法格式
2 代码例子
4.4 贝叶斯的样本不平衡问题
4.5 补集贝叶斯
1 ComplementNB语法格式
2 代码例子 sklearn中的贝叶斯分类器
前言
sklearn下各种朴素贝叶斯的分类器的原理可看sklearn之各类朴素贝叶斯原理
1 分类器介绍
Sklearn基于数据分布以及这些分布上的概率估计的改进为我们提供了四个朴素贝叶斯的分类器。
类含义naive_bayes.BernoulliNB伯努利分布下的朴素贝叶斯naive_bayes.GaussianNB高斯分布下的朴素贝叶斯naive_bayes.MultinomialNB多项式分布下的朴素贝叶斯naive_bayes.ComplementNB补集朴素贝叶斯naive_bayes.CategoricalNB类别贝叶斯linear_model.BayesianRidge贝叶斯岭回归在参数估计过程中使用贝叶斯回归技术来包括正则化参数
贝叶斯有以下特点
贝叶斯是从概率角度进行估计不需要太多的样本量极端情况下甚至我们可以使用1%的数据作为训练集依然可以得到很好的拟合效果。当然如果样本量少于特征数目贝叶斯的效果就会被削弱。与SVM和随机森林相比朴素贝叶斯运行速度更快因为求解本质是在每个特征上单独对概率进行计算然后再求乘积所以每个特征上的计算可以是独立并且并行的贝叶斯的运行效果不是那么好贝叶斯模型预测结果也不是总指向真正的分类结果
2 高斯朴素贝叶斯GaussianNB
2.1 认识高斯朴素贝叶斯
class sklearn.naive_bayes.GaussianNB(*, priorsNone, var_smoothing1e-09)
参数说明
参数说明priorsarray-like of shape (n_classes,) 类别的先验概率。一经指定不会根据数据进行调整。var_smoothingfloat, default1e-9 所有特征的最大方差部分添加到方差中用于提高计算稳定性。
属性说明
属性说明class_count_ndarray of shape (n_classes,) 每个类别中保留的训练样本数量。class_prior_ndarray of shape (n_classes,) 每个类别的概率。classes_ndarray of shape (n_classes,) 分类器已知的类别标签epsilon_float 方差的绝对相加值sigma_ndarray of shape (n_classes, n_features) 每个类中每个特征的方差theta_ndarray of shape (n_classes, n_features) 每个类中每个特征的均值
方法说明
方法说明fit(X, y[, sample_weight])根据Xy拟合高斯朴素贝叶斯get_params([deep])获取这个估计器的参数partial_fit(X, y[, classes, sample_weight])对一批样本进行增量拟合predict(X)对测试向量X进行分类。predict_log_proba(X)返回针对测试向量X的对数概率估计predict_proba(X)返回针对测试向量X的概率估计score(X, y[, sample_weight])返回给定测试数据和标签上的平均准确率。set_params(**params)为这个估计器设置参数
对X矩阵和y矩阵的要求
参数说明Xarray-like of shape (n_samples, n_features) 用于训练的向量其中n_samples是样本数量n_features是特征数量。yarray-like of shape (n_samples,) 目标值。 2.2 高斯朴素贝叶斯建模案例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split# 导入数据集
digits load_digits()X digits.data
y digits.target# 划分测试集和训练数据集,划分后训练数据1257个样本测试数据集540个样本
xtrain, xtest, ytrain, ytest train_test_split(X, y, test_size0.3, random_state0)# 查看标签种类
print(f种类标签为:\n{np.unique(ytrain)})# 实例化模型并且训练模型其中fit()过程就是在计算概率的过程
gnb GaussianNB().fit(xtrain, ytrain)# score()接口对于我们的分类型算法返回预测的精确性也就是accuracy使用测试数据集测试
acc_score gnb.score(xtest, ytest)
print(f预测的精确性为:{acc_score})# 返回所有样本对应的类别这里的样本标签是用我们下面得到的概率中
# 选取每一个样本中概率最大的作为此样本的标签
y_pred gnb.predict(xtest)
print(f贝叶斯模型对所有样本的预测类别为:\n{y_pred})# 查看我们的概率结果
# 可以看到返回的结果是540*10的二维矩阵其中应为分类有10个所以一共返回10列概率
# 取其中概率最大的哪一个分类作为最后的分类结果并且每一行的概率之和是1
yprob gnb.predict_proba(xtest)
print(f查看样本计算的概率结果结果为:\n{yprob})# 注意ROC曲线是不能用于多分类的。多分类状况下最佳的模型评估指标是混淆矩阵和整体的准确度
# 主对角线上的点是全部分类正确的而我们的主对角线的数值很大因此准确率很高
from sklearn.metrics import confusion_matrix as CM
print(f混淆矩阵为:\n{CM(ytest, y_pred)})
知识点补充
1train_test_split
语法格式如下
X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.25, random_stateNone, shuffleTrue, stratifyNone)X: 表示要划分的特征数据集。y: 表示相应的标签。test_size: 测试集的大小。可以是浮点数表示比例或整数表示样本数默认为 0.25。random_state: 随机种子用于控制随机数生成过程。如果设置为某个整数则每次划分数据集时将使用相同的随机种子以确保结果的可重复性。如果不设置则每次运行时都会生成不同的随机种子。shuffle: 是否在划分数据集之前对数据进行洗牌。默认为 True即洗牌。stratify: 可选参数用于在划分数据集时根据标签的分布来进行分层抽样。如果指定了该参数并且标签是分类问题的话将会根据标签的类别进行分层抽样确保训练集和测试集中各类别的样本比例与原始数据集中的比例相同。默认为 None表示不进行分层抽样。
2 load_digits
主要的参数如下
data: 包含手写数字的特征数据每一行代表一个样本每一列代表一个特征像素。target: 包含每个样本对应的标签即手写数字的真实值。target_names: 包含标签的名称即手写数字的可能取值。images: 包含手写数字的图像数据是 8x8 像素的灰度图像。 DESCR: 数据集的描述信息包括数据集的来源、特征的含义等。
索引 data images
其中每个元素是8×8的矩阵 target
每个数据对应的标签 target_names
所有的类别标签 data[1]元素为例
64维的向量 8×8的矩阵可以大致看出数字 ‘1’ 的轮廓 用plt.imshow()可以将images可视化 该数据的类别 2.3 高斯朴素贝叶斯擅长的数据集
2.3.1 三种数据集介绍
月亮型数据Moon-shaped data
月亮型数据是指具有类似月亮形状的数据分布。一般使用sklearn.datasets的make_moons方法调入方式为
from sklearn.datasets import make_moons
其语法格式为
make_moons(n_samples100, *, shuffleTrue, noiseNone, random_stateNone)n_samples: 生成的样本数量默认为 100。shuffle: 是否对数据进行洗牌默认为 True。如果设置为 False则生成的数据将按顺序排列。noise: 添加到数据集中的高斯噪声的标准差。如果为 None则不添加噪声。默认为 None。random_state: 随机种子用于控制随机数生成过程。如果设置为某个整数则每次生成数据集时将使用相同的随机种子以确保结果的可重复性。如果不设置则每次运行时都会生成不同的随机种子。
环形数据Ring-shaped data
环形数据是指具有环形或圆环形状的数据分布。数据点围绕着一个中心点呈环状排列。一般使用sklearn.datasets的make_circles方法调入方式为
from sklearn.datasets import make_circles
其语法格式为
make_circles(n_samples100, *, shuffleTrue, noiseNone, random_stateNone, factor0.8)n_samples生成的样本数默认为 100。shuffle是否打乱样本默认为 True。noise添加到数据中的高斯噪声的标准差若为 None则表示不添加噪声默认为 None。random_state随机种子默认为 None。factor外圈与内圈半径之比默认为 0.8取值范围为 0 到 1越接近 1内外圈之间的距离越大。
二分型数据Bimodal data
二分型数据在机器学习中指的是具有两类标签或类别的数据集。 一般使用sklearn.datasets的make_classification方法调入方式为
from sklearn.datasets import make_classification
其语法格式为
make_classification(n_samples100, n_features20, *, n_informative2, n_redundant2, n_classes2, n_clusters_per_class2, weightsNone, flip_y0.01, class_sep1.0, hypercubeTrue, shift0.0, scale1.0, shuffleTrue, random_stateNone)n_samples生成的样本数默认为 100。n_features特征数默认为 20。n_informative具有信息性的特征数默认为 2。n_redundant冗余特征数默认为 2。n_classes类别数量默认为 2。n_clusters_per_class每个类别中的簇数量默认为 2。weights每个类别的样本权重默认为 None。flip_y在生成标签时翻转翻译标签的比例默认为 0.01。class_sep类之间的平均距离默认为 1.0。hypercube如果为 True则将样本分布在一个多维超立方体中默认为 True。shift数据集的平移量默认为 0.0。scale数据集的缩放比例默认为 1.0。shuffle是否打乱样本默认为 True。random_state随机种子默认为 None。
2.3.2 构建三种数据
构建月亮型数据 构建环形数据 构建二分型数据 由上图可知生成的二分型数据的两个簇离彼此很远这样不利于我们测试分类器的效果因为这样的数据无论什么模型都是几乎百分百正确率因此我们使用np生成随机数组通过让已经生成的二分型数据点加减0~1之间的随机数使数据分布变得更散更稀疏 2.3.3 数据标准化
使用sklearn.preprocessing的StandardScaler函数来将数据标准化
训练数据采用fit_transform()函数测试数据采用tansform()函数
fit_transform()函数的计算过程计算均值/标准差使用均值/标准差数据转换tansform()函数则直接使用fit_transform()函数的均值和标准差来将数据转换
StandardScaler原理
标准差标准化standardScale使得经过处理的数据符合标准正态分布即均值为0标准差为1其转化函数为 其中μ为所有样本数据的均值σ为所有样本数据的标准差
数据标准化的好处是在实际数据中不同特征的取值范围可能会相差较大这会导致某些特征在模型训练过程中对结果产生更大的影响。通过标准化可以消除这种量纲差异使得各个特征在模型训练中对结果的影响更加平衡。
2.3.4 朴素贝叶斯处理数据
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_moons, make_circles, make_classification
from sklearn.naive_bayes import GaussianNB, MultinomialNB, BernoulliNB, ComplementNBh .02
# 模型的名字
names [Multinomial, Gaussian, Bernoulli, Complement]
# 创建我们的模型对象
classifiers [MultinomialNB(), GaussianNB(), BernoulliNB(), ComplementNB()]# 构造数据
# 创建二分型数据集
X, y make_classification(n_features2, n_redundant0, n_informative2,random_state1, n_clusters_per_class1)# 处理二分型数据集使数据更加稀疏
rng np.random.RandomState(2) #生成一种随机模式
X 2 * rng.uniform(sizeX.shape) #加减0~1之间的随机数
linearly_separable (X, y) #生成了新的X依然可以画散点图来观察一下特征的分布# 准备数据集合包含了月亮型数据环型数据二分型数据
datasets [make_moons(noise0.3, random_state0),make_circles(noise0.2, factor0.5, random_state1),linearly_separable]# 创建画布,宽高比为6*9
figure plt.figure(figsize(6, 9))
#设置用来安排图像显示位置的全局变量i
i 1for ds_index, ds in enumerate(datasets):# ——————————————第一步对测试集和训练集进行可视化——————————————X, y ds# 对X中的数据进行标准化X StandardScaler().fit_transform(X)# 区分测试集和训练集X_train, X_test, y_train, y_test train_test_split(X, y, test_size.4, random_state42)# 找出数据集中两个特征的最大值和最小值让最大值0.5最小值-0.5创造一个比两个特征的区间本身更大一点的区间x1_min, x1_max X[:, 0].min() - .5, X[:, 0].max() .5x2_min, x2_max X[:, 1].min() - .5, X[:, 1].max() .5# 函数meshgrid用以生成网格数据函数np.arange在给定的两个数之间返回均匀间隔的值0.2为步长# 生成的网格数据是用来绘制决策边界的因为绘制决策边界的函数contourf要求输入的两个特征都必须是二维的array1, array2 np.meshgrid(np.arange(x1_min, x1_max, 0.2),np.arange(x2_min, x2_max, 0.2))# 创建一种颜色映射(colormap)值较大则显示蓝色值较小则显示红色中间值为白色cm plt.cm.RdBu# 用ListedColormap为画布创建颜色#FF0000正红#0000FF正蓝cm_bright ListedColormap([#FF0000, #0000FF])# 在画布上加上一个子图数据为len(datasets)行2列放在位置i上ax plt.subplot(len(datasets), 2, i)# 只需要在第一个坐标系上有标题因此设定if ds_index0这个条件if ds_index 0:ax.set_title(Input data)# 将数据集的分布放到我们的坐标系上# 使用cm_bright画布其中类别为0是正红类别为1是正蓝# 放训练集ax.scatter(X_train[:, 0], X_train[:, 1], cy_train,cmapcm_bright, edgecolorsk)# 放测试集ax.scatter(X_test[:, 0], X_test[:, 1], cy_test,cmapcm_bright, alpha0.6, edgecolorsk)# 为图设置坐标轴的最大值和最小值ax.set_xlim(array1.min(), array1.max())ax.set_ylim(array2.min(), array2.max())# 设置没有坐标轴ax.set_xticks(())ax.set_yticks(())# 每次循环之后改变i的取值让图每次位列不同的位置i 1# ——————————————第二步从这里开始是贝叶斯模型对贝叶斯模型处理的数据可视化——————————————# 在画布上加上一个子图数据为len(datasets)行2列放在位置i上# 这里的i取值分别为2,4,6ax plt.subplot(len(datasets), 2, i)# 高斯朴素贝叶斯的建模过程fit训练 → score接口得到预测的准确率clf GaussianNB().fit(X_train, y_train)score clf.score(X_test, y_test)# 绘制决策边界为此我们将为网格中的每个点指定一种颜色[x1_minx1_max] x [x2_minx2_max]# ravel()能够将一个多维数组转换成一维数组np.c_是能够将两个数组组合起来的函数# 使用ravel()和np.c_为网格中每个点指定一种颜色# 使用高斯朴素贝叶斯的predict_proba返回每一个输入的数据点所对应的标签类概率[:, 1]代表只取标签类为1的概率Z clf.predict_proba(np.c_[array1.ravel(), array2.ravel()])[:, 1]# 将返回的类概率作为数据放到contourf里面绘制去绘制轮廓# 由于取了类别1的类概率当类概率越高时代表类1则显示正蓝;类概率越低时代表类0则显示正红。与图中的训练集和测试集的颜色相对应Z Z.reshape(array1.shape)ax.contourf(array1, array2, Z, cmapcm, alpha.8)# 同理由于i1在新位置的图上也要放置测试集和训练集ax.scatter(X_train[:, 0], X_train[:, 1], cy_train, cmapcm_bright,edgecolorsk)ax.scatter(X_test[:, 0], X_test[:, 1], cy_test, cmapcm_bright,edgecolorsk, alpha0.6)# 为图设置坐标轴的最大值和最小值ax.set_xlim(array1.min(), array1.max())ax.set_ylim(array2.min(), array2.max())# 设置没有坐标轴ax.set_xticks(())ax.set_yticks(())# 只需要在第一个坐标系上有标题因此设定if ds_index0这个条件if ds_index 0:ax.set_title(Gaussian Bayes)# (array1.max() - .3, array2.min() .3)位置坐标# ({:.1f}%.format(score * 100)将其转换为百分比# horizontalalignmentright右对齐方式ax.text(array1.max() - .3, array2.min() .3, ({:.1f}%.format(score * 100)),size15, horizontalalignmentright)i 1
# 对当前图像进行调整使得子图参数自动适应图像区域避免了子图之间或子图与标签之间的重叠。
plt.tight_layout()
# 显示图片
plt.show()
其代码结果如下 从图上来看高斯贝叶斯属于比较特殊的一类分类器其分类效果在二分数据和月亮型数据上表现优秀有85以上的准确率但是环形数据不太擅长。
2.4 高斯朴素贝叶斯的拟合效果与运算速度
2.4.1 交叉验证的概念
交叉验证Cross-validation一种将数据集分割成多个小部分然后多次对模型进行训练和验证的过程。通过多次进行这个过程可以评估模型的泛化性能和稳定性。
蒙特卡罗交叉验证也称为Shuffle Split交叉验证是一种非常灵活的交叉验证策略。在这种技术中数据集被随机划分为训练集和验证集。在这种交叉认证方式中自由决定要用做训练集和验证集的百分比训练集和验证集的百分比加起来不一定是100%自由决定训练次数。
2.4.2 ShuffleSplit和learning_curve
1ShuffleSplit
引入方式
from sklearn.model_selection import ShuffleSplit
语法格式
ShuffleSplit(n_splits10, *, test_sizeNone, train_sizeNone, random_stateNone)
n_splits划分训练集、测试集的次数默认为10。test_size测试集的大小。可以是浮点数表示测试集占总样本的比例或整数表示测试集的绝对大小。如果未提供则默认为 0.1。train_size训练集的大小。可以是浮点数表示训练集占总样本的比例或整数表示训练集的绝对大小。如果未提供则默认为 1 - test_size。random_state随机种子用于控制随机打乱的过程。
例子如下
# 创建了一个ShuffleSplit对象
cv ShuffleSplit(n_splits50 # 划分训练集、测试集的次数这里是50次, test_size0.2 # 其中有20%数据作为测试集, random_state0) # 在交叉验证的时候进行的随机抽样的模式
这里例子中的蒙特卡罗交叉验证有20的数据作为测试集80作为训练集并且重复的次数是50次
2learning_curve
2.1 语法格式
引入方式
from sklearn.model_selection import learning_curve
语法格式
learning_curve(estimator, X, y, *, train_sizesNone, cvNone, scoringNone, exploit_incremental_learningFalse, n_jobsNone, pre_dispatchall, verbose0, shuffleFalse, random_stateNone, error_scoreraise, return_timesFalse)estimator用于拟合数据的模型对象。X特征数据。y目标数据。train_sizes用于生成学习曲线的训练集大小。可以是整数、浮点数或者序列。如果是整数表示用于学习曲线的每个点的训练集大小如果是浮点数表示训练集大小相对于整个数据集的比例如果是序列表示具体的训练集大小列表。cv用于交叉验证的交叉验证迭代器默认为 5 折交叉验证。scoring用于评估模型性能的指标。默认情况下使用模型的 score 方法来计算。可以指定为字符串例如 accuracy、precision 等也可以传入一个自定义的评估函数。n_jobs并行运行的作业数量。如果设置为 -1则使用所有可用的 CPU 核心。默认为 None表示不并行运行。shuffle在每次迭代前对数据进行洗牌以防止每次划分的数据不同。默认为 False。 random_state随机种子用于控制洗牌过程的随机性。error_score当模型在某些子集上无法拟合时用于替代分数的值。return_times是否返回每次拟合模型的时间。默认为 False。learning_curve 函数返回一个元组其中包含训练样本大小、训练集得分、验证集得分等信息。
例子如下
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplitdatas load_digits()
X datas.data
y datas.target
clf GaussianNB()
# 交叉验证的模式
# 这里使用的训练集数据比例是默认的5次
cv ShuffleSplit(n_splits50 # 划分训练集、测试集的次数这里是50次, test_size0.2 # 其中有20%的数据会被作为测试集, random_state0) # 交叉验证所进行的随机抽样的模式# 默认进行5次验证每次验证会划分50次训练集和测试集进行测试其中20%作为测试集
# train_sizes 表示每次分训练集和测试集建模之后训练集上的样本数量
# train_scores 训练集上的分数 test_scores 测试集上的分数
train_sizes, train_scores, test_scores learning_curve(clf # 标示分类器, X, y # 特征矩阵和标签, cvcv # 设置交叉验证的模式, n_jobs4) # 每一次运行可以使用的线程数目表示允许算法使用多少运算资源
learning_curve会进行5次建模每次建模的训练集样本如下 train_scores和test_scores返回的结果是(5,50)这是因为ShuffleSplit是蒙特卡罗交叉验证将划分测试集和训练集进行了50次相当于进行了50次训练 2,2 学习曲线常见三种情况
学习曲线能判定偏差(bias)和方差(validation)问题 第一种当训练集和测试集的误差收敛但却很高时为高偏差-----欠拟合。
如左上图所示训练集准确率与验证集准确率收敛但是两者收敛后的准确率远小于我们的期望准确率上面那条红线因此该模型属于欠拟合underfitting问题。由于欠拟合所以需要增加模型的复杂度比如增加特征、减小正则项等
第二种当训练集和测试集的误差之间有大的差距时为高方差----过拟合。
如右上图所示训练集准确率高于期望值验证集则低于期望值两者之间有很大的间距误差很大对于新的数据集模型适应性较差因此该模型属于过拟合overfitting问题。由于过拟合所以需要降低模型的复杂度比如增大样本数、减少特征数等等。
第三种一个比较理想的学习曲线图应当是低偏差、低方差即收敛且误差小。
如左下图所示训练集准确率与验证集准确率收敛于期望值则为低偏差、低方差这是比较理想的学习曲线图
2.4.3 交叉验证分析
# ————第一步导入所需要的库————
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.tree import DecisionTreeClassifier as DTC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit
from time import time
import datetime# ————第二步定义绘制学习曲线的函数————
def plot_learning_curve(estimator, title, X, y, # estimator标示使用的分类器ax, # 选择子图ylimNone, # 设置纵坐标的取值范围cvNone, # 交叉验证n_jobsNone # 设定索要使用的线程):# 使用learning_curve返回必要参数train_sizes, train_scores, test_scores learning_curve(estimator, X, y, cvcv, n_jobsn_jobs)# 设置标题ax.set_title(title)# 设置y坐标的量纲形式一样即把多个子图的y坐标设置为一样# 使用*号解包if ylim is not None:ax.set_ylim(*ylim)# 设置横纵坐标名字ax.set_xlabel(Training examples)ax.set_ylabel(Score)# 显示网格作为背景不是必须ax.grid()# 分别画训练集和测试集的学习曲线# 横坐标是train_sizes,纵坐标分别是训练分数的均值和测试分数的均值ax.plot(train_sizes, np.mean(train_scores, axis1), o-, colorr, labelTraining score) # 画训练数据集的图像ax.plot(train_sizes, np.mean(test_scores, axis1), o-, colorg, labelTest score) # 画出测试集图像# 在图上标明一个图例用于说明每条曲线的文字显示ax.legend(locbest)# 返回子图return ax# ————第三步导入数据定义循环————
# 导入数据
digits load_digits()
X, y digits.data, digits.target
# 定义标题
title [Naive Bayes,DecisionTree,SVM, RBF kernel,RandomForest,Logistic]
# 定义五个算法模型
model [GaussianNB(),DTC(),SVC(gamma0.001)
,RFC(n_estimators50),LR(C.1,solverlbfgs)]
# 定义交叉验证模式
cv ShuffleSplit(n_splits50, test_size0.2, random_state0)# ————第四步 进入循环绘制学习曲线————
# 设置画布一行五列尺寸是30×6
# fig是画布axex是子图对象
fig, axes plt.subplots(1,5,figsize(30,6))
# ind代表每次循环的索引title代表每次循环的标题estimator代表每次循环的算法模型
for ind,title_,estimator in zip(range(len(title)),title,model):# 记录当前时间times time()# 调用学习曲线函数plot_learning_curve(estimator, title_, X, y,axaxes[ind], ylim [0.7, 1.05],n_jobs4, cvcv)# 记录使用时间print({}:{}.format(title_,datetime.datetime.fromtimestamp(time()-times).strftime(%M:%S:%f)))
# 显示图像
plt.show()
查看zip(range(len(title)),title,model 代码结果如下 对结果进行如下分析
各个代码运行时间。决策树和贝叶斯不相伯仲如果你没有发现这个结果可以多运行几次最终发现贝叶斯和决策树的运行时间逐渐变得差不多)。决策树之所以能够运行非常快速是因为sklearn中的分类树在选择特征时有所“偷懒”没有计算全部特征的信息熵而是随机选择了一部分特征来进行计算因此速度快但决策树的运算效率随着样本量逐渐增大会越来越慢朴素贝叶斯可以在很少的样本上获得不错的结果可以预料随着样本量的逐渐增大贝叶斯会逐渐变得比决策树更快朴素贝叶斯计算速度远远胜过SVM随机森林这样复杂的模型逻辑回归的运行受到最大迭代次数的强烈影响和输入数据的影响逻辑回归一般在线性数据上运行都比较快但在这里是受到了稀疏矩阵的影响。综上在运算时间上朴素贝叶斯还是十分有优势的。训练集上的拟合结果。手写数字数据集是一个较为简单的数据集决策树森林SVC和逻辑回归都成功拟合了100%的准确率但贝叶斯的最高训练准确率都没有超过95%说明朴素贝叶斯的分类效果不如其他分类器贝叶斯天生学习能力比较弱随着训练样本量的逐渐增大其他模型的训练拟合都保持在100%的水平但贝叶斯的训练准确率却逐渐下降这说明样本量越大贝叶斯需要学习的东西越多对训练集的拟合程度也越来越差。过拟合问题。所有模型在样本量很少的时候都是出于过拟合状态的训练集上表现好测试集上表现糟糕但随着样本的逐渐增多过拟合问题都逐渐消失了。SVM随机森林和逻辑归决策树通过提高模型在测试集上的表现来减轻过拟合问题而朴素贝叶斯是依赖训练集上的准确率下降测试集上的准确率上升来逐渐解决过拟合问题。测试集上的拟合结果即泛化误差的大小。贝叶斯和决策树在测试集上的表现远远不如SVM随机森林和逻辑回归VM在训练数据量增大到1500个样本左右的时候测试集上的表现已经非常接近100%随机森林和逻辑回归的表现也在95%以上而决策树和朴素贝叶斯还徘徊在85%左右决策树虽然测试结果不高但是依然具有潜力因为它的过拟合现象非常严重可以通过减枝来让决策树的测试结果逼近训练结果贝叶斯的过拟合现象在训练样本达到1500左右的时候已经几乎不存在了训练集上的分数和测试集上的分数非常接近综上判断85%左右就是贝叶斯在这个数据集上的极限了如果我们进行调参决策树最后应该可以达到90%左右的预测准确率。
综上所述可以得出结论
贝叶斯速度很快但分类效果一般如果数据十分复杂或者是稀疏矩阵则使用贝叶斯
3 概率模型的评估指标
3.1 前言
混淆矩阵和精确性可以帮助我们了解贝叶斯的分类结果。然而选择贝叶斯进行分类大多数时候不是为了单单追求效果而是希望看到预测的相关概率。这种概率给出预测的可信度所以对于概率类模型我们希望能够由其他的模型评估指标来帮助我们判断模型在“概率预测”这项工作上完成得如何。
3.2 布里尔分数Brier Score
1布里尔分数的概念
概率预测的准确程度被称为“校准程度”是衡量算法预测出的概率和真实结果的差异的一种方式。一种比较常用的指标叫做布里尔分数它被计算为是概率预测相对于测试样本的均方误差表示为 其中N是样本数量是朴素贝叶斯预测出的概率是样本所对应的真实结果只能取0或1如果事件发生则为1否则为0。这个指标衡量了我们的概率距离真实标签结果的差异看起来非常像是均方误差。布里尔分数的范围是从0到1分数越高则预测结果越差劲校准程度越差因此布里尔分数越接近0越好。
注意布里尔分数可以用于任何可以使用predict_proba接口调用概率的模型
2brier_score_loss语法格式
brier_score_loss(y_true, y_prob, sample_weightNone, pos_labelNone)y_true实际的标签通常是一个包含了真实标签的数组。y_prob模型对每个样本属于正类的预测概率通常是一个二维数组每行对应一个样本每列对应一个类别的预测概率。sample_weight可选参数样本权重用于加权计算 Brier 分数。pos_label可选参数正类的标签值。默认情况下pos_label 是1。
注意新版sklearn的brier_score_loss不再支持多分类只能用于二分类
3例子
由于brier_score_loss不能用于多分类因此使用只有二分类的乳腺癌数据进行评估后续再思考如何解决多分类的问题
import pandas as pd
from sklearn.metrics import brier_score_loss
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.datasets import load_breast_cancer# 第一步---载入数据集---
datas load_breast_cancer()
X datas.data
y datas.target# 划分测试集和训练数据集
xtrain, xtest, ytrain, ytest train_test_split(X, y, test_size0.3, random_state0)# 第二步---训练模型---
# 训练高斯朴素贝叶斯模型
gnb GaussianNB().fit(xtrain, ytrain)
# 训练svc模型
# 我们将SVM模型的probability参数设置为True。这样做是为了在模型预测时可以输出样本的概率。
# 使用了probability参数后就可以使用predict_proba接口进而可以使用布里尔分数评估
svc SVC(probabilityTrue)
svc.fit(xtrain, ytrain)
prob_svc svc.predict_proba(xtest)
# 训练逻辑归模型
logi LR(C1., solverlbfgs,max_iter3000,multi_classauto).fit(xtrain,ytrain)# 第三步---每个分类器每个标签类别下的布里尔分数可视化---# 定义三种模型以及颜色
name [Bayes,Logistic,SVC]
color [red,black,orange]# 由于数据集的类别有两种有三种模型因此设定DataFrame为两行三列
df pd.DataFrame(indexrange(2),columnsname)# 通过循环记录每个类别的布里尔分数
for i in range(2):df.loc[i, name[0]] brier_score_loss(ytest, gnb.predict_proba(xtest)[:, i], pos_labeli)df.loc[i, name[1]] brier_score_loss(ytest, logi.predict_proba(xtest)[:, i], pos_labeli)df.loc[i, name[2]] brier_score_loss(ytest, svc.predict_proba(xtest)[:, i], pos_labeli)
# 输出DataFrame
print(f三种模型每个类别的布里尔分数为:\n{df})# 类别数为横坐标每种模型为纵坐标
# 分别为三种模型都画图
for i in range(df.shape[1]):plt.plot(range(2), df.iloc[:, i], ccolor[i],labelname[i])
# 添加图标标题
plt.legend(locbest)
# 展示结果
plt.show()可以看到逻辑回归的布里尔分数是最好的但是逻辑回归在迭代过程中没有收敛这里没有放出警告后续可能会思考解决这个收敛问题贝叶斯效果比SVC和逻辑回归都差但总的来说效果也不错 3.3 对数似然函数Log Loss
1对数似然函数的概念
一种常用的概率损失衡量是对数损失log_loss又叫做对数似然逻辑损失或者交叉熵损失它是多元逻辑回归以及一些拓展算法比如神经网络中使用的损失函数。它被定义为对于一个给定的概率分类器在预测概率为条件的情况下真实概率发生的可能性的负对数。由于是损失因此对数似然函数的取值越小则证明概率估计越准确模型越理想。值得注意得是对数损失只能用于评估分类型模型 对于一个样本如果样本的真实标签在{0,1}中取值并且这个样本在类别1下的概率估计为则这个样本所对应的对数损失是 注意这里的 表示以 为底的自然对数。2log_loss语法格式
log_loss(y_true, y_pred, eps1e-15, normalizeTrue, sample_weightNone, labelsNone)y_true实际的标签通常是一个包含了真实标签的数组。y_pred模型对每个样本属于每个类别的预测概率通常是一个二维数组每行对应一个样本每列对应一个类别的预测概率。eps用于防止概率值为 0 或 1 时的数值稳定性避免取对数时出现无穷大。默认值为 1e-15。normalize可选参数指定是否将计算的损失值归一化。如果设置为 True默认则返回的是每个样本的平均对数损失如果设置为 False则返回的是每个样本的总对数损失。sample_weight可选参数样本权重用于加权计算对数损失。labels可选参数用于指定类别标签。如果不提供则函数会自动识别标签。
3例子
Log Loss可以用于多分类情况因此使用手写数据集来测试当然也可以用乳腺癌数据
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.datasets import load_digits
from sklearn.metrics import log_loss
from sklearn.datasets import load_breast_cancer# 第一步---载入数据集---
datas load_digits()
X datas.data
y datas.target# 划分测试集和训练数据集
xtrain, xtest, ytrain, ytest train_test_split(X, y, test_size0.3, random_state0)# 第二步---训练模型---
# 训练高斯朴素贝叶斯模型
gnb GaussianNB().fit(xtrain, ytrain)
# 训练svc模型
# 我们将SVM模型的probability参数设置为True。这样做是为了在模型预测时可以输出样本的概率。
# 使用了probability参数后就可以使用predict_proba接口进而可以使用布里尔分数评估
svc SVC(probabilityTrue)
svc.fit(xtrain, ytrain)
prob_svc svc.predict_proba(xtest)
# 训练逻辑归模型
logi LR(C1., solverlbfgs,max_iter3000,multi_classauto).fit(xtrain,ytrain)# 第三步---求log_loss分数---# 定义三种模型以及颜色
name [Bayes,Logistic,SVC]
color [red,black,orange]# 创建DataFrame
df pd.DataFrame(index[log_loss],columnsname)# 记录每个模型的log_loss分数
df.loc[log_loss, name[0]] log_loss(ytest, gnb.predict_proba(xtest))
df.loc[log_loss, name[1]] log_loss(ytest, logi.predict_proba(xtest))
df.loc[log_loss, name[2]] log_loss(ytest, svc.predict_proba(xtest))
# 输出DataFrame
print(f三种模型的log_loss分数为:\n{df})
结果如下 无论是乳腺癌数据集还是手写数据集朴素贝叶斯的效果都是最差的。因为逻辑回归和SVC都是以最优化为目的来求解模型然后进行分类的算法。而朴素贝叶斯中却没有最优化的过程。对数似然函数直接指向模型最优化的方向甚至就是逻辑回归的损失函数本身因此在逻辑回归和SVC上表现得更好。
4什么时候使用对数似然
对数似然函数是概率类模型评估的黄金指标往往是我们评估概率类模型的优先选择。但是它也有缺点
它没有界不像布里尔分数有上限可以作为模型效果的参考它的解释性不如布里尔分数很难与非技术人员去交流对数似然存在的可靠性和必要性它在以最优化为目标的模型上明显表现更好。而且它还有一些数学上的问题比如不能接受为0或1的概率否则的话对数似然就会取到极限值考虑以e为底的自然对数在取到0或1的时候的情况 综上所述有如下规则
需求优先使用对数似然优先使用布里尔分数衡量模型要对比多个模型或者衡量模型的不同变化衡量单一模型的表现可解释性机器学习和深度学习之间的行家交流学术论文商业报告老板开会业务模型的衡量最优化指向逻辑回归SVC朴素贝叶斯数学问题概率只能无限接近于0或1无法取到0或1概率可以取到0或1比如树随机森林
贝叶斯的原理简单根本没有什么可用的参数。但是产出概率的算法有自己的调节方式就是调节概率的校准程度。校准程度越高模型对概率的预测越准确算法在做判断时就越有自信模型就会更稳定。如果我们追求模型在概率预测上必须尽量贴近真实概率那就可以使用可靠性曲线来调节概率的校准程度
3.4 可靠性曲线 reliability curve
3.4.1 基础知识
1概念
可靠性曲线reliability curve又叫做概率校准曲线probability calibration curve可靠性图reliability diagrams这是一条以预测概率为横坐标真实标签为纵坐标的曲线。我们希望预测概率和真实值越接近越好最好两者相等因此一个模型/算法的概率校准曲线越靠近对角线越好。校准曲线因此也是我们的模型评估指标之一。和布里尔分数相似概率校准曲线是对于标签的某一类来说的因此一类标签就会有一条曲线或者我们可以使用一个多类标签下的平均来表示一整个模型的概率校准曲线。但通常来说曲线用于二分类的情况最多2make_classification语法格式
sklearn.datasets.make_classification(n_samples100, n_features20, *, n_informative2, n_redundant2, n_repeated0, n_classes2, n_clusters_per_class2, weightsNone, flip_y0.01, class_sep1.0, hypercubeTrue, shift0.0, scale1.0, shuffleTrue, random_stateNone)
n_samples生成的样本数量默认值为100n_features生成的特征数量默认值为20n_informative指定分类问题中有多少个特征是有用的即与目标变量相关默认值为2n_redundant指定分类问题中有多少个特征是冗余的即与目标变量无关但与其他特征相关默认值为2n_repeated指定分类问题中有多少个特征是重复的即完全相同的特征数默认值为0n_classes指定分类问题中有多少个类别默认值为2n_clusters_per_class指定每个类别中有多少个簇默认值为2weights指定各个类别的权重默认为None即类是平衡的flip_y随机将标签翻转的概率默认为0.01class_sep指定类别之间的距离默认为1.0hypercube指定是否在超立方体中生成数据默认为Trueshift指定生成数据的移位量默认为0scale指定生成数据的缩放比例默认为1shuffle指定是否对数据进行随机洗牌默认为Truerandom_state随机种子默认为None
返回值为
X生成的样本array of shape [n_samples, n_features]y每个样本的类成员的整数标签array of shape [n_samples]
例子如下
from sklearn.datasets import make_classification as mc# 创建数据集
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)print(X.shape)
print(y.shape)
代码结果如下 3calibration_curve
sklearn.calibration.calibration_curve(y_true, y_prob, normalizeFalse, n_bins5, strategyuniform)
y_true真实标签的数组或序列。y_prob预测标签为正类的概率数组或序列。normalize可选参数默认为 False。如果为 True则将每个箱中的样本数除以总样本数使每个箱的值在 [0, 1] 范围内。n_bins可选参数默认为 5。将概率分成的箱的数量。strategy可选参数默认为 uniform。指定分箱策略可选值为 uniform 或 quantile。
返回值为
trueproba可靠性曲线的纵坐标结构为(n_bins, )是每个箱子中少数类(Y1)的占比predproba 可靠性曲线的横坐标结构为(n_bins, )是每个箱子中概率的均值
3.4.2 模型评估
1 朴素贝叶斯评估
先对朴素贝叶斯进行评估代码如下
# 可靠性曲线
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.metrics import brier_score_loss
from sklearn.model_selection import train_test_split
import pandas as pd# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 朴素贝叶斯训练集很小效果也很好因此仅用1的样本作为训练集
xtrain,xtest,ytrain,ytesttrain_test_split(X,y,test_size0.99,random_state0)# 第二步---建立模型---
gnb GaussianNB()
gnb gnb.fit(xtrain,ytrain)
# 导出分类的结果
y_pred gnb.predict(xtest)
# 导出类别为1的预测概率
y_prob gnb.predict_proba(xtest)[:,1]
# 导出精确性
acc_score gnb.score(xtest, ytest)# 第三步---绘制图像---# 利用字典创建DateFrame({列的名称:[列的值]})
# 选取一部分测试集创建DateFrame一列是真实值ytrue一列是预测概率probability
df pd.DataFrame({ytrue: ytest[:500], probability: y_prob[:500]})# 在我们的横纵表坐标上概率是由顺序的由小到大所以对数据按照预测概率进行一个排序
# 对df中的数据进行排序按照probability进行排序
df df.sort_values(byprobability)
# 排序后索引会乱要恢复索引让索引按顺序排序
df.index range(df.shape[0])# 紧接着我们就可以画图了
fig plt.figure() # 建立画布
ax1 plt.subplot() # 建立一个子图
ax1.plot([0, 1], [0, 1], k:, labelPerfectly calibrated) # 得做一条对角线来对比呀# 以df[probability]即预测概率为横坐标df[ytrue]即真实类别为纵坐标
ax1.plot(df[probability], df[ytrue], s-, label%s (%1.3f) % (Bayes, acc_score))
ax1.set_ylabel(True label)
ax1.set_xlabel(predcited probability)# 设置纵坐标范围
ax1.set_ylim([-0.05, 1.05])
ax1.legend()
plt.show()
代码结果如下 按照预测概率的顺序进行排序的而预测概率从0开始到1的过程中真实取值不断在0和1之间变化而我们是绘制折线图因此无数个纵坐标分布在0和1的被链接起来了所以看起来如此混乱。
换成散点图后就可以看得很清晰了 所谓可靠性曲线的横纵坐标横坐标是预测概率而纵坐标是真实值真实值应该是概率而不是标签事实上真实概率是不可能获取的因此一个简单的做法是将数据进行分箱然后规定每个箱子中真实的少数类所占的比例为这个箱上的真实概率trueproba这个箱子中预测概率的均值为这个箱子的预测概率predproba然后以trueproba为纵坐标predproba为横坐标来绘制我们的可靠性曲线。分箱之后样本点的特征被聚合到了一起曲线可以变得单调且平滑 可以通过绘制可靠性曲线的类calibration_curve来实现
# 可靠性曲线
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
import pandas as pd
from sklearn.calibration import calibration_curve# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 朴素贝叶斯训练集很小效果也很好因此仅用1的样本作为训练集
xtrain,xtest,ytrain,ytesttrain_test_split(X,y,test_size0.99,random_state0)# 第二步---建立模型---
gnb GaussianNB()
gnb gnb.fit(xtrain,ytrain)
# 导出分类的结果
y_pred gnb.predict(xtest)
# 导出类别为1的预测概率
y_prob gnb.predict_proba(xtest)[:,1]
# 导出精确性
acc_score gnb.score(xtest, ytest)# 分成10箱ytest代表是真实标签y_prob标示返回的概率
trueproba, predproba calibration_curve(ytest, y_prob, n_bins10)# 第三步---绘制图像---# 利用字典创建DateFrame({列的名称:[列的值]})
# 选取一部分测试集创建DateFrame一列是真实值ytrue一列是预测概率probability
df pd.DataFrame({ytrue: ytest[:500], probability: y_prob[:500]})# 在我们的横纵表坐标上概率是由顺序的由小到大所以对数据按照预测概率进行一个排序
# 对df中的数据进行排序按照probability进行排序
df df.sort_values(byprobability)
# 排序后索引会乱要恢复索引让索引按顺序排序
df.index range(df.shape[0])# 紧接着我们就可以画图了
fig plt.figure() # 建立画布
ax1 plt.subplot() # 建立一个子图
ax1.plot([0, 1], [0, 1], k:, labelPerfectly calibrated) # 得做一条对角线来对比呀# 以df[probability]即预测概率为横坐标df[ytrue]即真实类别为纵坐标
ax1.plot(predproba, trueproba, s-, label%s (%1.3f) % (Bayes, acc_score))
ax1.set_ylabel(True label)
ax1.set_xlabel(predcited probability)# 设置纵坐标范围
ax1.set_ylim([-0.05, 1.05])
ax1.legend()
plt.show()
结果如下 那么在不同箱数的情况下会有什么变化呢把箱数分别设置为3,10,100查看结果代码如下
# 可靠性曲线
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
import pandas as pd
from sklearn.calibration import calibration_curve# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 朴素贝叶斯训练集很小效果也很好因此仅用1的样本作为训练集
xtrain,xtest,ytrain,ytesttrain_test_split(X,y,test_size0.99,random_state0)# 第二步---建立模型---
gnb GaussianNB()
gnb gnb.fit(xtrain,ytrain)
# 导出分类的结果
y_pred gnb.predict(xtest)
# 导出类别为1的预测概率
y_prob gnb.predict_proba(xtest)[:,1]
# 导出精确性
acc_score gnb.score(xtest, ytest)# 第三步---绘制图像---# 利用字典创建DateFrame({列的名称:[列的值]})
# 选取一部分测试集创建DateFrame一列是真实值ytrue一列是预测概率probability
df pd.DataFrame({ytrue: ytest[:500], probability: y_prob[:500]})# 在我们的横纵表坐标上概率是由顺序的由小到大所以对数据按照预测概率进行一个排序
# 对df中的数据进行排序按照probability进行排序
df df.sort_values(byprobability)
# 排序后索引会乱要恢复索引让索引按顺序排序
df.index range(df.shape[0])# 紧接着我们就可以画图了
# 我们绘制出的图像越接近yx这条直线越好
fig, axes plt.subplots(1,3,figsize(18,4))
for ind,i in enumerate([3,10,100]):ax axes[ind]# 画yx直线ax.plot([0, 1], [0, 1], k:, labelPerfectly calibrated)# 分箱后的真实值和预测值trueproba, predproba calibration_curve(ytest, y_prob,n_binsi)ax.plot(predproba, trueproba,s-,labeln_bins {}.format(i))ax.set_ylabel(True probability for class 1)ax.set_xlabel(Mean predcited probability)ax.set_ylim([-0.05, 1.05])ax.legend()
plt.show()
结果如下 从上述图可以得出以下结论
n_bins越大箱子越多概率校准曲线就越精确但是太过精确的曲线不够平滑即剧烈震荡无法和我们希望的完美概率密度曲线相比较。n_bins越小箱子越少概率校准曲线就越粗糙无法反应真实情况虽然靠近完美概率密度曲线但是无法真实地展现模型概率预测的结果。需要取适中的箱子个数让概率校准曲线是一条相对平滑又可以反应出模型对概率预测的趋势的曲线。通常来说建议先试试看箱子数等于10的情况。箱子的数目越大所需要的样本量也越多否则曲线就会太过精确
2 其它模型
建立其它模型比较一下效果分别为逻辑回归SVC贝叶斯。代码如下
# 可靠性曲线
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.calibration import calibration_curve
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.metrics import brier_score_loss# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 朴素贝叶斯训练集很小效果也很好因此仅用1的样本作为训练集
xtrain,xtest,ytrain,ytesttrain_test_split(X,y,test_size0.99,random_state0)# 第二步---建立模型---# 训练贝叶斯模型
gnb GaussianNB()
# 训练svc模型
svc SVC(probabilityTrue)
# 训练逻辑归模型
logi LR(C1., solverlbfgs,max_iter3000,multi_classauto).fit(xtrain,ytrain)# 第三步---绘制图像---name [GaussianBayes,Logistic,SVC]
# 紧接着我们就可以画图了
fig, ax1 plt.subplots(figsize(8,6))
ax1.plot([0, 1], [0, 1], k:, labelPerfectly calibrated)for clf, name_ in zip([gnb,logi,svc],name):# 训练模型clf.fit(xtrain,ytrain)# 预测标签y_pred clf.predict(xtest)# 预测概率prob_pos clf.predict_proba(xtest)[:,1]# 返回布里尔分数clf_score brier_score_loss(ytest, prob_pos, pos_labely.max())# 分箱数为10trueproba, predproba calibration_curve(ytest, prob_pos,n_bins10)ax1.plot(predproba, trueproba,s-,label%s (%1.3f) % (name_, clf_score))
ax1.set_ylabel(True probability for class 1)
ax1.set_xlabel(Mean predcited probability)
ax1.set_ylim([-0.05, 1.05])
ax1.legend()
ax1.set_title(Calibration plots (reliability curve))
plt.show()
代码结果如下 从图中可以看出
相对来说高斯朴素贝叶斯的结果比较糟糕高斯朴素贝叶斯呈现和Sigmoid函数相反的形状。对于贝叶斯如果概率校准曲线呈现sigmoid函数的镜像的情况则说明数据集中的特征不是相互条件独立的。贝叶斯原理中的”朴素“原则特征相互条件独立原则被违反了我们设定了10个冗余特征这些特征就是噪音他们之间不可能完全独立因此贝叶斯的表现不够好。
3.5 预测概率的直方图
1基础知识
可以通过绘制直方图来查看模型的预测概率的分布。直方图是以样本的预测概率分箱后的结果为横坐标每个箱中的样本数量为纵坐标的一个图像。
注意这里的分箱和在可靠性曲线中的分箱不同这里的分箱是将预测概率均匀分为一个个的区间
2matplotlib.pyplot.hist参数详解
ax.hist(x, binsNone, rangeNone, densityFalse, weightsNone,cumulativeFalse, bottomNone, histtypebar, alignmid, orientationvertical, rwidthNone, logFalse, colorNone,labelNone, stackedFalse, *, dataNone, **kwargs)
x: 绘制直方图所需的一维数组或序列。bins: 直方图的条形数目默认值为 10。range: 直方图的取值范围默认值为 None即 (min(x), max(x))。density: 布尔值默认为False。若为True则绘制频率分布直方图若为False则绘制频数分布直方图。weights: 每个数据点的权重默认值为 None。cumulative: 布尔值默认为False。若为True当density为False时直方图显示累计频数当density为True时直方图显示累计频率。bottom: 数值或数组序列默认为None。若为数值则直方图的柱子相对于y0向上/向下偏移相同的量。若为数组序列则根据数组元素取值每根柱子偏移相应的量。histtype: 直方图类型可选值为 bar, barstacked, step, stepfilled。bar是传统的条形直方图barstacked是堆叠的条形直方图step是未填充的阶梯直方图只有外边框stepfilled是有填充的阶梯直方图。align: 直方图条形的对齐方式可选值为 left, mid, right。orientation: 直方图的方向可选值为 horizontal, vertical。horizontal表示柱子水平排列 vertical表示柱子垂直排列。rwidth: 直方图条形宽度浮点数或 None默认为 None。log: 是否绘制对数刻度的直方图默认值为 False。color: 直方图颜色。label: 直方图标签。stacked: 布尔值默认为False。当图中有多个数据集时使用该参数若取值为True则输出数据集累计堆叠的结果若取值为False则多个数据集柱子并排排列。
3例子
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.calibration import calibration_curve
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.metrics import brier_score_loss# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 朴素贝叶斯训练集很小效果也很好因此仅用1的样本作为训练集
xtrain,xtest,ytrain,ytesttrain_test_split(X,y,test_size0.99,random_state0)# 第二步---建立模型---# 训练贝叶斯模型
gnb GaussianNB()
# 训练svc模型
svc SVC(probabilityTrue)
# 训练逻辑归模型
logi LR(C1., solverlbfgs,max_iter3000,multi_classauto).fit(xtrain,ytrain)# 第三步---绘制图像---name [GaussianBayes,Logistic,SVC]
# 紧接着我们就可以画图了
fig, ax1 plt.subplots(figsize(8,6))for clf, name_ in zip([gnb,logi,svc],name):# 训练模型clf.fit(xtrain,ytrain)# 预测标签y_pred clf.predict(xtest)# 预测概率prob_pos clf.predict_proba(xtest)[:,1]ax1.hist(prob_pos, bins10, labelname_, histtypestep # 设置直方图为透明, lw2 # 设置直方图每个柱子描边的粗细)# 纵坐标为样本数
ax1.set_ylabel(Distribution of probability)
# 样本预测概率的均值
ax1.set_xlabel(Mean predicted probability)
# 设定x取值
ax1.set_xlim([-0.05, 1.05])
# 限制x轴刻度
ax1.set_xticks([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1])
ax1.legend(loc9)
plt.show()
结果如下 根据结果分析如下
逻辑回归。看橙色线0到0.1之间有很多的样本数这可以说明很大可能这些样本是类别00.9-1之间也有很多的样本数这可以说明很大可能这些样本是类别1。几乎90%以上的样本都在0和1的附近这些样本可以充分预测其类别是置信度最高的算法高斯贝叶斯。看蓝色线同理高斯贝叶斯的概率分布是两边非常高中间非常低几乎90%以上的样本都在0和1的附近是置信度最高的算法。但实际上高斯贝叶斯算法太多样本数在0和1的附近置信度太高了可能有一些类别1的样本在0附近类别0的样本在1附近这也是它可靠性曲线表现不好的原因。支持向量机当使用了predict_proba接口后跟上述算法同理是置信度最高的算法综上当聚集在0和1附近的样本数过多置信度过高其效果也不一定好如果有一个算法处于中间的样本数很多即中间高两边低则这些样本的类别不确定性很大算法需要改进
注意使用的预测概率是类别为1情况下的预测概率
3.6 校准可靠性曲线
3.6.1 基础知识
1基本介绍
等近似回归有两种回归可以使用一种是基于Platt的Sigmoid模型的参数校准方法一种是基于等渗回归isotoniccalibration的非参数的校准方法。概率校准应该发生在测试集上必须是模型未曾见过的数据。在数学上使用这两种方式来对概率进行校准的原理十分复杂而此过程我们在sklearn中无法进行干涉大家不必过于去深究。
2CalibratedClassifierCV语法格式
class sklearn.calibration.CalibratedClassifierCV(base_estimatorNone, methodsigmoid, cvNone)base_estimator: 使用的基本分类器默认为 None。可以是任何有 predict_proba() 接口或decision_function接口的分类器。method: 校准概率的方法。可选值为 sigmoid 和 isotonic默认sigmoid。输入sigmoid使用基于Platt的Sigmoid模型来进行校准输入isotonic使用等渗回归来进行校准。样本数过少小于等于1000时建议使用sigmoids如果使用等渗回归会过拟合cv: 用于交叉验证的折数。默认为 None表示使用默认的 5 折交叉验证。可输入整数代表指定折数可输入已经使用其他类建好的交叉验证模式或生成器cv可输入可迭代的已经分割完毕的测试集和训练集索引数组输入prefit则假设已经在分类器上拟合完毕数据。在这种模式下使用者必须手动确定用来拟合分类器的数据与即将被校准的数据没有交集
CalibratedClassifierCV 的主要方法包括
fit(X, y, sample_weightNone): 训练模型并对概率估计进行校准。其中X 和 y 分别为训练集的特征和标签。predict(X): 对测试集进行预测并返回预测结果的类别。predict_proba(X): 对测试集进行预测并返回每个类别的概率估计。predict_log_proba(X): 对测试集进行预测并返回每个类别的对数概率估计。get_params(deepTrue): 获取模型的超参数。set_params(**params): 设置模型的超参数。
3.6.2 分析贝叶斯模型
这里分别使用了两种校准方式分别为sigmoid 和 isotonic
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.calibration import calibration_curve
from sklearn.linear_model import LogisticRegression as LR
from sklearn.metrics import brier_score_loss
from sklearn.calibration import CalibratedClassifierCV# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 朴素贝叶斯训练集很小效果也很好因此仅用1的样本作为训练集
xtrain,xtest,ytrain,ytest train_test_split(X,y,test_size0.99,random_state0)# 第二步---建立模型---# 定义贝叶斯模型
gnb GaussianNB()
# 所有模型放在models列表中定义了两种校准方式
models [gnb, LR(C1., solverlbfgs, max_iter3000, multi_classauto)# 定义两种校准方式, CalibratedClassifierCV(gnb, cv2, methodisotonic), CalibratedClassifierCV(gnb, cv2, methodsigmoid)]# 第三步---定义画图函数---def plot_calib(models, name, Xtrain, Xtest, Ytrain, Ytest, n_bins10):ax1.plot([0, 1], [0, 1], k:, labelPerfectly calibrated) # 画出yx的直线for clf, name_ in zip(models, name):clf.fit(xtrain, ytrain)y_pred clf.predict(Xtest)prob_pos clf.predict_proba(Xtest)[:, 1]# 返回布里尔分数clf_score brier_score_loss(Ytest, prob_pos, pos_labely.max())# 可靠性曲线trueproba, predproba calibration_curve(Ytest, prob_pos, n_binsn_bins)ax1.plot(predproba, trueproba, s-, label%s (%1.3f) % (name_, clf_score))ax2.hist(prob_pos, range(0, 1), binsn_bins, labelname_, histtypestep, lw2)# 第四步---绘制图像---
name [GaussianBayes, Logistic, Bayesisotonic, Bayessigmoid]# 建立画布以及子图
fig, (ax1, ax2) plt.subplots(1, 2, figsize(20, 6))
# 调用画图函数
plot_calib(models, name, xtrain, xtest, ytrain, ytest)
# 子图2的一些配置
ax2.set_ylabel(Distribution of probability)
ax2.set_xlabel(Mean predicted probability)
ax2.set_xlim([-0.05, 1.05])
ax2.legend(loc9)
ax2.set_title(Distribution of probablity)
# 子图1的一些配置
ax1.set_ylabel(True probability for class 1)
ax1.set_xlabel(Mean predcited probability)
ax1.set_ylim([-0.05, 1.05])
ax1.legend()
ax1.set_title(Calibration plots(reliability curve))plt.show()# 第四步---输出准确率和布里尔分数---
print(f贝叶斯的准确率为:{gnb.score(xtest,ytest)},f布里尔分数为{brier_score_loss(ytest,gnb.predict_proba(xtest)[:,1],pos_label 1)})
gnbisotonic CalibratedClassifierCV(gnb, cv2, methodisotonic).fit(xtrain,ytrain)
print(f使用isotonic后的贝叶斯的准确率为:{gnbisotonic.score(xtest,ytest)},f布里尔分数为{brier_score_loss(ytest,gnbisotonic.predict_proba(xtest)[:,1],pos_label 1)})
结果如下 对于曲线图和直方图分析结果如下
从曲线图来看Isotonic等渗校正大大改善了曲线的形状几乎让贝叶斯的效果与逻辑回归持平Sigmoid校准的方式也对曲线进行了稍稍的改善不过效果不明显从直方图来看Isotonic校正让高斯朴素贝叶斯的效果接近逻辑回归而Sigmoid校正后的结果依然和原本的高斯朴素贝叶斯更相近综上所述当数据的特征之间不是相互条件独立的时候使用Isotonic方式来校准概率曲线可以得到不错的结果让模型在预测上更加谦虚
对于贝叶斯模型和准确率和布尔分数的分析
校准概率后布里尔分数明显变小了但整体的准确率却略有下降这证明算法在校准之后尽管对概率的预测更准确了但模型的判断力略有降低这是因为在朴素贝叶斯中有各种各样的假设除了“朴素”假设还有我们对概率分布的假设比如说高斯在这些假设下这种概率估计其实不是那么准确和严肃。通过校准让模型的预测概率更贴近于真实概率本质是在统计学上让算法更加贴近我们对整体样本状况的估计这样的一种校准在一组数据集上可能表现出让准确率上升也可能表现出让准确率下降这取决于测试集有多贴近估计的真实样本的面貌深层的可能原因是概率校准过程中的数学细节如何影响了我们的校准类calibration_curve中是如何分箱如何通过真实标签和预测值来生成校准曲线使用的横纵坐标这些过程中也可能有着让布里尔分数和准确率向两个方向移动的过程 当两者相悖的时候以准确率为标准但概率类模型几乎没有参数可以调整概率校准曲线非常好的针对概率提升模型的方法所以仍然可以考虑使用这些方法
3.6.3 SVC校准效果
使用SVCpredict_proba接口来进行处理代码如下
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification as mc
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.calibration import calibration_curve
from sklearn.linear_model import LogisticRegression as LR
from sklearn.svm import SVC
from sklearn.metrics import brier_score_loss
from sklearn.calibration import CalibratedClassifierCV# 第一步---创建数据集---
X, y mc(n_samples100000,n_features20 #总共20个特征,n_classes2 #标签为2分类,n_informative2 #其中两个代表较多信息即比较重要的特征,n_redundant10 #10个都是冗余特征,random_state42)# 仅用45的样本作为训练集
xtrain,xtest,ytrain,ytest train_test_split(X,y,test_size0.55,random_state0)# 第二步---建立模型---# 定义SVC
svc SVC(kernel linear,gamma1,probabilityTrue)
# 所有模型放在models列表中定义了两种校准方式
models [svc,LR(C1., solverlbfgs,max_iter3000,multi_classauto)#依然定义两种校准方式,CalibratedClassifierCV(svc, cv2, methodisotonic),CalibratedClassifierCV(svc, cv2, methodsigmoid)]# 第三步---定义画图函数---def plot_calib(models, name, Xtrain, Xtest, Ytrain, Ytest, n_bins10):ax1.plot([0, 1], [0, 1], k:, labelPerfectly calibrated) # 画出yx的直线for clf, name_ in zip(models, name):clf.fit(xtrain, ytrain)y_pred clf.predict(Xtest)prob_pos clf.predict_proba(Xtest)[:, 1]# 返回布里尔分数clf_score brier_score_loss(Ytest, prob_pos, pos_labely.max())# 可靠性曲线trueproba, predproba calibration_curve(Ytest, prob_pos, n_binsn_bins)ax1.plot(predproba, trueproba, s-, label%s (%1.3f) % (name_, clf_score))ax2.hist(prob_pos, range(0, 1), binsn_bins, labelname_, histtypestep, lw2)# 第四步---绘制图像---
name [SVC,Logistic,SVCisotonic,SVCsigmoid]# 建立画布以及子图
fig, (ax1, ax2) plt.subplots(1, 2, figsize(20, 6))
# 调用画图函数
plot_calib(models, name, xtrain, xtest, ytrain, ytest)
# 子图2的一些配置
ax2.set_ylabel(Distribution of probability)
ax2.set_xlabel(Mean predicted probability)
ax2.set_xlim([-0.05, 1.05])
ax2.legend(loc9)
ax2.set_title(Distribution of probablity)
# 子图1的一些配置
ax1.set_ylabel(True probability for class 1)
ax1.set_xlabel(Mean predcited probability)
ax1.set_ylim([-0.05, 1.05])
ax1.legend()
ax1.set_title(Calibration plots(reliability curve))plt.show()当使用45的样本作为训练集时效果如下 4 其它贝叶斯
4.1 多项式朴素贝叶斯MultinomialNB
1 如何判定数据符合多项式朴素贝叶斯
根据多项分布的概念以词袋模型为例在文本分类中有如下假设
不考虑文本中单词之间的次序即认为这两个文本‘ Love and Peace’和‘ Peace and Love’最后建模出来对应于同一个特征向量。不考虑文本单词之间的次序会导致文本语义丢失。在类别为Yc的文本中每个单词的出现是相互独立。即在类别为Yc的文本中每次随机试验为随机从词表中抽取一个单词进行n次独立重复试验。
第2个假设只有满足了才保证了文本的特征随机向量满足多项式分布即给定类别Yc的文本满足 即满足了上述要求可用多项式朴素贝叶斯推导过程里的方法求条件概率 一般使用词频法和TF-IDF表示法详情见词袋模型
2 MultinomialNB语法格式
class sklearn.naive_bayes.MultinomialNB(*, alpha1.0, fit_priorTrue, class_priorNone)
参数说明
参数说明alphafloat, default1.0 附加的(Laplace/Lidstone)平滑参数(0表示不平滑)fit_priorbool, defaultTrue 是否学习类别先验概率。如果为False将使用统一的先验。class_priorarray-like of shape (n_classes,), defaultNone 类别的先验概率。一经指定先验概率不能随着数据而调整。
属性说明
属性说明class_count_ndarray of shape (n_classes,) 拟合期间每个类别遇到的样本数。此值由提供的样本权重加权。class_log_prior_ndarray of shape (n_classes, ) 每个类别的经验对数概率平滑。classes_ndarray of shape (n_classes,) 分类器已知的类别标签coef_ndarray of shape (n_classes, n_features) 用于将MultinomialNB解释为线性模型的镜像feature_log_prob_。feature_count_ndarray of shape (n_classes, n_features) 拟合期间每个(类别特征)遇到的样本数。此值由提供的样本权重加权。feature_log_prob_ndarray of shape (n_classes, n_features) 给定一类特征的经验对数概率P(xi|y)intercept_ndarray of shape (n_classes, ) 用于将MultinomialNB解释为线性模型的镜像class_log_prior_。n_features_int 每个样本的特征数量。
方法说明
方法说明fit(X, y[, sample_weight])根据Xy拟合朴素贝叶斯分类器get_params([deep])获取这个估计器的参数partial_fit(X, y[, classes, sample_weight])对一批样本进行增量拟合predict(X)对测试向量X进行分类。predict_log_proba(X)返回针对测试向量X的对数概率估计predict_proba(X)返回针对测试向量X的概率估计score(X, y[, sample_weight])返回给定测试数据和标签上的平均准确率。set_params(**params)为这个估计器设置参数
对X矩阵和y矩阵的要求如下
参数说明X{array-like, sparse matrix} of shape (n_samples, n_features) 用于训练的向量其中n_samples是样本数量n_features是特征数量。yarray-like of shape (n_samples,) 目标值。
3 代码实现
1 基础知识
1make_blobs语法格式
sklearn.datasets.make_blobs(n_samples100, n_features2, centers3, cluster_std1.0, center_box(-10.0, 10.0), shuffleTrue, random_stateNone)
n_samples生成的样本总数默认为100。n_features每个样本的特征数默认为2。centers要生成的聚类中心数量或者中心坐标默认为3。cluster_std每个聚类的标准差默认为1.0。center_box生成的聚类中心的范围默认为(-10.0, 10.0)。shuffle是否打乱数据顺序默认为True。random_state随机数种子默认为None。
2KBinsDiscretizer语法格式
sklearn.preprocessing.KBinsDiscretizer(n_bins5, encodeonehot, strategyuniform)参数含义和输入n_bins每个特征要分的箱子数量默认为5可以是单个整数或者数组形式对每个特征分别指定encode 编码方式默认为onehot独热编码。可选值包括 onehot做哑变量返回一个稀疏矩阵每一列是一个特征的一个类别含有该类别的样本为1否则为0 ordinal每个特征的每个箱都被编码为一个整数返回每一列是一个特征每个特征下有不同整数编码的箱的矩阵 onehot-dense做哑变量返回密集矩阵 strategy 分箱策略默认为quantile。可选值包括 uniform等宽分箱即每个特征中每个箱子的最大值之间的差为(特征.max()-特征.min())/(n_bins) quantile等位分箱即每个特征中每个箱子的样本数量相同 kmeans聚类分箱每个箱子的值到最近的一维k均值聚类的簇心的距离都相同
3MinMaxScaler语法格式
MinMaxScaler(feature_range(0, 1), copyTrue)feature_range要缩放特征的范围默认为(0, 1)copy是否在转换时复制输入数据默认为True
常用方法有
创建 MinMaxScaler 对象
scaler MinMaxScaler(feature_range(0, 1))fit(X, yNone)计算训练数据 X 的最小值和最大值用于后续的数据缩放
scaler.fit(X)transform(X)根据之前计算的最小值和最大值来缩放数据 X
X_scaled scaler.transform(X)fit_transform(X, yNone)相当于先调用 fit 方法然后再调用 transform 方法
X_scaled scaler.fit_transform(X)inverse_transform(X)执行反向缩放将缩放后的数据转换回原始范围
X_original scaler.inverse_transform(X_scaled)2 连续型数据处理
sklearn中的多项式分布也可以处理连续型变量但实际上想要处理连续型 变量应当使用高斯朴素贝叶斯
# 导入库
from sklearn.preprocessing import MinMaxScaler
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.metrics import brier_score_loss
import numpy as np# **********第一步建立数据集**********
class_1 500
class_2 500 # 两个类分别设置500个样本
centers [[0, 0], [2, 2]] # 设置数据集的中心
clusters_std [0.5, 0.5] # 设置两个类别的均值和方差# 使用make_blobs生成样本y的类别只有0和1
X, y make_blobs(n_samples[class_1, class_2], centerscenters, cluster_stdclusters_std, random_state0, shuffleFalse)# 划分数据集测试集
xtrain, xtest, ytrain, ytest train_test_split(X, y, random_state0, test_size0.3)# **********第二步归一化确保矩阵不带有负数**********
mms MinMaxScaler().fit(xtrain)
xtrain_ mms.transform(xtrain)
xtest_ mms.transform(xtest)# **********第三步建立多项式朴素贝叶斯分类器**********
# 训练的时候使用归一化之后的特征矩阵
mnb MultinomialNB().fit(xtrain_, ytrain)# 获取每一个特征的先验概率
# 返回每一个标签类对应的先验概率
print(f对数先验概率矩阵为\n{mnb.class_log_prior_})
# 使用np.exp求出真正的概率因为对数是以e为底
print(f先验概率矩阵为\n{np.exp(mnb.class_log_prior_)}\n)# 返回每一个固定类别标签下的每一个特征的对数概率log(p(xi|y))
# 矩阵形状是2*2,因为有2个特征2个类别
print(f对数条件概率矩阵为\n{mnb.feature_log_prob_})
# 使用np.exp求出真正的概率因为对数是以e为底
print(f条件概率矩阵为\n{np.exp(mnb.feature_log_prob_)}\n)# 在fit时每一个标签类别下包含的样本数
# 当fit时候接口中sample_weight被设置的时候该接口返回的值也会受到加权的影响
print(f0类和1类的样本数分别为\n{mnb.class_count_}\n)# 返回预测结果
print(f预测结果为\n{mnb.predict(xtest_)}\n)# 返回每一个样本在每一个标签下面的取值概率
print(f标签的取值概率矩阵为\n{mnb.predict_proba(xtest_)}\n)# 返回我们的准确度
print(f准确度为{mnb.score(xtest_, ytest)}\n)# 返回我们的布里尔分数
print(f布里尔分数为{brier_score_loss(ytest, mnb.predict_proba(xtest_)[:, 1], pos_label1)})
结果如图所示有些矩阵过大只截取一部分 由准确度和布里尔分数可知多项式朴素贝叶斯处理连续型数据准确率不高因此考虑使用分箱法来将连续型数据转成分类型数据
2 分类型数据
使用KBinsDiscretizer进行onehot编码方式分箱后代码如下
# 导入库
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.metrics import brier_score_loss
import numpy as np# **********第一步建立数据集**********
class_1 500
class_2 500 # 两个类分别设置500个样本
centers [[0, 0], [2, 2]] # 设置数据集的中心
clusters_std [0.5, 0.5] # 设置两个类别的均值和方差# 使用make_blobs生成样本y的类别只有0和1
X, y make_blobs(n_samples[class_1, class_2], centerscenters, cluster_stdclusters_std, random_state0, shuffleFalse)# 划分数据集测试集
xtrain, xtest, ytrain, ytest train_test_split(X, y, random_state0, test_size0.3)# **********第二步数据转换**********
# 把Xtiain转换成分类型数据
# 注意我们的Xtrain没有经过归一化因为做哑变量之后自然所有的数据就不会有负数了
# 在这里2个特征中每个特征分了十个箱相当于2个特征裂变成20个特征
kbs KBinsDiscretizer(n_bins10, encodeonehot).fit(xtrain)
xtrain_ kbs.transform(xtrain)
xtest_ kbs.transform(xtest)# **********第三步建立多项式朴素贝叶斯分类器**********
# 训练的时候使用归一化之后的特征矩阵
mnb MultinomialNB().fit(xtrain_, ytrain)# 获取每一个特征的先验概率
# 返回每一个标签类对应的先验概率
print(f对数先验概率矩阵为\n{mnb.class_log_prior_})
# 使用np.exp求出真正的概率因为对数是以e为底
print(f先验概率矩阵为\n{np.exp(mnb.class_log_prior_)}\n)# 返回每一个固定类别标签下的每一个特征的对数概率log(p(xi|y))
# 矩阵形状是2*2,因为有2个特征2个类别
print(f对数条件概率矩阵为\n{mnb.feature_log_prob_})
# 使用np.exp求出真正的概率因为对数是以e为底
print(f条件概率矩阵为\n{np.exp(mnb.feature_log_prob_)}\n)# 在fit时每一个标签类别下包含的样本数
# 当fit时候接口中sample_weight被设置的时候该接口返回的值也会受到加权的影响
print(f0类和1类的样本数分别为\n{mnb.class_count_}\n)# 返回预测结果
print(f预测结果为\n{mnb.predict(xtest_)}\n)# 返回每一个样本在每一个标签下面的取值概率
print(f标签的取值概率矩阵为\n{mnb.predict_proba(xtest_)}\n)# 返回我们的准确度
print(f准确度为{mnb.score(xtest_, ytest)}\n)# 返回我们的布里尔分数
print(f布里尔分数为{brier_score_loss(ytest, mnb.predict_proba(xtest_)[:, 1], pos_label1)})
结果如下 可以看到性能大大提升 4.2 伯努利贝叶斯
1 BernoulliNB语法格式
多元伯努利分布的特点是数据集中可以存在多个特征但每个特征都是二分类的可以以布尔变量表示也可以表示为{01}或者{-11}等任意二分类组合。因此这个类要求将样本转换为二分类特征向量如果数据不是二分类的可以使用类中专门用来二值化的参数binarize来改变数据。
class sklearn.naive_bayes.BernoulliNB(*, alpha1.0, binarize0.0, fit_priorTrue, class_priorNone)
参数说明
参数说明alphafloat, default1.0 附加的平滑参数(Laplace/Lidstone)0是不平滑binarizefloat or None, default0.0 用于将样本特征二值化映射为布尔值的阈值例如小于该阈值设为0大于该阈值设为1。如果为None则假定输入已经由二分类向量组成。fit_priorbool, defaultTrue 是否学习类别先验概率。如果为False将使用统一的先验。class_priorarray-like of shape (n_classes,), defaultNone 类别的先验概率。一经指定先验概率不能随着数据而调整。
属性说明
属性说明class_count_ndarray of shape (n_classes) 拟合期间每个类别遇到的样本数。此值由提供的样本权重加权。class_log_prior_ndarray of shape (n_classes) 每个类别的对数概率平滑。classes_ndarray of shape (n_classes,) 分类器已知的类别标签feature_count_ndarray of shape (n_classes, n_features) 拟合期间每个类别特征遇到的样本数。此值由提供的样品权重加权。feature_log_prob_ndarray of shape (n_classes, n_features) 给定一类P(xi|y)的特征的经验对数概率。n_features_int 每个样本的特征数量。
常用方法如下
方法说明fit(X, y[, sample_weight])根据Xy拟合朴素贝叶斯分类器get_params([deep])获取这个估计器的参数partial_fit(X, y[, classes, sample_weight])对一批样本进行增量拟合predict(X)对测试向量X进行分类。predict_log_proba(X)返回针对测试向量X的对数概率估计predict_proba(X)返回针对测试向量X的概率估计score(X, y[, sample_weight])返回给定测试数据和标签上的平均准确率。set_params(**params)为这个估计器设置参数
对X矩阵和y矩阵的要求如下
参数说明X{array-like, sparse matrix} of shape (n_samples, n_features) 用于训练的向量其中n_samples是样本数量n_features是特征数量。yarray-like of shape (n_samples,) 目标值。
2 代码例子
仍然使用多项式朴素贝叶斯的数据集
# 导入库
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.metrics import brier_score_loss
from sklearn.preprocessing import MinMaxScaler
from sklearn.naive_bayes import BernoulliNB# **********第一步建立数据集**********
class_1 500
class_2 500 # 两个类分别设置500个样本
centers [[0, 0], [2, 2]] # 设置数据集的中心
clusters_std [0.5, 0.5] # 设置两个类别的均值和方差# 使用make_blobs生成样本y的类别只有0和1
X, y make_blobs(n_samples[class_1, class_2], centerscenters, cluster_stdclusters_std, random_state0, shuffleFalse)# 划分数据集测试集
Xtrain, Xtest, Ytrain, Ytest train_test_split(X, y, random_state0, test_size0.3)# **********第二步数据转换**********
# 普通来说我们应该使用二值化的类sklearn.preprocessing.Binarizer来将特征一个个二值化
# 然而这样效率过低因此我们选择归一化之后直接设置一个阈值
mms MinMaxScaler().fit(Xtrain)
Xtrain_ mms.transform(Xtrain)
Xtest_ mms.transform(Xtest)# **********第三步建立伯努利朴素贝叶斯分类器**********
# 不设置二值化
bnl_ BernoulliNB().fit(Xtrain_, Ytrain)
print(f不设置二值化时准确度为{bnl_.score(Xtest_,Ytest)})
print(f不设置二值化时布里尔分数为{brier_score_loss(Ytest,bnl_.predict_proba(Xtest_)[:,1],pos_label1)})# 设置二值化阈值为0.5
bnl BernoulliNB(binarize0.5).fit(Xtrain_, Ytrain)
print(f设置二值化时准确度为{bnl.score(Xtest_,Ytest)})
print(f设置二值化时布里尔分数为{brier_score_loss(Ytest,bnl.predict_proba(Xtest_)[:,1],pos_label1)})代码结果如下
通过代码结果可知二值化时伯努利朴素贝叶斯拥有非常高的准确度 4.3 类别贝叶斯CategoricalNB
1 CategoricalNB语法格式
class sklearn.naive_bayes.CategoricalNB(*, alpha1.0, fit_priorTrue, class_priorNone)参数说明
参数 说明 alphafloat, default1.0 附加的平滑参数(Laplace/Lidstone)0是不平滑fit_priorbool, defaultTrue 是否学习类别先验概率。若为False将使用统一的先验概率相等class_priorarray-like of shape (n_classes,), defaultNone 类别的先验概率。一经指定先验概率不能随着数据而调整。
属性说明
属性 说明 category_count_list of arrays of shape (n_features,) 为每个要素保存形状的数组n_classes各个要素的n_categories。每个数组为每个类别和分类的特定特征提供遇到的样本数量。class_count_ndarray of shape (n_classes,) 拟合期间每个类别遇到的样本数。此值由提供的样本权重加权。class_log_prior_ndarray of shape (n_classes,) 每个类别的对数先验概率平滑。classes_ndarray of shape (n_classes,) 分类器已知的类别标签feature_log_prob_list of arrays of shape (n_features,) 为每个特征保形状的数组n_classes各个要素的n_categories。每个数组提供了给定各自特征和类别的分类的经验对数概率log(p(xi|y))n_features_int 每个样本的特征数量。
方法说明
方法 说明 fit(X, y[, sample_weight])根据Xy拟合朴素贝叶斯分类器。get_params([deep])获取这个估计器的参数partial_fit(X, y[, classes, sample_weight])对一批样本进行增量拟合。predict(X)对测试向量X进行分类predict_log_proba(X)返回针对测试向量X的对数概率估计predict_proba(X)返回针对测试向量X的概率估计score(X, y[, sample_weight])返回给定测试数据和标签上的平均准确率set_params(**params)为这个估计器设置参数
对于X矩阵和y矩阵的要求如下
参数 说明 X {array-like, sparse matrix} of shape (n_samples, n_features) 样本的特征矩阵其中n_samples是样本数量n_features是特征数量。在此假设X的每个特征都来自不同的分类分布。进一步假设每个特征的所有类别均由数字0…n-1表示其中n表示给定特征的类别总数。例如这可以在顺序编码OrdinalEncoder的帮助下实现。 yarray-like of shape (n_samples,) 每个样本所属的标签类别
2 代码例子
以多项式朴素贝叶斯的连续型数据为例对其进行Ordinal分箱代码如下
# 导入库
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.metrics import brier_score_loss
from sklearn.naive_bayes import CategoricalNB
import numpy as np# **********第一步建立数据集**********
class_1 500
class_2 500 # 两个类分别设置500个样本
centers [[0, 0], [2, 2]] # 设置数据集的中心
clusters_std [0.5, 0.5] # 设置两个类别的均值和方差# 使用make_blobs生成样本y的类别只有0和1
X, y make_blobs(n_samples[class_1, class_2], centerscenters, cluster_stdclusters_std, random_state0, shuffleFalse)# 划分数据集测试集
xtrain, xtest, ytrain, ytest train_test_split(X, y, random_state0, test_size0.3)# **********第二步数据转换**********
# 在这里2个特征中将每个特征定义为有五个类别即分成五个箱
# 矩阵每一列是特征每一列的值是箱的整数编号该整数编号相当于该特征的所属类别
kbs KBinsDiscretizer(n_bins5, encodeordinal).fit(xtrain)
xtrain_ kbs.transform(xtrain)
xtest_ kbs.transform(xtest)# **********第三步建立类别朴素贝叶斯分类器**********
# 训练数据
mnb CategoricalNB().fit(xtrain_, ytrain)# 获取每一个特征的先验概率
# 返回每一个标签类对应的先验概率
print(f对数先验概率矩阵为\n{mnb.class_log_prior_})
# 使用np.exp求出真正的概率因为对数是以e为底
print(f先验概率矩阵为\n{np.exp(mnb.class_log_prior_)}\n)# 返回每一个固定类别标签下的每一个特征的对数概率log(p(xi|y))
# 矩阵形状是2*2,因为有2个特征2个类别
print(f对数条件概率矩阵为\n{mnb.feature_log_prob_})
# 使用np.exp求出真正的概率因为对数是以e为底
print(f条件概率矩阵为\n{np.exp(mnb.feature_log_prob_)}\n)# 在fit时每一个标签类别下包含的样本数
# 当fit时候接口中sample_weight被设置的时候该接口返回的值也会受到加权的影响
print(f0类和1类的样本数分别为\n{mnb.class_count_}\n)# 返回预测结果
print(f预测结果为\n{mnb.predict(xtest_)}\n)# 返回每一个样本在每一个标签下面的取值概率
print(f标签的取值概率矩阵为\n{mnb.predict_proba(xtest_)}\n)# 返回我们的准确度
print(f准确度为{mnb.score(xtest_, ytest)}\n)# 返回我们的布里尔分数
print(f布里尔分数为{brier_score_loss(ytest, mnb.predict_proba(xtest_)[:, 1], pos_label1)})
最终的准确度和布里尔分数为 4.4 贝叶斯的样本不平衡问题
探讨一个分类算法永远都逃不过的核心问题样本不平衡。贝叶斯由于分类效力不算太好因此对样本不平衡极为敏感
注意对于召回率的概念可看混淆矩阵-ROC曲线、召回率、精确率、准确率
接下来看一个例子以少数类样本为正类代码如下
from sklearn.naive_bayes import MultinomialNB, GaussianNB, BernoulliNB,CategoricalNB
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.metrics import brier_score_loss as BS,recall_score,roc_auc_score as AUC# 第一步创建数据集
# 其中少数类为正类即为类别1
class_1 50000 #多数类为50000个样本
class_2 500 #少数类为500个样本
centers [[0.0, 0.0], [5.0, 5.0]] #设定两个类别的中心
clusters_std [3, 1] #设定两个类别的方差
X, y make_blobs(n_samples[class_1, class_2],centerscenters,cluster_stdclusters_std,random_state0, shuffleFalse)
# 查看所有贝叶斯样本不均衡的表现
name [Multinomial,Gaussian,Bernoulli,Categorical]
models [MultinomialNB(),GaussianNB(),BernoulliNB(),CategoricalNB()]
for name,clf in zip(name,models):Xtrain, Xtest, Ytrain, Ytest train_test_split(X,y,test_size0.3,random_state420)if name Categorical:kbs KBinsDiscretizer(n_bins5, encodeordinal).fit(Xtrain)Xtrain kbs.transform(Xtrain)Xtest kbs.transform(Xtest)if name ! Gaussian and name !Categorical:kbs KBinsDiscretizer(n_bins10, encodeonehot).fit(Xtrain)Xtrain kbs.transform(Xtrain)Xtest kbs.transform(Xtest)clf.fit(Xtrain,Ytrain)y_pred clf.predict(Xtest)proba clf.predict_proba(Xtest)[:,1]score clf.score(Xtest,Ytest)print(name)print(\tBrier:{:.3f}.format(BS(Ytest,proba,pos_label1)))print(\tAccuracy:{:.3f}.format(score))# 返回召回率print(\tRecall:{:.3f}.format(recall_score(Ytest,y_pred)))# 返回AUCprint(\tAUC:{:.3f}.format(AUC(Ytest,proba)))
代码结果如下 从结果得到如下结论
多项式朴素贝叶斯判断出了所有的多数类样本但放弃了全部的少数类样本受到样本不均衡问题影响最严重类别贝叶斯和多项式朴素贝叶斯一样高斯比多项式在少数类的判断上更加成功一些至少得到了43.8%的recall伯努利贝叶斯虽然整体的准确度和布里尔分数不如多项式和高斯朴素贝叶斯和但至少成功捕捉出了77.1%的少数类
从上述结果可知这四类贝叶斯结果都不好因此出现了新兴贝叶斯算法补集朴素贝叶斯
4.5 补集贝叶斯
1 ComplementNB语法格式
补集朴素贝叶斯complement naive BayesCNB算法是标准多项式朴素贝叶斯算法的改进。补集贝叶斯可以解决样本不平衡问题并且能够一定程度上忽略朴素假设
class sklearn.naive_bayes.ComplementNB*alpha 1.0fit_prior Trueclass_prior Nonenorm False
参数说明
参数说明alphafloat, default1.0 附加的(Laplace/Lidstone)平滑参数(0表示不平滑)fit_priorbool, defaultTrue 是否学习类别先验概率。如果为False将使用统一的先验。class_priorarray-like of shape (n_classes,), defaultNone 类别的先验概率。一经指定先验概率不能随着数据而调整。normbool, defaultFalse 在计算权重的时候是否适用L2范式来规范权重的大小。默认不进行规范即不跟从补集朴素贝叶斯算法的全部内容如果希望进行规范请设置为True。
属性说明
属性说明class_count_ndarray of shape (n_classes,) 拟合期间每个类别遇到的样本数。此值由提供的样本权重加权。class_log_prior_ndarray of shape (n_classes,) 每个类别的对数概率平滑。classes_ndarray of shape (n_classes,) 分类器已知的类别标签feature_all_ndarray of shape (n_features,) 拟合期间每个特征遇到的样本数。此值由提供的样本权重加权。feature_count_ndarray of shape (n_classes, n_features) 拟合期间每个(类别特征)遇到的样本数。此值由提供的样本权重加权。feature_log_prob_ndarray of shape (n_classes, n_features) 类别补充的经验权重n_features_int 每个样本的特征数量。
常用方法如下
方法说明fit(X, y[, sample_weight])根据Xy拟合朴素贝叶斯分类器get_params([deep])获取这个估计器的参数partial_fit(X, y[, classes, sample_weight])对一批样本进行增量拟合predict(X)对测试向量X进行分类。predict_log_proba(X)返回针对测试向量X的对数概率估计predict_proba(X)返回针对测试向量X的概率估计score(X, y[, sample_weight])返回给定测试数据和标签上的平均准确率。set_params(**params)为这个估计器设置参数
对X矩阵和y矩阵要求如下
参数说明X{array-like, sparse matrix} of shape (n_samples, n_features) 用于训练的向量其中n_samples是样本数量n_features是特征数量。yarray-like of shape (n_samples,) 目标值
2 代码例子
接下来看一个例子以少数类样本为正类代码如下
from sklearn.naive_bayes import MultinomialNB, GaussianNB, BernoulliNB,CategoricalNB, ComplementNB
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.metrics import brier_score_loss as BS,recall_score,roc_auc_score as AUC# 第一步创建数据集
# 其中少数类为正类即为类别1
class_1 50000 #多数类为50000个样本
class_2 500 #少数类为500个样本
centers [[0.0, 0.0], [5.0, 5.0]] #设定两个类别的中心
clusters_std [3, 1] #设定两个类别的方差
X, y make_blobs(n_samples[class_1, class_2],centerscenters,cluster_stdclusters_std,random_state0, shuffleFalse)
# 查看所有贝叶斯样本不均衡的表现
name [Multinomial,Gaussian,Bernoulli,Categorical,Complement]
models [MultinomialNB(),GaussianNB(),BernoulliNB(),CategoricalNB(),ComplementNB()]
for name,clf in zip(name,models):Xtrain, Xtest, Ytrain, Ytest train_test_split(X,y,test_size0.3,random_state420)if name Categorical:kbs KBinsDiscretizer(n_bins5, encodeordinal).fit(Xtrain)Xtrain kbs.transform(Xtrain)Xtest kbs.transform(Xtest)if name ! Gaussian and name !Categorical:kbs KBinsDiscretizer(n_bins10, encodeonehot).fit(Xtrain)Xtrain kbs.transform(Xtrain)Xtest kbs.transform(Xtest)clf.fit(Xtrain,Ytrain)y_pred clf.predict(Xtest)proba clf.predict_proba(Xtest)[:,1]score clf.score(Xtest,Ytest)print(name)print(\tBrier:{:.3f}.format(BS(Ytest,proba,pos_label1)))print(\tAccuracy:{:.3f}.format(score))# 返回召回率print(\tRecall:{:.3f}.format(recall_score(Ytest,y_pred)))# 返回AUCprint(\tAUC:{:.3f}.format(AUC(Ytest,proba)))
代码结果如下 从代码结果可以得出
补集朴素贝叶斯牺牲了部分整体的精确度和布里尔指数但是得到了十分高的召回率Recall捕捉出了98.7%的少数类并且在此基础上维持了和原本的多项式朴素贝叶斯一致的AUC分数。和其他的贝叶斯算法比起来补集朴素贝叶斯的运行速度也十分优秀。如果目标是捕捉少数类则选择补集朴素贝叶斯。