七、支持向量机
7.1 概述
用的最多的是分类,不过做其他的也有不错的效果
对于三种差别的输入数据,每种分类器的体现。可以看出SVM最棒
SVM是最靠近深度学习的机器学习算法。线性SVM可以看成是神经网络的单个神经元,非线性的SVM则与两层的神经网络相当,非线性的SVM中如果添加多个核函数,则可以模仿多层的神经网络
7.1.1 支持向量机分类器是怎样工作的
这是一组两种标签的数据,两种标签分别由圆和方块代表
- 支持向量机的分类方法:是在这组分布中找出一个超平面作为决策边界,使模型在数据上的分类偏差只管靠近于小,尤其是在未知数据集上的分类偏差(泛化偏差)只管小
把决策边界B1向两边平移,直到碰到离这条决策边界迩来的方块和圆圈后停下,形成两个新的超平面,分别是b11 和b12——>在b11 和b12中心的距离,叫做B1这条决策边界的边际,记为d,图下图所示:
——>留意,边际很小的环境,是一种模型在 训练集上体现很好,却在测试集上体现糟糕 的环境,以是会“过拟合”(如下图的红点对于B2及其边际而言)。以是我们在找寻决策边界的时候,希望边际越大越好
支持向量机,就是通过找出边际最大的决策边界,来对数据举行分类的分类器
——>支持向量分类器又叫做最大边际分类器(但是现实上并不简单)
7.1.2 支持向量机原理的三层理解
- 目标:"找出边际最大的决策边界",SVM也是通过最小化损失函数来求解一个用于后续模型利用的重要信息:决策边界
7.1.3 sklearn中的支持向量机
留意,除了特殊表明是线性的两个类LinearSVC和LinearSVR之外,其他的所有类都是同时支持线性和非线性的;SCV/SVR是最常用的;Nu则是能够限定支持向量的数量;Libsvm是一个简单、易于利用和快速有效的英文的SVM库,若熟悉这些操纵,可直接从lib调用函数来举利用用
7.2 sklearn.svm.SVC
class sklearn.svm.SVC (C=1.0, kernel=’rbf’, degree=3, gamma=’auto_deprecated’, coef0=0.0, shrinking=True,probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1,decision_function_shape=’ovr’, random_state=None)
7.2.1 线性SVM用于分类的原理
(1~3) 原理部分(看网课和pdf去吧)
(4) 线性SVM决策过程的可视化
用sklearn中的式子来为可视化我们的决策边界,支持向量,以及决策边界平行的两个超平面
#下面这个包可以用于制造一堆堆的数据堆from sklearn.datasets import make_blobsfrom sklearn.svm import SVCimport matplotlib.pyplot as pltimport numpy as npX,y = make_blobs(n_samples=50, centers=2, random_state=0,cluster_std=0.6)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plt.xticks([])plt.yticks([])plt.show()
- 画决策边界:理解函数contour
matplotlib.axes.Axes.contour([X, Y,] Z, [levels], **kwargs)
Contour是我们专门用来绘制等高线的函数。等高线的本质是 在二维图像上体现三维图像的一种形式 ,其中两维X和Y是两条坐标轴上的取值,而Z表现高度;Contour就是将由X和Y构成平面上的所有点中,高度一致的点毗连成线段的函数,在同一条等高线上的点一定具有雷同的Z值,可以用它来绘制决策边界
只需要在我们的样本构成的平面上,把所有到决策边界的距离为0的点相连,就是我们的决策边界,而把所有到决策边界的相对距离为1的点相连,就是我们的两个平行于决策边界的超平面了,那么Z就是平面上的任意点到达超平面的距离
首先,我们需要获取样本构成的平面,作为一个对象
#用contour画出决策边界#不利用上面的散点图,而是用网格图来做点,再盘算每个点到超平面的距离#首先要有散点图plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")#获取当前的子图,如果不存在,则创建新的子图ax = plt.gca() # 画决策边界:制作网格,理解函数meshgrid#获取平面上两条坐标轴的最大值和最小值(也就是坐标轴范围)xlim = ax.get_xlim()ylim = ax.get_ylim()xlim#(-0.7425578984849813, 3.3721920271976598)ylim#(-0.41872382476349596, 5.754870487889891)#在最大值和最小值之间形成30个规律/匀称的数据#linespace的第一个参数是起始点,第二个是停止点,第三个是指定范围内取得个数axisx = np.linspace(xlim[0],xlim[1],30)axisy = np.linspace(ylim[0],ylim[1],30)axisy,axisx = np.meshgrid(axisy,axisx) #我们将利用这里形成的二维数组作为我们contour函数中的X和Y #利用meshgrid函数将两个一维向量转换为特征矩阵#核心是将两个特征向量广播,以便获取y.shape * x.shape这么多个坐标点的横坐标和纵坐标xy = np.vstack([axisx.ravel(), axisy.ravel()]).T #其中ravel()是降维函数,vstack能够将多个布局一致的一维数组按行堆叠起来#xy就是已经形成的网格,它是遍布在整个画布上的麋集的点plt.scatter(xy[:,0],xy[:,1],s=1,cmap="rainbow") #理解函数meshgrid和vstack的作用a = np.array([1,2,3])b = np.array([7,8])#两两组合,会得到多少个坐标?#答案是6个,分别是 (1,7),(2,7),(3,7),(1,8),(2,8),(3,8)v1,v2 = np.meshgrid(a,b)v1#array([[1, 2, 3],# [1, 2, 3]])v2#array([[7, 7, 7],# [8, 8, 8]])#通过ravel来举行降维v1.ravel()#array([1, 2, 3, 1, 2, 3])v2.ravel()#array([7, 7, 7, 8, 8, 8])v = np.vstack([v1.ravel(), v2.ravel()]).T#array([[1, 7],# [2, 7],# [3, 7],# [1, 8],# [2, 8],# [3, 8]])#vstack就是把两个特征向量中的一个当横坐标,另一个当纵坐标,来形成点
- 建模,盘算决策边界并找出网格上每个点到决策边界的距离
#开始建模#首先要有散点图plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")#获取当前的子图,如果不存在,则创建新的子图ax = plt.gca() #建模,通过fit盘算出对应的决策边界#fit的本质就是在找决策边界clf = SVC(kernel = "linear").fit(X,y) Z = clf.decision_function(xy).reshape(axisx.shape) #重要接口decision_function,返回每个输入的样本所对应的到决策边界的距离#然后再将这个距离转换为axisx的布局,这是由于画图的函数contour要求Z的布局必须与X和Y保持一致#画决策边界和平行于决策边界的超平面ax.contour(axisx,axisy,Z ,colors="k" ,levels=[-1,0,1] #画三条等高线,分别是Z为-1,0和Z为1的三条线 ,alpha=0.5 ,linestyles=["--","-","--"]) #--是虚线,-是实线ax.set_xlim(xlim)ax.set_ylim(ylim)
#记得Z的本质么?是输入的样本到决策边界的距离,而contour函数中的level其实是输入了这个距离#让我们用一个点来试试看plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plt.scatter(X[10,0],X[10,1],c="black",s=50,cmap="rainbow")
#盘算上面谁人玄色点到决策边界的距离,再用contour函数画一条直线clf.decision_function(X[10].reshape(1,2))#array([-3.33917354])plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")ax = plt.gca()ax.contour(axisx,axisy,Z ,colors="k" ,levels=[-3.33917354] ,alpha=0.5 ,linestyles=["--"])
虚线上所有点到决策边界的距离都是-3.33917354
#将绘图过程包装成函数#将上述过程包装成函数:def plot_svc_decision_function(model,ax=None): if ax is None: ax = plt.gca() xlim = ax.get_xlim() ylim = ax.get_ylim() x = np.linspace(xlim[0],xlim[1],30) y = np.linspace(ylim[0],ylim[1],30) Y,X = np.meshgrid(y,x) xy = np.vstack([X.ravel(), Y.ravel()]).T P = model.decision_function(xy).reshape(X.shape) ax.contour(X, Y, P,colors="k",levels=[-1,0,1],alpha=0.5,linestyles=["--","-","--"]) ax.set_xlim(xlim) ax.set_ylim(ylim) #则整个绘图过程可以写作:clf = SVC(kernel = "linear").fit(X,y)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plot_svc_decision_function(clf)
只要在上面的代码中修改X,y就可以画出差别数据集分布下的决策边界
clf.predict(X) #根据决策边界,对X中的样本举行分类,返回的布局为n_samples#就是在根据决策边界来举行分类#array([1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1,# 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1,# 0, 1, 1, 0, 1, 0])clf.score(X,y) #返回给定测试数据和标签的平均正确度# 1.0clf.support_vectors_#返回支持向量#array([[0.44359863, 3.11530945],# [2.33812285, 3.43116792],# [2.06156753, 1.96918596]])#返回了三个支持向量所对应的横,纵坐标clf.n_support_#返回每个类中支持向量的个数#array([2, 1])from sklearn.datasets import make_circles#画环,会生成两个环X,y = make_circles(100, factor=0.1, noise=.1) X.shape#(100, 2)y.shape#(100,)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plt.show()
#画出超平面和决策边界clf = SVC(kernel = "linear").fit(X,y)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plot_svc_decision_function(clf)clf.score(X,y)# 0.55明显,现在线性SVM已经不适合于我们的状况了。此时,如果我们能够在本来的X和y的基础上,添加一个维度r,变成三维,我们可视化这个数据,来看看添加维度让我们的数据怎样厘革
# 9. 为非线性数据增长维度并绘制3D图像#界说一个由x盘算出来的新维度r r = np.exp(-(X**2).sum(1))rlim = np.linspace(min(r),max(r),100)from mpl_toolkits import mplot3d#界说一个绘制三维图像的函数#elev表现上下旋转的角度#azim表现平行旋转的角度def plot_3D(elev=30,azim=30,X=X,y=y): ax = plt.subplot(projection="3d") ax.scatter3D(X[:,0],X[:,1],r,c=y,s=50,cmap='rainbow') ax.view_init(elev=elev,azim=azim) ax.set_xlabel("x") ax.set_ylabel("y") ax.set_zlabel("r") plt.show() plot_3D()
此时,我们可以利用一个平面来将数据完全分开,并使平面的上方的所有数据点为一类,平面下方的所有数据点为另一类。
- 将上述过程放到Jupyter Notebook中运行
#10. 将上述过程放到Jupyter Notebook中运行#如果放到jupyter notebook中运行from sklearn.svm import SVCimport matplotlib.pyplot as pltimport numpy as npfrom sklearn.datasets import make_circlesX,y = make_circles(100, factor=0.1, noise=.1)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")def plot_svc_decision_function(model,ax=None): if ax is None: ax = plt.gca() xlim = ax.get_xlim() ylim = ax.get_ylim() x = np.linspace(xlim[0],xlim[1],30) y = np.linspace(ylim[0],ylim[1],30) Y,X = np.meshgrid(y,x) xy = np.vstack([X.ravel(), Y.ravel()]).T P = model.decision_function(xy).reshape(X.shape) ax.contour(X, Y, P,colors="k",levels=[-1,0,1],alpha=0.5,linestyles=["--","-","--"]) ax.set_xlim(xlim) ax.set_ylim(ylim) clf = SVC(kernel = "linear").fit(X,y)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plot_svc_decision_function(clf) r = np.exp(-(X**2).sum(1))rlim = np.linspace(min(r),max(r),0.2)from mpl_toolkits import mplot3ddef plot_3D(elev=30,azim=30,X=X,y=y): ax = plt.subplot(projection="3d") ax.scatter3D(X[:,0],X[:,1],r,c=y,s=50,cmap='rainbow') ax.view_init(elev=elev,azim=azim) ax.set_xlabel("x") ax.set_ylabel("y") ax.set_zlabel("r") plt.show() from ipywidgets import interact,fixedinteract(plot_3D,elev=[0,30],azip=(-180,180),X=fixed(X),y=fixed(y))plt.show()
此时我们的数据在三维空间中,我们的超平面就是一个二维平面。
核变更:上面做的盘算r,并将r作为数据的第三维度来将数据升维的过程。便是将数据投影到高维空间中,以探求能够将数据美满分割的超平面,便是说探求能够让数据线性可分的高维空间——>核函数
7.2.2 非线性SVM与核函数
(1) SVC在非线性数据上的推广
看pdf,网课去
(2) 重要参数kernel
核函数可以帮我们找到合适的高纬度空间
- 有了核函数之后,我们无需去担心新空间毕竟应该是什么样,由于非线性SVM中的核函数都是正定核函数确保了高维空间中任意两个向量的点积一定可以被低维空间中的这两个向量的某种盘算来表现(多数时候是点积的某种变更);
- 利用核函数盘算低维度中的向量关系比盘算本来的新空间点积要简单太多了;
- 由于盘算是在原始空间中举行,以是避免了维度唾骂*(由于维度太高而无法盘算)的题目;
在SVC中,这个功能由参数“kernel”和一系列与核函数相关的参数来举行控制。参数“kernel"在sklearn中可选以下几种选项:
而刚才我们利用的盘算r的方法,其实是高斯径向基核函数所对应的功能,在参数”kernel“中输入”rbf“就可以利用这种核函数:
#用rbf核函数来处置惩罚非线性的环境clf = SVC(kernel = "rbf").fit(X,y)plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")plot_svc_decision_function(clf)可以看到,决策边界被美满地找了出来。
(3) 探索核函数在差别数据集上的体现
import numpy as npimport matplotlib.pyplot as plt#引入Colormap是为了画图更好看from matplotlib.colors import ListedColormapfrom sklearn import svm#引用各种数据类from sklearn.datasets import make_circles, make_moons,make_blobs,make_classificationn_samples = 100datasets = [ make_moons(n_samples=n_samples, noise=0.2, random_state=0), make_circles(n_samples=n_samples, noise=0.2, factor=0.5, random_state=1), make_blobs(n_samples=n_samples, centers=2, random_state=5), #分类是一定要指定特征个数n_features,n_informative指明带信息特征的个数,n_redundant指明不带信息特征个数 make_classification(n_samples=n_samples,n_features = 2,n_informative=2,n_redundant=0, random_state=5) ]Kernel = ["linear","poly","rbf","sigmoid"] #四个数据集分别是什么样子呢?for X,Y in datasets: plt.figure(figsize=(5,4)) plt.scatter(X[:,0],X[:,1],c=Y,s=50,cmap="rainbow")
我们统共有四个数据集,四种核函数,我们希望观察每种数据集下每个核函数的体现。以核函数为列,以图像分布为行,我们统共需要16个子图来展示分类结果,另有4个是原始图,共计需要20个
nrows=len(datasets)ncols=len(Kernel) + 1fig, axes = plt.subplots(nrows, ncols,figsize=(20,16))#4. 开始举行子图循环#第一层循环:在差别的数据集中循环;enumerate返回的是对应的索引for ds_cnt, (X,Y) in enumerate(datasets): #在图像中的第一列,放置原数据的分布 ax = axes[ds_cnt, 0] if ds_cnt == 0: ax.set_title("Input data") ax.scatter(X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.cm.Paired,edgecolors='k')#zorder是让图像体现在上/下面的参数,值越大/小就越上/下面 ax.set_xticks(()) ax.set_yticks(()) #第二层循环:在差别的核函数中循环 #从图像的第二列开始,一个个填充分类结果 for est_idx, kernel in enumerate(Kernel): #界说子图位置 ax = axes[ds_cnt, est_idx + 1] #建模 clf = svm.SVC(kernel=kernel, gamma=2).fit(X, Y) score = clf.score(X, Y) #绘制图像自己分布的散点图 ax.scatter(X[:, 0], X[:, 1], c=Y ,zorder=10 ,cmap=plt.cm.Paired,edgecolors='k') #绘制支持向量 ax.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=50, facecolors='none', zorder=10, edgecolors='k') #绘制决策边界 x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5 #np.mgrid,归并了我们之前利用的np.linspace和np.meshgrid的用法 #一次性利用最大值和最小值来生成网格 #表现为[起始值:结束值:步长] #如果步长是复数,则其整数部分就是起始值和结束值之间创建的点的数量,并且结束值被包含在内 XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] #np.c_,类似于np.vstack的功能 Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()]).reshape(XX.shape) #填充等高线差别区域的颜色 ax.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired) #绘制等高线 ax.contour(XX, YY, Z, colors=['k', 'k', 'k'], linestyles=['--', '-', '--'], levels=[-1, 0, 1]) #设定坐标轴为不体现 ax.set_xticks(()) ax.set_yticks(()) #将标题放在第一行的顶上 if ds_cnt == 0: ax.set_title(kernel) #为每张图添加分类的分数 ax.text(0.95, 0.06, ('%.2f' % score).lstrip('0') , size=15 , bbox=dict(boxstyle='round', alpha=0.8, facecolor='white') #为分数添加一个白色的格子作为底色 , transform=ax.transAxes #确定文字所对应的坐标轴,就是ax子图的坐标轴自己 , horizontalalignment='right' #位于坐标轴的什么方向 ) plt.tight_layout()plt.show()这里要3和4一起运行,否则没法出图;第三行这种混杂数据,可以试着用用看决策树
(4) 探索核函数的上风和缺陷
上面所画的图要求我们事先知道数据的分布环境,但是现实环境不一定是这样的。其实rbf和poly都有自己的弊端,我们利用乳腺癌数据集作为例子来展示一下:
#其实rbf和poly都有自己的弊端,我们利用乳腺癌数据集作为例子来展示一下from sklearn.datasets import load_breast_cancerfrom sklearn.svm import SVCfrom sklearn.model_selection import train_test_splitimport matplotlib.pyplot as pltimport numpy as np#时间模块,可以用来计时from time import time#将时间戳转为真实时间import datetime#实例化data = load_breast_cancer()X = data.datay = data.targetX.shape#(569,30)np.unique(y)#array([0,1])plt.scatter(X[:,0],X[:,1],c=y)plt.show()Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)Kernel = ["linear","poly","rbf","sigmoid"]for kernel in Kernel: time0 = time() clf= SVC(kernel = kernel , gamma="auto" # , degree = 1 , cache_size=5000 ).fit(Xtrain,Ytrain) print("The accuracy under kernel %s is %f" % (kernel,clf.score(Xtest,Ytest))) print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))然后我们发现,怎么跑都跑不出来。模型一直停留在线性核函数之后,就没有再打印结果了。这证明,多项式核函数此时此刻要消耗大量的时间,运算非常的迟钝。让我们在循环中去掉多项式核函数,再试试看可否跑出结果:
Kernel = ["linear","rbf","sigmoid"]for kernel in Kernel: time0 = time() clf= SVC(kernel = kernel , gamma="auto" # , degree = 1 , cache_size=5000 ).fit(Xtrain,Ytrain) print("The accuracy under kernel %s is %f" % (kernel,clf.score(Xtest,Ytest))) print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))输出结果为:
可以看出,linear最好,说明是个线性分布的数据集;不过线性的运行速度最慢
——>设定degree=1的多项式核函数
Kernel = ["linear","poly","rbf","sigmoid"]for kernel in Kernel: time0 = time() clf= SVC(kernel = kernel , gamma="auto" , degree = 1 , cache_size=5000 ).fit(Xtrain,Ytrain) print("The accuracy under kernel %s is %f" % (kernel,clf.score(Xtest,Ytest))) print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))为什么rbf在这里的发挥这么拉?这是由于数据的量纲题目,先来探索一下乳腺癌数据集的量纲:
import pandas as pddata = pd.DataFrame(X)#describe可以看到一大堆的形貌性统计,用于检察数据是否有偏态#偏态分布,是指统计数据峰值与平均值不相等的频率分布data.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T#量纲不同一#数据较大的特征多数有偏态题目
可以看出上面这些数据的均值、方差,最大/小值等的分布都非常不稳定,说明其量纲不同一——>数据标准化
from sklearn.preprocessing import StandardScaler#将所有数据转化为(0,1)间的正态分布X = StandardScaler().fit_transform(X)data = pd.DataFrame(X)data.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).TXtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)Kernel = ["linear","poly","rbf","sigmoid"]for kernel in Kernel: time0 = time() clf= SVC(kernel = kernel , gamma="auto" , degree = 1 , cache_size=5000 ).fit(Xtrain,Ytrain) print("The accuracy under kernel %s is %f" % (kernel,clf.score(Xtest,Ytest))) print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))
可以看到,运行速度和正确率都得到了很大的提升。
结论/缺点:
- 线性核,尤其是多项式核函数在高次项时盘算非常迟钝;
- rbf和多项式核函数都不善于处置惩罚量纲不同一的数据集;
不过上面这俩题目都可以拿无量纲化来办理。因此,SVM实行之前,非常推荐先举行数据的无量纲化;
加下来就可以看看相关参数了;
(5) 选取与核函数相关的参数:degree & gamma & coef0
参数gamma就是表达式中的γ,degree就是多项式核函数的次数d,参数coef0就是常数项r。其中,高斯径向基核函数受到gamma的影响,而多项式核函数受到全部三个参数的影响;
很难去界定具体每个参数怎样影响了SVM的体现。我们往往避免除真正探究这些参数怎样影响了我们的核函数,而直接利用学习曲线或者网格搜索来帮助我们查找最佳的参数组合;
对于高斯径向基核函数,调整gamma的方式其实比力容易,那就是画学习曲线。我们来试试看高斯径向基核函数rbf的参数gamma在乳腺癌数据集上的体现:
score = []#返回在对数刻度上匀称隔断的数字;第一个是起始值,第二个值是停止值,第三个值是取得个数gamma_range = np.logspace(-10, 1, 50) for i in gamma_range: clf = SVC(kernel="rbf",gamma = i,cache_size=5000).fit(Xtrain,Ytrain) score.append(clf.score(Xtest,Ytest))#输出最高分数以及其对应的值print(max(score), gamma_range[score.index(max(score))])plt.plot(gamma_range,score)plt.show()通过学习曲线,很容就找出了rbf的最佳gamma值;
但对于多项式核函数来说,统统就没有那么容易了,由于三个参数共同作用在一个数学公式上影响它的效果,因此我们往往利用网格搜索来共同调整三个对多项式核函数有影响的参数。依然利用乳腺癌数据集:
#ploy调参from sklearn.model_selection import StratifiedShuffleSplitfrom sklearn.model_selection import GridSearchCVtime0 = time()#从前面的代码可知,degree为1时最好,以是只用调别的两个#两个参数就用网课搜索来做gamma_range = np.logspace(-10,1,20)#coef不能为负数coef0_range = np.linspace(0,5,10)#创建一个字典param_grid = dict(gamma = gamma_range ,coef0 = coef0_range)cv = StratifiedShuffleSplit(n_splits=5, test_size=0.3, random_state=420)grid = GridSearchCV(SVC(kernel = "poly",degree=1,cache_size=5000), param_grid=param_grid, cv=cv)grid.fit(X, y)print("The best parameters are %s with a score of %0.5f" % (grid.best_params_, grid.best_score_))print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))#The best parameters are {'coef0': 0.0, 'gamma': 0.18329807108324375} with a score of 0.96959#00:07:088303虽然比调参前略有进步,但依然没有凌驾线性核函数核rbf的结果。可见,如果最初选择核函数的时候,你就发现多项式的结果不如rbf和线性核函数,那就不要挣扎了,试试看调整rbf或者直接利用线性;
7.2.3 硬隔断与软隔断:重要参数C
(1) SVM在软隔断数据上的推广
看网课,pdf
(2) 重要参数C
用于权衡”训练样本的正确分类“与”决策函数的边际最大化“两个不可同时完成的目标,希望找出一个平衡点来让模型的效果最佳;
在现实利用中,C和核函数的相关参数(gamma,degree等等)们搭配,往往是SVM调参的重点。与gamma差别,C没有在对偶函数中出现,并且是明确了调参目标的,以是我们可以 明确我们毕竟是否需要训练集上的高正确度来调整C的方向。默认环境下C为1,通常来说这都是一个合理的参数。 如果我们的数据很嘈杂,那我们往往减小C。固然,我们也可以利用网格搜索或者学习曲线来调整C的值
#重要参数C#调线性核函数score = []C_range = np.linspace(0.01,30,50)for i in C_range: clf = SVC(kernel="linear",C=i,cache_size=5000).fit(Xtrain,Ytrain) score.append(clf.score(Xtest,Ytest))print(max(score), C_range[score.index(max(score))])plt.plot(C_range,score)plt.show()0.9766081871345029 1.2340816326530613
可以看出,正确率就是原来啥都没干的值。并且从学习曲线可以看出越背面值越低,根本可以确定这个就是最大值;
#换rbfscore = []C_range = np.linspace(0.01,30,50)for i in C_range: clf = SVC(kernel="rbf",C=i,gamma = 0.012742749857031322,cache_size=5000).fit(Xtrain,Ytrain) score.append(clf.score(Xtest,Ytest)) print(max(score), C_range[score.index(max(score))])plt.plot(C_range,score)plt.show()0.9824561403508771 6.130408163265306
可以看出10之后就下降之后并保持平稳,一开始那里则是疯狂上升,那么再细化:
#进一步细化score = []C_range = np.linspace(5,7,50)for i in C_range: clf = SVC(kernel="rbf",C=i,gamma = 0.012742749857031322,cache_size=5000).fit(Xtrain,Ytrain) score.append(clf.score(Xtest,Ytest)) print(max(score), C_range[score.index(max(score))])plt.plot(C_range,score)plt.show()0.9824561403508771 5.938775510204081
此时,我们找到了乳腺癌数据集上的最优解:rbf核函数下的98.24%的正确率。我们还可以用交叉验证来进一步优化;
7.3 总结
向量机的运用要对数据举行无量纲化预处置惩罚,可以对结果有着很大的提升。 |