梯度下降法、拉格朗日乘子法、KKT条件回顾
梯度下降法
梯度下降法(Gradient Descent, GD)常用于求解无约束情况下凸函数(Convex Function)的极小值,是一种迭代类型的算法,因为凸函数只有一个极值点,故求解出来的极小值点就是函数的最小值点。
导数:一个函数在某一点的导数描述了这个函数在这一点附近的变化率,也可以 认为是函数在某一点的导数就是该函数所代表的曲线在这一点的切线斜率。导数 值越大,表示函数在该点处的变化越大。
梯度:梯度是一个向量,表示某一函数在该点处的方向导数沿着该方向取的最大值,即函数在该点处沿着该方向变化最快,变化率最大(即该梯度向量的模);当函数为一维函数的时候,梯度其实就是导数。
梯度下降法的优化思想是用当前位置负梯度方向作为搜索方向,因为该方向为当前位置的最快下降方向,所以梯度下降法也被称为“最速下降法” 。梯度下降法中越接近目标值,变量变化越小。计算公式如下:
α被称为步长或者学习率(learning rate),表示自变量x每次迭代变化的大小。
收敛条件:当目标函数的函数值变化非常小的时候或者达到最大迭代次数的时候,就结束循环。
由于梯度下降法中负梯度方向作为变量的变化方向,所以有可能导致最终求解 的值是局部最优解,所以在使用梯度下降的时候,一般需要进行一些调优策略:
- 学习率的选择:学习率过大,表示每次迭代更新的时候变化比较大,有可能会跳过最优解;学习率过小,表示每次迭代更新的时候变化比较小,就会导致迭代速度过慢,很长时间都不能结束;
- 算法初始参数值的选择:初始值不同,最终获得的最小值也有可能不同,因为梯度下降法求解的是局部最优解,所以一般情况下,选择多次不同初始值运行算法,并最终返回损失函数最小情况下的结果值;
- 标准化:由于样本不同特征的取值范围不同,可能会导致在各个不同参数上迭代速度不同,为了减少特征取值的影响,可以将特征进行标准化操作。
批量梯度下降法(Batch Gradient Descent, BGD):使用所有样本在当前点的梯度值来对变量参数进行更新操作。
随机梯度下降法(Stochastic Gradient Descent, SGD):在更新变量参数的时候, 选取一个样本的梯度值来更新参数。
小批量梯度下降法(Mini-batch Gradient Descent, MBGD):集合BGD和SGD 的特性,从原始数据中,每次选择n个样本来更新参数值,一般n选择10.
BGD、SGD、MBGD的区别:
- 当样本量为m的时候,每次迭代BGD算法中对于参数值更新一次,SGD算法中对于参数值更新m次,MBGD算法中对于参数值更新m/n次,相对来讲SGD算法的更新速度最快;
- SGD算法中对于每个样本都需要更新参数值,当样本值不太正常的时候,就有可能会导致本次的参数更新会产生相反的影响,也就是说SGD算法的结果并不是完全收敛的,而是在收敛结果处波动的;
- SGD算法是每个样本都更新一次参数值,所以SGD算法特别适合样本数据量大的情况以及在线机器学习(Online ML)。
有约束的最优化问题
最优化问题一般是指对于某一个函数而言,求解在其指定作用域上的全局最小值问题,一般分为以下三种情况(备注:以下几种方式求出来的解都有可能是局部极小值,只有当函数是凸函数的时候,才可以得到全局最小值):
- 无约束问题:求解方式一般求解方式梯度下降法、牛顿法、坐标轴下降法等;
- 等式约束条件:求解方式一般为拉格朗日乘子法
- 不等式约束条件:求解方式一般为KKT条件
拉格朗日乘子法
拉格朗日乘子法就是当我们的优化函数存在等值约束的情况下的一种最优化求解方式;其中参数α被称为拉格朗日乘子,要求α不等于0。
数学证明:https://wenku.baidu.com/view/ac56710e2e3f5727a5e962a7.html
import numpy as np import matplotlib.pyplot as plt # 原函数 # def f(x, y): # return x**2 / 2.0 + y**2 / 3.0 - 2 # 限制条件 x = np.arange(-4, 5, 0.2) y = np.array(list(map(lambda x: x ** 2 - x +1, x))) # 拉格朗日乘子法理解 def f(x, y): \'\'\'因为限制条件是 y=x ** 2 - x + 1,所以 x ** 2 - x + 1 - y = 0,令 alpha=0.5。\'\'\' return x**2 / 2.0 + y**2 / 3.0 + 0.5 * (x ** 2 - x + 1 - y) - 2 # 构建数据 X = np.arange(-8, 10, 0.2) Y = np.arange(-8, 10, 0.2) # 将原始数据变成网格数据 X, Y = np.meshgrid(X, Y) Height = np.array(list(map(lambda t: f(t[0], t[1]), zip(X.flatten(), Y.flatten())))) Height.shape = X.shape plt.plot(x,y,\'r-\') # 填充颜色 plt.contourf(X, Y, Height,10,alpha = 0.5) # 绘制等高线 C = plt.contour(X, Y, Height, 10, colors = \'black\', linewidths = 0.5) # 显示各等高线的数据标签 plt.clabel(C, inline = True, fontsize = 10) print(y) plt.show()
import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import math from mpl_toolkits.mplot3d import Axes3D # 设置在jupyter中matplotlib的显示情况, tk表示突出显示 %matplotlib tk # 解决中文显示问题 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False # 拉格朗日乘子法理解 # def f(x, y): # return x**2 / 2.0 + y**2 / 3.0 - 2 def f(x, y): return x**2 / 2.0 + y**2 / 3.0 + 0.5 * (x ** 2 - x + 1 - y) - 2 # 构建数据 X1 = np.arange(-8, 8, 0.2) X2 = np.arange(-8, 8, 0.2) X1, X2 = np.meshgrid(X1, X2) Y = np.array(list(map(lambda t: f(t[0], t[1]), zip(X1.flatten(), X2.flatten())))) Y.shape = X1.shape # 限制条件 X3 = np.arange(-4, 4, 0.2) X3.shape = 1,-1 X4 = np.array(list(map(lambda t: t ** 2 - t +1, X3))) # 画图 fig = plt.figure(facecolor=\'w\') ax = Axes3D(fig) ax.plot_surface(X1, X2, Y, rstride=1, cstride=1, cmap=plt.cm.jet) ax.plot(X3, X4 , \'ro--\', linewidths=2) ax.set_xlabel(\'x\') ax.set_zlabel(\'z\') ax.set_ylabel(\'y\') plt.show()
对偶问题
在优化问题中,目标函数f(x)存在多种形式,如果目标函数和约束条件都为变量x的线性函数,则称问题为线性规划;如果目标函数为二次函数,则称最优化问题为二次规划;如果目标函数或者约束条件为非线性函数,则称最优化问题为非线性优化。每个线性规划问题都有一个对应的对偶问题。对偶问题具有以下几个特性:
- 对偶问题的对偶是原问题;
- 无论原始问题是否是凸的,对偶问题都是凸优化问题;
- 对偶问题可以给出原始问题的一个下界;
- 当满足一定条件的时候,原始问题和对偶问题的解是完美等价的。
KKT条件
KKT条件是泛拉格朗日乘子法的一种形式;主要应用在当我们的优化函数存在不等值约束的情况下的一种最优化求解方式;KKT条件即满足不等式约束情况下的条件。
当可行解在约束内部区域的时候,令β=0即可消去约束。
对于参数β的取值而言,在等值约束中,约束函数和目标函数的梯度只要满足平行即可,而在不等式约束中,若β≠0,则说明可行解在约束区域的边界上,这个时候可行解应该尽可能的靠近无约束情况下的解,所以在约束边界上,目标函数的负梯度方向应该远离约束区域朝无约束区域时的解,此时约束函数的梯度方向与目标函数的负梯度方向应相同;从而可以得出β>0。
对偶问题的直观理解:最小的里面的那个最大的要比最大的那个里面的最小的大;从而就可以为原问题引入一个下界。
KKT条件总结
高中距离知识回顾
点到直线/平面的距离公式:
- 假定点p(x0 ,y0 ),平面方程为f(x,y)=Ax+By+C,那么点p到平面f(x)的距离为:
- 从三维空间扩展到多维空间中,如果存在一个超平面f(X)=θX+b; 那么某一个点X0 到这个超平面的距离为:
感知器模型
感知器算法是最古老的分类算法之一,原理比较简单,不过模型的分类泛化能力比较弱,不过感知器模型是SVM、神经网络、深度学习等算法的基础。
感知器的思想很简单:比如北风上有很多的学员,分为男学员和女学员,感知器模型就是试图找到一条直线,能够把所有的男学员和女学员分隔开,如果是高维空间中,感知器模型寻找的就是一个超平面,能够把所有的二元类别分割开。感知器模型的前提是:数据是线性可分的。
对于m个样本,每个样本n维特征以及一个二元类别输出y,如下:
目标是找到一个超平面,即:
感知器模型为:
正确分类(预测和实际类别一致):yθx>0,错误分类(预测和实际类别不一致):yθx<0;所以我们可以定义我们的损害函数为:期望使分类错误的所有样本(k条样本)到超平面的距离之和最小。
因为此时分子和分母中都包含了θ值,当分子扩大N倍的时候,分母也会随之扩大,也就是说分子和分母之间存在倍数关系,所以可以固定分子或者分母为1,然后求另一个即分子或者分母的倒数的最小化作为损失函数,简化后的损失函数为(分母为1):
直接使用梯度下降法就可以对损失函数求解,不过由于这里的m是分类错误的样本点集合,不是固定的,所以我们不能使用批量梯度下降法(BGD)求解,只能使用随机梯度下降(SGD)或者小批量梯度下降(MBGD);一般在感知器模型中使用SGD来求解。
SVM线性可分
SVM原理
支持向量机(Support Vecor Machine, SVM)本身是一个二元分类算法,是对感知器算法模型的一种扩展,现在的SVM算法支持线性分类和非线性分类的分类应用,并且也能够直接将SVM应用于回归应用中,同时通过OvR或者OvO的方式我们也可以将SVM应用在多元分类领域中。在不考虑集成学习算法,不考虑特定的数据集的时候,在分类算法中SVM可以说是特别优秀的。
在感知器模型中,算法是在数据中找出一个划分超平面,让尽可能多的数据分布在这个平面的两侧,从而达到分类的效果,但是在实际数据中这个符合我们要求的超平面是可能存在多个的。
在感知器模型中,我们可以找到多个可以分类的超平面将数据分开,并且优化时希望所有的点(预测正确的点)都离超平面尽可能的远,但是实际上离超平面足够远的点基本上都是被正确分类的,所以这个是没有意义的;反而比较关心那些离超平面很近的点,这些点比较容易分错。所以说我们只要让离超平面比较近的点尽可能的远离这个超平面,那么我们的模型分类效果应该就会比较不错喽。SVM其实就是这个思想。
线性可分(Linearly Separable):在数据集中,如果可以找出一个超平面,将两组数据分开,那么这个数据集叫做线性可分数据。
线性不可分(Linear Inseparable):在数据集中,没法找出一个超平面,能够将两组数据分开,那么这个数据集就叫做线性不可分数据。
分割超平面(Separating Hyperplane):将数据集分割开来的直线/平面叫做分 割超平面。
支持向量(Support Vector):离分割超平面最近的那些点叫做支持向量。
间隔(Margin):支持向量数据点到分割超平面的距离称为间隔。
SVM模型是让所有的分类点在各自类别的支持向量远离超平面的一侧,同时要求支持向量尽可能的远离这个超平面,用数学公式表示如下:
SVM目标函数/损失函数为:
将此时的目标函数和约束条件使用KKT条件转换为拉格朗日函数,从而转换为无 约束的优化函数。
引入拉格朗日乘子后,优化目标变成:
根据拉格朗日对偶化特性,将该优化目标转换为等价的对偶问题来求解,从而优 化目标变成:
所以对于该优化函数而言,可以先求优化函数对于w和b的极小值,然后再求解对于拉格朗日乘子β的极大值。
首先求让函数L极小化的时候w和b的取值,这个极值可以直接通过对函数L分别 求w和b的偏导数得到:
将求解出来的w和b带入优化函数L中,定义优化之后的函数如下:
通过对w、b极小化后,我们最终得到的优化函数只和β有关,所以此时我们可以直接极大化我们的优化函数,得到β的值,从而可以最终得到w和b的值。
假设存在最优解β*; 根据w、b和β的关系,可以分别计算出对应的w值和b值(一 般使用所有支持向量的计算均值来作为实际的b值):
这里的(xs ,ys)即支持向量,根据KKT条件中的对偶互补条件(松弛条件约束),支 持向量必须满足一下公式:
线性可分SVM算法流程
输入线性可分的m个样本数据{(x1 ,y1),(x2 ,y2),...,(xm ,ym)},其中x为n维的特征向量, y为二元输出,取值为+1或者-1;SVM模型输出为参数w、b以及分类决策函数。
构造约束优化问题:
使用SMO算法求出上式优化中对应的最优解β*:
找出所有的支持向量集合S:
更新参数w* 、b*的值:
构建最终的分类器:
线性可分SVM案例
给定三个数据点:正例点x1=(3,3),x2=(4,3), 负例点x3=(1,1),构造此时的约束 优化条件。
from sympy import symbols,pprint,symarray,collect,apart,Rational,Symbol,init_printing from sympy.abc import x import numpy as np init_printing(use_unicode=True) X = np.array([(3,3),(4,3),(1,1)]) Y = np.array([1,1,-1]) m = X.shape[0] betas = symarray(\'beta\',m+1)[1:] func = 0 st = 0 symb = Symbol(\'1/2\') for i in range(m): for j in range(m): func += symb*betas[i]*betas[j]*Y[i]*Y[j]*np.dot(X[i],X[j]) func -= betas[i] st += betas[i]*Y[i] func = collect(func,symb) func
线性可分SVM总结
要求数据必须是线性可分的;
纯线性可分的SVM模型对于异常数据的预测可能会不太准;
对于线性可分的数据,线性SVM分类器的效果非常不错。
SVM线性不可分
SVM的软间隔模型
线性可分SVM中要求数据必须是线性可分的,才可以找到分类的超平面,但是有的时候线性数据集中存在少量的异常点,由于这些异常点导致了数据集不能够线性划分;直白来讲就是:正常数据本身是线性可分的,但是由于存在异常点数据,导致数据集不能够线性可分;
如果线性数据中存在异常点导致没法直接使用SVM线性分割模型的时候,我们可以通过引入软间隔的概念来解决这个问题;
硬间隔:可以认为线性划分SVM中的距离度量就是硬间隔,在线性划分SVM中,要求函数距离一定是大于1的,最大化硬间隔条件为:
软间隔:SVM对于训练集中的每个样本都引入一个松弛因子(ξ),使得函数距离加上松弛因子后的值是大于等于1;这表示相对于硬间隔,对样本到超平面距离的要求放松了。
松弛因子(ξ)越大,表示样本点离超平面越近,如果松弛因子大于1,那么表示允许该样本点分错,所以说加入松弛因子是有成本的,过大的松弛因子可能会导致模型分类错误,因此我们要同时训练ξ尽可能小。所以最终的目标函数就转换成为:
备注:函数中的C>0是惩罚参数,是一个超参数,类似L1/L2 norm的参数;C越大表示对误分类的惩罚越大,也就是越 不允许存在分错的样本;C越小表示对误分类的惩罚越小, 也就是表示允许更多的分错样本存在;C值的给定需要调参。
同线性可分SVM,根据KK条件构造软间隔最大化的约束问题对应的拉格朗日函 数如下:
从而将我们的优化目标函数转换为:
优化目标同样满足KKT条件,所以使用拉格朗日对偶将优化问题转换为等价的对 偶问题:
先求优化函数对于w、b、ξ的极小值,这个可以通过分别对优化函数L求w、b、 ξ的偏导数得,从而可以得到w、b、ξ关于β和μ之间的关系。
将w、b、ξ的值带入L函数中,就可以消去优化函数中的w、b、ξ,定义优化之后的函数如下:
最终优化后的目标函数/损失函数和线性可分SVM模型基本一样,除了约束条件 不同而已, 也就是说也可以使用SMO算法来求解。
在硬间隔最大化的时候,支持向量比较简单,就是离超平面的函数距离为1的样本点就是支持向量。
在软间隔中,根据KKT条件中的对偶互补条件: β(1-ξ-y(wx+b))=0和μ(-ξ)=0, 从而有:
- 当0<βi≤C的时候,并且ξi=0的样本点均是支持向量(即所有的0<βi<C)。即满足|wx+b|=1的所有样本均是支持向量。
- 当0<βi<C对应的样本就是支持向量。
- 备注:软间隔和硬间隔中的支持向量的规则是一样的。
SVM的软间隔模型算法流程
输入线性可分的m个样本数据{(x1 ,y1),(x2 ,y2),...,(xm ,ym)},其中x为n维的特征向量,y为二元输出,取值为+1或者-1;SVM模型输出为参数w、b以及分类决策函数。
选择一个惩罚系数C>0,构造约束优化问题;
使用SMO算法求出上式优化中对应的最优解β*;
更新参数w* 、b*的值;
构建最终的分类器;
SVM的软间隔模型总结
可以解决线性数据中携带异常点的分类模型构建的问题;
通过引入惩罚项系数(松弛因子),可以增加模型的泛化能力,即鲁棒性;
如果给定的惩罚项系数C越小,表示在模型构建的时候,就允许存在越多的分类错误的样本, 也就表示此时模型的准确率会比较低;如果惩罚项系数越大,表示在模型构建的时候,就越不允许存在分类错误的样本,也就表示此时模型的准确率会比较高。
非线性可分SVM
不管是线性可分SVM还是加入惩罚系数后的软间隔线性可分SVM其实都要求数 据本身是线性可分的,对于完全不可以线性可分的数据,这两种算法模型就没法 解决这个问题了。
在线性回归中,我们可以通过多项式扩展将低维度的数据扩展成为高维度的数据,从而可以使用线性回归模型来解决问题。 也就是说对于二维空间中不是线性可分的数据,将其映射到高维空间中后,变成了线性可分的数据。
结合多项式回归在处理非线性可分数据时候的作用,在SVM的线性不可分的数据上,如果将数据映射到高维空间中,那么数据就会变成线性可分的,从而就可以使用线性可分SVM模型或者软间隔线性可分SVM模型。
也就是说,对于线性不可分SVM模型来讲,重点在于低维特征数据到高维特征数据之间的映射。
定义一个从低维特征空间到高维特征空间的映射函数Ф,非线性可分SVM的优化目标函数:
可以看到的是,只需要将原来的低维空间中的两个向量的点积转换为高维空间中两个向量的点积即可。
这样一来问题就解决了吗?似乎是的:拿到非线性数据,就找一个映射,然后一股脑把原来的数据映射到新空间中,再做线性 SVM 即可。不过事实上没有这么简单!其实刚才的方法稍想一下就会发现有问题:在最初的例子里做了一个二阶多项式的转换,对一个二维空间做映射,选择的新空间是原始空间的所有一阶和二阶的组合,得到了5个维度;如果原始空间是三维,那么我们会得到9维的新空间;如果原始空间是n维,那么我们会得到一个n(n+3)/2维的新空间;这个数目是呈爆炸性增长的,这给计算带来了非常大的困难,而且如果遇到无穷维的情况, 就根本无从计算。
核函数
假设函数Ф是一个从低维特征空间到高维特征空间的一个映射,那么如果存在函数K(x,z), 对于任意的低维特征向量x和z,都有:
称函数K(x,z)为核函数(kernal function);
核函数:在低维空间上的计算量等价于特征做维度扩展后的点乘的结果。
核函数在解决线性不可分问题的时候,采取的方式是:使用低维特征空间上的计算来避免在高维特征空间中向量内积的恐怖计算量;也就是说此时SVM模型可以应用在高维特征空间中数据可线性分割的优点,同时又避免了引入这个高维特征空间恐怖的内积计算量。
即:用低维空间中少的内积的计算量来让模型具有高维空间中的线性可分的优点。
不妨还是从最开始的简单例子出发,设两个向量 ,而即是到前面说的五维空间的映射,因此映射过后的内积为:
而同时我们可以发现有一下公式:
可以发现两者之间非常相似,所以我们只要乘上一个相关的系数,就可以让这两个式子的值相等,这样不就将五维空间的一个内积转换为两维空间的内积的运算。
现有有两个两维的向量,进行二阶多项式扩展,然后进行内积计算,这个时候映射高维后计算的计算量为:11次乘法+4次加法;采用近似计算的计算量为:3次乘法+2次加法;采用加系数后的近似计算的计算量为:4次乘法+2次加法;
线性核函数(Linear Kernel):
多项式核函数(Polynomial Kernel):其中γ、r、d属于超参,需要调参定义;
高斯核函数(Gaussian Kernel):其中γ属于超参,要求大于0,需要调参定义;
Sigmoid核函数(Sigmoid Kernel):其中γ、r属于超参,需要调参定义;
核函数总结
核函数可以自定义;核函数必须是正定核函数,即Gram矩阵是半正定矩阵;
核函数的价值在于它虽然也是将特征进行从低维到高维的转换,但核函数它事先在低维上进行计算,而将实质上的分类效果表现在了高维上,也就如上文所说的避免了直接在高维空间中的复杂计算;
通过核函数,可以将非线性可分的数据转换为线性可分数据;
核函数的优先选择
- 分类:线性核函数、多项式核函数(poly)、高斯核函数(rbf)
- 回归:高斯核函数
import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt from sklearn import svm, datasets ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False ## 加载鸢尾花数据 iris = datasets.load_iris() ## 获取前两列作为特征属性(可以比较一下后两列的效果) X = iris.data[:, :2] Y = iris.target ## 自定义一个核函数, 参数x1,x2是特征属性矩阵(会进行迭代,迭代后类型就会不同) def my_kernel(x1, x2): """ We create a custom kernel: (2 0) k(x1, x2) = x1 ( ) x2.T (0 1) """ M = np.array([[2, 0], [0, 1]]) return np.dot(np.dot(x1, M), x2.T) ## 使用自定义的核函数创建一个SVM对象 clf = svm.SVC(kernel=my_kernel) clf.fit(X, Y) ## 评估效果 score = clf.score(X,Y) print ("训练集准确率:%.2f%%" % (score * 100)) ## 构建预测网格 h = .02 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, h), np.arange(y_min, y_max, h)) ## 预测值 Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) cm_light = mpl.colors.ListedColormap([\'#A0FFA0\', \'#FFA0A0\', \'#A0A0FF\']) cm_dark = mpl.colors.ListedColormap([\'g\', \'r\', \'b\']) plt.figure(facecolor=\'w\', figsize=(8,4)) ## 画出区域图 plt.pcolormesh(xx, yy, Z, cmap=cm_light) ## 画出点图 plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=cm_dark) ## 设置title及其他相关属性 plt.title(u\'SVM中自定义核函数\') plt.xlim(x_min, x_max) plt.ylim(y_min, y_max) plt.text(x_max - .3, y_min + .3, (u\'准确率%.2f%%\' % (score * 100)).lstrip(\'0\'), size=15, horizontalalignment=\'right\') plt.show()
高斯核公式证明(扩展)
令z=x;那么进行多维变换后,应该是同一个向量,从而可以得到以下公式:
scitit-learn SVM算法库概述
scikit-learn中SVM的算法库主要分为两类,一类是分类算法,包括:SVC、NuSVC和LinearSVC这三个类,另外一类是回归算法,包括:SVR、NuSVR和LinearSVR这三个类;除此之外,用的比较多的SVM模型还有OneClassSVM类 (主要功能是:异常点检测)。
详见:https://scikit-learn.org/0.19/modules/classes.html
scitit-learn SVM算法库概述分类算法
OneClassSVM是一种异常点检测的算法,算法原理:先使用SVM算法,对正常数据进行模型训练,找出正常数据的数据特性(eg: 数据集中在哪儿??),也就 是找出数据中分割面(也就是正常数据的边界),以边界作为算法找到的支持向量。 预测的时候,如果样本点落在支持向量内部,那就认为属于正常样本,否则就认为属于异常样本。
scitit-learn SVM案例
import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt import warnings from sklearn import svm #svm导入 from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from sklearn.exceptions import ChangedBehaviorWarning ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False warnings.filterwarnings(\'ignore\', category=ChangedBehaviorWarning) ## 读取数据 # \'sepal length\', \'sepal width\', \'petal length\', \'petal width\' iris_feature = [\'花萼长度\', \'花萼宽度\', \'花瓣长度\', \'花瓣宽度\'] path = \'../datas/iris.data\' # 数据文件路径 data = pd.read_csv(path, header=None) x, y = data[list(range(4))], data[4] y = pd.Categorical(y).codes #把文本数据进行编码,比如a b c编码为 0 1 2; 可以通过pd.Categorical(y).categories获取index对应的原始值 x = x[[0, 1]] # 获取第一列和第二列 data.head() ## 数据分割 x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=0, train_size=0.8) print("训练数据格式:{}".format(x_train.shape)) # svm.SVC API说明: # 功能:使用SVM分类器进行模型构建 # 参数说明: # C: 误差项的惩罚系数,默认为1.0;一般为大于0的一个数字,C越大表示在训练过程中对于总误差的关注度越高,也就是说当C越大的时候,对于训练集的表现会越好, # 但是有可能引发过度拟合的问题(overfiting) # kernel:指定SVM内部函数的类型,可选值:linear、poly、rbf、sigmoid、precomputed(基本不用,有前提要求,要求特征属性数目和样本数目一样);默认是rbf; # degree:当使用多项式函数作为svm内部的函数的时候,给定多项式的项数,默认为3 # gamma:当SVM内部使用poly、rbf、sigmoid的时候,核函数的系数值,当默认值为auto的时候,实际系数为1/n_features # coef0: 当核函数为poly或者sigmoid的时候,给定的独立系数,默认为0 # probability:是否启用概率估计,默认不启动,不太建议启动 # shrinking:是否开启收缩启发式计算,默认为True # tol: 模型构建收敛参数,当模型的的误差变化率小于该值的时候,结束模型构建过程,默认值:1e-3 # cache_size:在模型构建过程中,缓存数据的最大内存大小,默认为空,单位MB # class_weight:给定各个类别的权重,默认为空 # max_iter:最大迭代次数,默认-1表示不限制 # decision_function_shape: 决策函数,可选值:ovo和ovr,默认为None;推荐使用ovr;(1.7以上版本才有) # \'\'\' ## 数据SVM分类器构建 clf = svm.SVC(C=1,kernel=\'linear\', decision_function_shape=\'ovr\') #gamma值越大,训练集的拟合就越好,但是会造成过拟合,导致测试集拟合变差 #gamma值越小,模型的泛化能力越好,训练集和测试集的拟合相近,但是会导致训练集出现欠拟合问题, #从而,准确率变低,导致测试集准确率也变低。 ## 模型训练 clf.fit(x_train, y_train) print("参数w:\n{}".format(clf.coef_)) print("截距项:\n{}".format(clf.intercept_)) print (\'预测值:\n\', clf.predict(x_train)) print (\'decision_function:\n\', clf.decision_function(x_train)) print(x_train.iloc[0]) ## 计算模型的准确率/精度 print (clf.score(x_train, y_train)) print (\'训练集准确率:\', accuracy_score(y_train, clf.predict(x_train))) print (clf.score(x_test, y_test)) print (\'测试集准确率:\', accuracy_score(y_test, clf.predict(x_test))) ## 计算决策函数的结构值以及预测值(decision_function计算的是样本x到各个分割平面的距离<也就是决策函数的值>) print (\'decision_function:\n\', clf.decision_function(x_train)) print (\'\npredict:\n\', clf.predict(x_train)) clf.predict(x_train) # 画图 N = 500 x1_min, x2_min = x.min() x1_max, x2_max = x.max() t1 = np.linspace(x1_min, x1_max, N) t2 = np.linspace(x2_min, x2_max, N) x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点 grid_show = np.dstack((x1.flat, x2.flat))[0] # 测试点 grid_hat = clf.predict(grid_show) # 预测分类值 grid_hat = grid_hat.reshape(x1.shape) # 使之与输入的形状相同 cm_light = mpl.colors.ListedColormap([\'#00FFCC\', \'#FFA0A0\', \'#A0A0FF\']) cm_dark = mpl.colors.ListedColormap([\'g\', \'r\', \'b\']) plt.figure(facecolor=\'w\') ## 区域图 plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'None\', edgecolors=\'k\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花SVM特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.show()
import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from sklearn.linear_model import LogisticRegression,RidgeClassifier from sklearn.neighbors import KNeighborsClassifier import warnings ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False warnings.filterwarnings(action=\'ignore\') ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False warnings.filterwarnings(action=\'ignore\') ## 数据分割 x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=28, train_size=0.6) ## 数据SVM分类器构建 svm = SVC(C=1, kernel=\'linear\') ## 模型训练 svm.fit(x_train, y_train) # 截距项, 也就是ppt上b svm.intercept_ # 模型参数,也就是ppt上的w svm.coef_ ## Linear分类器构建 lr = LogisticRegression() rc = RidgeClassifier()#ridge是为了解决特征大于样本,而导致分类效果较差的情况,而提出的 #svm有一个重要的瓶颈——当特征数大于样本数的时候,效果变差; 如果样本比较少的时候,并且数据特性比较完整的时候,knn可能训练效果最好 knn = KNeighborsClassifier() ## 模型训练 lr.fit(x_train, y_train) rc.fit(x_train, y_train) knn.fit(x_train, y_train) ### 效果评估 svm_score1 = accuracy_score(y_train, svm.predict(x_train)) svm_score2 = accuracy_score(y_test, svm.predict(x_test)) lr_score1 = accuracy_score(y_train, lr.predict(x_train)) lr_score2 = accuracy_score(y_test, lr.predict(x_test)) rc_score1 = accuracy_score(y_train, rc.predict(x_train)) rc_score2 = accuracy_score(y_test, rc.predict(x_test)) knn_score1 = accuracy_score(y_train, knn.predict(x_train)) knn_score2 = accuracy_score(y_test, knn.predict(x_test)) ## 画图 x_tmp = [0,1,2,3] y_score1 = [svm_score1, lr_score1, rc_score1, knn_score1] y_score2 = [svm_score2, lr_score2, rc_score2, knn_score2] plt.figure(facecolor=\'w\') plt.plot(x_tmp, y_score1, \'r-\', lw=2, label=u\'训练集准确率\') plt.plot(x_tmp, y_score2, \'g-\', lw=2, label=u\'测试集准确率\') plt.xlim(0, 3) plt.ylim(np.min((np.min(y_score1), np.min(y_score2)))*0.9, np.max((np.max(y_score1), np.max(y_score2)))*1.1) plt.legend(loc = \'lower right\') plt.title(u\'鸢尾花数据不同分类器准确率比较\', fontsize=16) plt.xticks(x_tmp, [u\'SVM\', u\'Logistic\', u\'Ridge\', u\'KNN\'], rotation=0) plt.grid(b=True) plt.show() ### 画图比较 N = 500 x1_min, x2_min = x.min() x1_max, x2_max = x.max() t1 = np.linspace(x1_min, x1_max, N) t2 = np.linspace(x2_min, x2_max, N) x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点 grid_show = np.dstack((x1.flat, x2.flat))[0] # 测试点 ## 获取各个不同算法的测试值 svm_grid_hat = svm.predict(grid_show) svm_grid_hat = svm_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 lr_grid_hat = lr.predict(grid_show) lr_grid_hat = lr_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 rc_grid_hat = rc.predict(grid_show) rc_grid_hat = rc_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 knn_grid_hat = knn.predict(grid_show) knn_grid_hat = knn_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 ## 画图 cm_light = mpl.colors.ListedColormap([\'#A0FFA0\', \'#FFA0A0\', \'#A0A0FF\']) cm_dark = mpl.colors.ListedColormap([\'g\', \'r\', \'b\']) plt.figure(facecolor=\'w\', figsize=(14,7)) ### svm plt.subplot(221) ## 区域图 plt.pcolormesh(x1, x2, svm_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花SVM特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(222) ## 区域图 plt.pcolormesh(x1, x2, lr_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花Logistic特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(223) ## 区域图 plt.pcolormesh(x1, x2, rc_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花Ridge特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(224) ## 区域图 plt.pcolormesh(x1, x2, knn_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花KNN特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.show()
import time import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import warnings ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False warnings.filterwarnings(action=\'ignore\') ## 读取数据 # \'sepal length\', \'sepal width\', \'petal length\', \'petal width\' iris_feature = u\'花萼长度\', u\'花萼宽度\', u\'花瓣长度\', u\'花瓣宽度\' path = \'../datas/iris.data\' # 数据文件路径 data = pd.read_csv(path, header=None) x, y = data[list(range(4))], data[4] y = pd.Categorical(y).codes x = x[[0, 1]] ## 数据分割 x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=28, train_size=0.6) ## 数据SVM分类器构建 svm1 = SVC(C=1, kernel=\'linear\') svm2 = SVC(C=1, kernel=\'rbf\') svm3 = SVC(C=1, kernel=\'poly\') svm4 = SVC(C=1, kernel=\'sigmoid\') ## 模型训练 t0=time.time() svm1.fit(x_train, y_train) t1=time.time() svm2.fit(x_train, y_train) t2=time.time() svm3.fit(x_train, y_train) t3=time.time() svm4.fit(x_train, y_train) t4=time.time() ### 效果评估 svm1_score1 = accuracy_score(y_train, svm1.predict(x_train)) svm1_score2 = accuracy_score(y_test, svm1.predict(x_test)) svm2_score1 = accuracy_score(y_train, svm2.predict(x_train)) svm2_score2 = accuracy_score(y_test, svm2.predict(x_test)) svm3_score1 = accuracy_score(y_train, svm3.predict(x_train)) svm3_score2 = accuracy_score(y_test, svm3.predict(x_test)) svm4_score1 = accuracy_score(y_train, svm4.predict(x_train)) svm4_score2 = accuracy_score(y_test, svm4.predict(x_test)) ## 画图 x_tmp = [0,1,2,3] t_score = [t1 - t0, t2-t1, t3-t2, t4-t3] y_score1 = [svm1_score1, svm2_score1, svm3_score1, svm4_score1] y_score2 = [svm1_score2, svm2_score2, svm3_score2, svm4_score2] plt.figure(facecolor=\'w\', figsize=(12,6)) plt.subplot(121) plt.plot(x_tmp, y_score1, \'r-\', lw=2, label=u\'训练集准确率\') plt.plot(x_tmp, y_score2, \'g-\', lw=2, label=u\'测试集准确率\') plt.xlim(-0.3, 3.3) plt.ylim(np.min((np.min(y_score1), np.min(y_score2)))*0.9, np.max((np.max(y_score1), np.max(y_score2)))*1.1) plt.legend(loc = \'lower left\') plt.title(u\'模型预测准确率\', fontsize=13) plt.xticks(x_tmp, [u\'linear-SVM\', u\'rbf-SVM\', u\'poly-SVM\', u\'sigmoid-SVM\'], rotation=0) plt.grid(b=True) plt.subplot(122) plt.plot(x_tmp, t_score, \'b-\', lw=2, label=u\'模型训练时间\') plt.title(u\'模型训练耗时\', fontsize=13) plt.xticks(x_tmp, [u\'linear-SVM\', u\'rbf-SVM\', u\'poly-SVM\', u\'sigmoid-SVM\'], rotation=0) plt.xlim(-0.3, 3.3) plt.grid(b=True) plt.suptitle(u\'鸢尾花数据SVM分类器不同内核函数模型比较\', fontsize=16) plt.show() ### 预测结果画图 ### 画图比较 N = 500 x1_min, x2_min = x.min() x1_max, x2_max = x.max() t1 = np.linspace(x1_min, x1_max, N) t2 = np.linspace(x2_min, x2_max, N) x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点 grid_show = np.dstack((x1.flat, x2.flat))[0] # 测试点 ## 获取各个不同算法的测试值 svm1_grid_hat = svm1.predict(grid_show) svm1_grid_hat = svm1_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm2_grid_hat = svm2.predict(grid_show) svm2_grid_hat = svm2_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm3_grid_hat = svm3.predict(grid_show) svm3_grid_hat = svm3_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm4_grid_hat = svm4.predict(grid_show) svm4_grid_hat = svm4_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 ## 画图 cm_light = mpl.colors.ListedColormap([\'#A0FFA0\', \'#FFA0A0\', \'#A0A0FF\']) cm_dark = mpl.colors.ListedColormap([\'g\', \'r\', \'b\']) plt.figure(facecolor=\'w\', figsize=(14,7)) ### svm plt.subplot(221) ## 区域图 plt.pcolormesh(x1, x2, svm1_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花Linear-SVM特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(222) ## 区域图 plt.pcolormesh(x1, x2, svm2_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花rbf-SVM特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(223) ## 区域图 plt.pcolormesh(x1, x2, svm3_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花poly-SVM特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(224) ## 区域图 plt.pcolormesh(x1, x2, svm4_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'鸢尾花sigmoid-SVM特征分类\', fontsize=16) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.show()
import time import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import warnings ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False warnings.filterwarnings(action="ignore") ## 读取数据 # \'sepal length\', \'sepal width\', \'petal length\', \'petal width\' iris_feature = u\'花萼长度\', u\'花萼宽度\', u\'花瓣长度\', u\'花瓣宽度\' path = \'../datas/iris.data\' # 数据文件路径 data = pd.read_csv(path, header=None) x, y = data[list(range(4))], data[4] y = pd.Categorical(y).codes x = x[[0, 1]] ## 数据分割 x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=28, train_size=0.6) ## 数据SVM分类器构建 svm1 = SVC(C=0.1, kernel=\'rbf\') svm2 = SVC(C=1, kernel=\'rbf\') svm3 = SVC(C=10, kernel=\'rbf\') svm4 = SVC(C=100, kernel=\'rbf\') svm5 = SVC(C=500, kernel=\'rbf\') svm6 = SVC(C=100000, kernel=\'rbf\') #C越大,泛化能力越差,会出现过拟合的问题 #C越小,泛化能力越好,但是容易出现欠拟合的问题 ## 模型训练 t0=time.time() svm1.fit(x_train, y_train) t1=time.time() svm2.fit(x_train, y_train) t2=time.time() svm3.fit(x_train, y_train) t3=time.time() svm4.fit(x_train, y_train) t4=time.time() svm5.fit(x_train, y_train) t5=time.time() svm6.fit(x_train, y_train) t6=time.time() ### 效果评估 svm1_score1 = accuracy_score(y_train, svm1.predict(x_train)) svm1_score2 = accuracy_score(y_test, svm1.predict(x_test)) svm2_score1 = accuracy_score(y_train, svm2.predict(x_train)) svm2_score2 = accuracy_score(y_test, svm2.predict(x_test)) svm3_score1 = accuracy_score(y_train, svm3.predict(x_train)) svm3_score2 = accuracy_score(y_test, svm3.predict(x_test)) svm4_score1 = accuracy_score(y_train, svm4.predict(x_train)) svm4_score2 = accuracy_score(y_test, svm4.predict(x_test)) svm5_score1 = accuracy_score(y_train, svm5.predict(x_train)) svm5_score2 = accuracy_score(y_test, svm5.predict(x_test)) svm6_score1 = accuracy_score(y_train, svm6.predict(x_train)) svm6_score2 = accuracy_score(y_test, svm6.predict(x_test)) ## 画图 x_tmp = [0,1,2,3, 4, 5] t_score = [t1 - t0, t2-t1, t3-t2, t4-t3, t5-t4, t6-t5] y_score1 = [svm1_score1, svm2_score1, svm3_score1, svm4_score1, svm5_score1, svm6_score1] y_score2 = [svm1_score2, svm2_score2, svm3_score2, svm4_score2, svm5_score2, svm6_score2] plt.figure(facecolor=\'w\', figsize=(12,6)) plt.subplot(121) plt.plot(x_tmp, y_score1, \'r-\', lw=2, label=u\'训练集准确率\') plt.plot(x_tmp, y_score2, \'g-\', lw=2, label=u\'测试集准确率\') plt.xlim(-0.3, 3.3) plt.ylim(np.min((np.min(y_score1), np.min(y_score2)))*0.9, np.max((np.max(y_score1), np.max(y_score2)))*1.1) plt.legend(loc = \'lower left\') plt.title(u\'模型预测准确率\', fontsize=13) plt.xticks(x_tmp, [u\'C=0.1\', u\'C=1\', u\'C=10\', u\'C=100\', u\'C=500\', u\'C=10000\'], rotation=0) plt.grid(b=True) plt.subplot(122) plt.plot(x_tmp, t_score, \'b-\', lw=2, label=u\'模型训练时间\') plt.title(u\'模型训练耗时\', fontsize=13) plt.xticks(x_tmp, [u\'C=0.1\', u\'C=1\', u\'C=10\', u\'C=100\', u\'C=500\', u\'C=10000\'], rotation=0) plt.grid(b=True) plt.suptitle(u\'鸢尾花数据SVM分类器不同内核函数模型比较\', fontsize=16) plt.show() ### 预测结果画图 ### 画图比较 N = 500 x1_min, x2_min = x.min() x1_max, x2_max = x.max() t1 = np.linspace(x1_min, x1_max, N) t2 = np.linspace(x2_min, x2_max, N) x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点 grid_show = np.dstack((x1.flat, x2.flat))[0] # 测试点 ## 获取各个不同算法的测试值 svm1_grid_hat = svm1.predict(grid_show) svm1_grid_hat = svm1_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm2_grid_hat = svm2.predict(grid_show) svm2_grid_hat = svm2_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm3_grid_hat = svm3.predict(grid_show) svm3_grid_hat = svm3_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm4_grid_hat = svm4.predict(grid_show) svm4_grid_hat = svm4_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm5_grid_hat = svm5.predict(grid_show) svm5_grid_hat = svm5_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 svm6_grid_hat = svm6.predict(grid_show) svm6_grid_hat = svm6_grid_hat.reshape(x1.shape) # 使之与输入的形状相同 ## 画图 cm_light = mpl.colors.ListedColormap([\'#A0FFA0\', \'#FFA0A0\', \'#A0A0FF\']) cm_dark = mpl.colors.ListedColormap([\'g\', \'r\', \'b\']) plt.figure(facecolor=\'w\', figsize=(14,7)) ### svm plt.subplot(231) ## 区域图 plt.pcolormesh(x1, x2, svm1_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'C=0.1\', fontsize=15) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(232) ## 区域图 plt.pcolormesh(x1, x2, svm2_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'C=1\', fontsize=15) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(233) ## 区域图 plt.pcolormesh(x1, x2, svm3_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'C=10\', fontsize=15) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(234) ## 区域图 plt.pcolormesh(x1, x2, svm4_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'C=100\', fontsize=15) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(235) ## 区域图 plt.pcolormesh(x1, x2, svm5_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'C=500\', fontsize=15) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.subplot(236) ## 区域图 plt.pcolormesh(x1, x2, svm6_grid_hat, cmap=cm_light) ## 所以样本点 plt.scatter(x[0], x[1], c=y, edgecolors=\'k\', s=50, cmap=cm_dark) # 样本 ## 测试数据集 plt.scatter(x_test[0], x_test[1], s=120, facecolors=\'none\', zorder=10) # 圈中测试集样本 ## lable列表 plt.xlabel(iris_feature[0], fontsize=13) plt.ylabel(iris_feature[1], fontsize=13) plt.xlim(x1_min, x1_max) plt.ylim(x2_min, x2_max) plt.title(u\'C=10000\', fontsize=15) plt.grid(b=True, ls=\':\') plt.tight_layout(pad=1.5) plt.suptitle(u\'鸢尾花数据SVM分类器不同C参数效果比较\', fontsize=16) plt.show()
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl import matplotlib.font_manager from sklearn import svm ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False # 模拟数据产生 xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500)) # 产生训练数据 X = 0.3 * np.random.randn(100, 2) X_train = np.r_[X + 2, X - 2] # 产测试数据 X = 0.3 * np.random.randn(20, 2) X_test = np.r_[X + 2, X - 2] # 产生一些异常点数据 X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2)) # 模型训练(异常点检测的时候是使用正常样本来训练模型,模型是为了找正常数据的数据特征) clf = svm.OneClassSVM(nu=0.01, kernel="rbf", gamma=0.1) clf.fit(X_train) # 预测结果获取 y_pred_train = clf.predict(X_train) y_pred_test = clf.predict(X_test) y_pred_outliers = clf.predict(X_outliers) # 返回1表示属于这个类别,-1表示不属于这个类别---> 那就是可以认为是异常点啦 n_error_train = y_pred_train[y_pred_train == -1].size n_error_test = y_pred_test[y_pred_test == -1].size n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size # Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) # Z = Z.reshape(xx.shape) # Z[:3] # np.c_[xx.ravel(), yy.ravel()].shape # 获取绘图的点信息 # decision_function: 返回样本属于正常样本的可能性大小, # 默认情况,如果是大于0,那就认为是正常样本(predict返回+1), # 如果是小于0就认为是异常样本(predict返回-1) Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # 画图 plt.figure(facecolor=\'w\') plt.title("异常点检测") # 画出区域图 # contourf: 画等高区域图(xx, yy给定坐标点,Z给定对应坐标点的取值, levels给定等高线的区间) plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), Z.max(), 9), cmap=plt.cm.PuBu) # contour:画等高线图 a = plt.contour(xx, yy, Z, levels=[-0.5], linewidths=2, colors=\'darkred\') # 区域填充(在0~max区域做填充) plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors=\'palevioletred\') # 画出点图 s = 40 b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c=\'white\', s=s, edgecolors=\'k\') b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c=\'blueviolet\', s=s, edgecolors=\'k\') c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c=\'gold\', s=s, edgecolors=\'k\') # 设置相关信息 plt.axis(\'tight\') plt.xlim((-5, 5)) plt.ylim((-5, 5)) plt.legend([a.collections[0], b1, b2, c], ["分割超平面", "训练样本", "测试样本", "异常点"], loc="upper left", prop=matplotlib.font_manager.FontProperties(size=11)) plt.xlabel("训练集错误率: %d/200 ; 测试集错误率: %d/40 ; 异常点错误率: %d/40" \ % (n_error_train, n_error_test, n_error_outliers)) plt.show()
import matplotlib as mpl import matplotlib.pyplot as plt from sklearn import datasets, svm, metrics ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False ## 加载数字图片数据 digits = datasets.load_digits() ## 获取样本数量,并将图片数据格式化(要求所有图片的大小、像素点都是一致的 => 转换成为的向量大小是一致的) n_samples = len(digits.images) data = digits.images.reshape((n_samples, -1)) ## 模型构建 classifier = svm.SVC(gamma=0.001)#默认是rbf # from sklearn.neighbors import KNeighborsClassifier # classifier = KNeighborsClassifier(n_neighbors=9, weights=\'distance\') ## 使用二分之一的数据进行模型训练 ##取前一半数据训练,后一半数据测试 classifier.fit(data[:int(n_samples / 2)], digits.target[:int(n_samples / 2)]) ## 测试数据部分实际值和预测值获取 ##后一半数据作为测试集 expected = digits.target[int(n_samples/2):] ##y_test predicted = classifier.predict(data[int(n_samples / 2):])##y_predicted ##生成一个分类报告classification_report print("分类器%s的分类效果:\n%s\n" % (classifier, metrics.classification_report(expected, predicted))) ##生成混淆矩阵 print("混淆矩阵为:\n%s" % metrics.confusion_matrix(expected, predicted)) ## 计算准确率 print("score_svm:\n%f" %classifier.score(data[int(n_samples / 2):], digits.target[int(n_samples / 2):])) ## 进行图片展示 plt.figure(facecolor=\'gray\', figsize=(12,5)) ## 先画出5个预测失败的 ##把预测错的值的 x值 y值 和y的预测值取出 images_and_predictions = list(zip(digits.images[int(n_samples / 2):][expected != predicted], expected[expected != predicted], predicted[expected != predicted])) ##通过enumerate,分别拿出x值 y值 和y的预测值的前五个,并画图 for index,(image,expection, prediction) in enumerate(images_and_predictions[:5]): plt.subplot(2, 5, index + 1) plt.axis(\'off\') plt.imshow(image, cmap=plt.cm.gray_r, interpolation=\'nearest\')#把cmap中的灰度值与image矩阵对应,并填充 plt.title(u\'预测值/实际值:%i/%i\' % (prediction, expection)) ## 再画出5个预测成功的 images_and_predictions = list(zip(digits.images[int(n_samples / 2):][expected == predicted], expected[expected == predicted], predicted[expected == predicted])) for index, (image,expection, prediction) in enumerate(images_and_predictions[:5]): plt.subplot(2, 5, index + 6) # plt.axis(\'off\') plt.imshow(image, cmap=plt.cm.gray_r, interpolation=\'nearest\') plt.title(u\'预测值/实际值:%i/%i\' % (prediction, expection)) plt.subplots_adjust(.04, .02, .97, .94, .09, .2) plt.show()
SMO
序列最小优化算法(Sequential minimal optimization, SMO)是一种用于解决 SVM训练过程中所产生的优化问题的算法。 于1998年由John Platt发明,论文 详见:
假定存在一个β* =(β1 ,β2 ,...,βm)是我们最终的最优解,那么根据KKT条件我们可以 计算出w和b的最优解,如下:
进而我们可以得到最终的分离超平面为:
拉格朗日乘子法和KKT的对偶互补条件为:
β、μ和C之间的关系为:
根据这个对偶互补条件,我们有如下关系式:
也就是说我们找出的最优的分割超平面必须满足下列的目标条件(g(x)):
拉格朗日对偶化要求的两个限制的初始条件为:
从而可以得到解决问题的思路如下:
- 首先,初始化后一个β值,让它满足对偶问题的两个初始限制条件;
- 然后不断优化这个β值,使得由它确定的分割超平面满足g(x)目标条件;而且在优化过程中,始终保证β值满足初始限制条件。
- 备注:这个求解过程中,和传统的思路不太一样,不是对目标函数求最小值,而是 让g(x)目标条件尽可能的满足。
在这样一个过程中,到底如何优化这个β值呢???整理可以发现β值的优化必 须遵循以下两个基本原则:
- 每次优化的时候,必须同时优化β的两个分量;因为如果只优化一个分量的话,新的β值就没法满足初始限制条件中的等式约束条件了。
- 每次优化的两个分量应该是违反g(x)目标条件比较多的。也就是说,本来应当是大于等于1的,越是小于1违反g(x)目标条件就越多。
或者换一种思路来理解,因为目标函数中存在m个变量,直接优化比较难,利用启发式的方法/EM算法的思想,每次优化的时候,只优化两个变量,将其它的变量看成常数项,这样SMO算法就将一个复杂的优化算法转换为一个比较简单的两变量优化问题了。
认为β1、β2是变量,其它β值是常量,从而将目标函数转换如下(C是常数项):
由于β1y1 + β2y2 = k ,并且y1=1或者-1,也就是我们使用β2来表示β1的值:
将上式带入目标优化函数,就可以消去β1,从而只留下仅仅包含β2的式子。
考虑β1和β2的取值限定范围,假定新求出来的β值是满足我们的边界限制的,即 如下所示:
当y1=y2的时候,β1+β2=k; 由于β的限制条件,我们可以得到:
当y1≠y2的时候,β1 - β2=k; 由于β的限制条件,我们可以得到:
结合β的取值限制范围以及函数W的β最优解,我们可以得带迭代过程中的最优 解为:
然后根据β1和β2的关系,从而可以得到迭代后的β1的值:
求解β的过程中,相关公式如下:
可以发现SMO算法中,是选择两个合适的β变量做迭代,其它变量作为常量来进 行优化的一个过程,那么这两个变量到底怎么选择呢???
- 每次优化的时候,必须同时优化β的两个分量;因为如果只优化一个分量的话,新的β值就没法满足初始限制条件中的等式约束条件了。
- 每次优化的两个分量应该是违反g(x)目标条件比较多的。也就是说,本来应当是大于等于1的,越是小于1违反g(x)目标条件就越多。
第一个β变量的选择
SMO算法在选择第一个β变量的时候,需要选择在训练集上违反KKT条件最严重的样本点。一般情况下,先选择0<β<C的样本点(即支持向量),只有当所有的支持向量都满足KKT条件的时候,才会选择其它样本点。因为此时违反KKT条件越严重,在经过一次优化后,会让变量β尽可能的发生变化,从而可以以更少的迭代次数让模型达到g(x)目标条件。
在选择第一个变量β1后,在选择第二个变量β2的时候,希望能够按照优化后的β1和β2有尽可能多的改变来选择,也就是说让|E1-E2 |足够的大,当E1为正的时候, 选择最小的Ei作为E2;当E1为负的时候,选择最大的Ei作为E2。
备注:如果选择的第二个变量不能够让目标函数有足够的下降,那么可以通过遍历所有样本点来作为β2,直到目标函数有足够的下降,如果都没有足够的下降的话,那么直接跳出循环,重新选择β1;
在每次完成两个β变量的优化更新之后,需要重新计算阈值b和差值Ei。当0<β1new<C时,有:
化简可得:
计算阈值b和差值Ei
同样的当β2的取值为: 0<β2<C的时候,我们也可以得到:
最终计算出来的b为:
当更新计算阈值b后,就可以得到差值Ei为:
SMO算法流程总结
输入线性可分的m个样本数据{(x1 ,y1,(x2 ,y2),...,(xm ,ym)},其中x为n维的特征向量, y为二元输出,取值为+1或者-1;精度为e。
- 取初值β0=0,k=0;
- 选择需要进行更新的两个变量: β1k和β2k ,计算出来新的β2new,unt;
- 按照下列式子求出具体的β2k+1;
- 按照 β1k和β2k的关系,求出β1k+1的值:
- 按照公式计算bk+1和Ei的值;
- 检查函数y(i)*Ei的绝对值是否在精度范围内,并且求解出来的β解满足KKT相关约束条件,那么此时结束循环,返回此时的β解即可,否则继续迭代计算β2new,unt的值。
SVR
SVM和决策树一样,可以将模型直接应用到回归问题中;在SVM的分类模型 (SVC)中,目标函数和限制条件如下:
在SVR中,目的是为了尽量拟合一个线性模型y=wx+b;从而我们可以定义常量eps>0,对于任意一点(x,y),如果|y-wx-b|≤eps,那么认为没有损失,从而我们可以得到目标函数和限制条件如下:
加入松弛因子ξ>0,从而我们的目标函数和限制条件变成:
构造拉格朗日函数:
拉格朗日函数对偶化
首先来求优化函数对于w、b、ξ的极小值,通过求导可得:
将w、b、ξ的值带入函数L中,就可以将L转换为只包含β的函数,从而我们可以得到最终的优化目标函数为(备注:对于β的求解照样可以使用SMO算法来求解):
scitit-learn SVM算法库概述回归算法
import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import pandas as pd import warnings import sklearn from sklearn.svm import SVR#对比SVC,是svm的回归形式 from sklearn.model_selection import train_test_split from sklearn.model_selection import GridSearchCV ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False def notEmpty(s): return s != \'\' ## 加载数据 names = [\'CRIM\',\'ZN\', \'INDUS\',\'CHAS\',\'NOX\',\'RM\',\'AGE\',\'DIS\',\'RAD\',\'TAX\',\'PTRATIO\',\'B\',\'LSTAT\'] path = "../datas/boston_housing.data" ## 由于数据文件格式不统一,所以读取的时候,先按照一行一个字段属性读取数据,然后再安装每行数据进行处理 fd = pd.read_csv(path, header=None) data = np.empty((len(fd), 14)) for i, d in enumerate(fd.values): d = map(float, filter(notEmpty, d[0].split(\' \'))) data[i] = list(d) ## 分割数据 x, y = np.split(data, (13,), axis=1) y = y.ravel() # 转换格式 print ("样本数据量:%d, 特征个数:%d" % x.shape) print ("target样本数据量:%d" % y.shape[0]) # 数据分割 x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=28) ## 模型构建(参数类型和SVC基本一样) parameters = { \'kernel\': [\'linear\', \'rbf\'], \'C\': [0.1, 0.5,0.9,1,5], \'gamma\': [0.001,0.01,0.1,1] } model = GridSearchCV(SVR(), param_grid=parameters, cv=3) model.fit(x_train, y_train) ## 获取最优参数 print ("最优参数列表:", model.best_params_) print ("最优模型:", model.best_estimator_) print ("最优准确率:", model.best_score_) ## 模型效果输出 print ("训练集准确率:%.2f%%" % (model.score(x_train, y_train) * 100)) print ("测试集准确率:%.2f%%" % (model.score(x_test, y_test) * 100)) ## 画图 colors = [\'g-\', \'b-\'] ln_x_test = range(len(x_test)) y_predict = model.predict(x_test) plt.figure(figsize=(16,8), facecolor=\'w\') plt.plot(ln_x_test, y_test, \'r-\', lw=2, label=u\'真实值\') plt.plot(ln_x_test, y_predict, \'g-\', lw = 3, label=u\'SVR算法估计值,$R^2$=%.3f\' % (model.best_score_)) # 图形显示 plt.legend(loc = \'upper left\') plt.grid(True) plt.title(u"波士顿房屋价格预测(SVM)") plt.xlim(0, 101) plt.show()
分类算法模型的选择方式
比较逻辑回归、KNN、决策树、随机森林、GBDT、Adaboost、SVM等分类算 法的效果,数据集使用sklearn自带的模拟数据进行测试。
我们首先看数据量,如果数据量多,那使用简单算法(eg: KNN、Logtistic);如果数据量少,首先使用简单执行速度快的算法(Logitsic回归、LinearSVC、决策树),然后如果基础算法效果不好,那么考虑集成算法或者SVC(rbf)。
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from matplotlib.colors import ListedColormap from sklearn import svm 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.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier from sklearn.linear_model import LogisticRegressionCV ## 设置属性防止中文乱码 mpl.rcParams[\'font.sans-serif\'] = [u\'SimHei\'] mpl.rcParams[\'axes.unicode_minus\'] = False %matplotlib tk X, y = make_classification(n_features=2, n_redundant=0, n_informative=2, random_state=1, n_clusters_per_class=1) rng = np.random.RandomState(2) X += 2 * rng.uniform(size=X.shape) linearly_separable = (X, y) datasets = [make_moons(noise=0.3, random_state=0), make_circles(noise=0.2, factor=0.4, random_state=1), linearly_separable ] #建模环节,用list把所有算法装起来 names = ["Nearest Neighbors", "Logistic","Decision Tree", "Random Forest", "AdaBoost", "GBDT","svm"] classifiers = [ KNeighborsClassifier(3), LogisticRegressionCV(), DecisionTreeClassifier(max_depth=5), RandomForestClassifier(max_depth=5, n_estimators=10, max_features=1), AdaBoostClassifier(n_estimators=10,learning_rate=1.5), GradientBoostingClassifier(n_estimators=10, learning_rate=1.5), svm.SVC(C=1, kernel=\'rbf\', gamma=0.1) ] ## 画图 figure = plt.figure(figsize=(27, 9), facecolor=\'w\') i = 1 h = .02 # 步长 for ds in datasets: X, y = ds X = StandardScaler().fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4) x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5 xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) cm = plt.cm.RdBu cm_bright = ListedColormap([\'r\', \'b\', \'y\']) # 原始的样本图 ax = plt.subplot(len(datasets), len(classifiers) + 1, i) ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright) ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6) ax.set_xlim(xx.min(), xx.max()) ax.set_ylim(yy.min(), yy.max()) ax.set_xticks(()) ax.set_yticks(()) i += 1 # 画每个算法的图 for name, clf in zip(names, classifiers): ax = plt.subplot(len(datasets), len(classifiers) + 1, i) clf.fit(X_train, y_train) score = clf.score(X_test, y_test) #hasattr是判定某个模型中,有没有哪个参数, #判断clf模型中,有没有decision_function #np.c_让内部数据按列合并 if hasattr(clf, "decision_function"): Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) else: # 获取概率值 Z = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1] Z = Z.reshape(xx.shape) ax.contourf(xx, yy, Z, cmap=cm, alpha=.8) ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright) ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6) ax.set_xlim(xx.min(), xx.max()) ax.set_ylim(yy.min(), yy.max()) ax.set_xticks(()) ax.set_yticks(()) ax.set_title(name) ax.text(xx.max() - .3, yy.min() + .3, (\'%.2f\' % score).lstrip(\'0\'), size=25, horizontalalignment=\'right\') i += 1 ## 展示图 figure.subplots_adjust(left=.02, right=.98) plt.show() # plt.savefig("cs.png")