在支持向量机(以下简称SVM)的核函数中,高斯核(以下简称RBF)是最常用的,从理论上讲,RBF一定不比线性核函数差,但是在实际应用中,却面临着几个重要的超参数的调优问题。如果调的不好,可能比线性核函数还要差。所以我们实际应用中,能用线性核函数得到较好效果的都会选择线性核函数。如果线性核不好,我们就需要使用RBF,在享受RBF对非线性数据的良好分类效果前,我们需要对主要的超参数进行选取。本文我们就对scikit-learn中 SVM RBF的调参做一个小结。
如果是SVM分类模型,这两个超参数分别是惩罚系数和RBF核函数的系数。当然如果是nu-SVC的话,惩罚系数C代替为分类错误率上限nu, 由于惩罚系数C和分类错误率上限nu起的作用等价,因此本文只讨论带惩罚系数C的分类SVM**
1.1 SVM分类模型
###(1) 惩罚系数惩罚系数C即上一篇里讲到的松弛变量ξ的系数。它在优化函数里主要是平衡支持向量的复杂度和误分类率这两者之间的关系,可以理解为正则化系数。
当惩罚系数C比较大时,我们的损失函数也会越大,这意味着我们不愿意放弃比较远的离群点。这样我们会有更加多的支持向量,也就是说支持向量和超平面的模型也会变得越复杂,也容易过拟合。
当惩罚系数C比较小时,意味我们不想理那些离群点,会选择较少的样本来做支持向量,最终的支持向量和超平面的模型也会简单。scikit-learn中默认值是1。
(2)RBF核函数的系数
另一个超参数是RBF核函数的参数。回忆下RBF 核函数
γ主要定义了单个样本对整个分类超平面的影响。当γ比较小时,单个样本对整个分类超平面的影响比较小,不容易被选择为支持向量
当γ比较大时,单个样本对整个分类超平面的影响比较大,更容易被选择为支持向量**,或者说整个模型的支持向量也会多。scikit-learn中默认值是1/n_features**
(3)惩罚系数和RBF核函数的系数
如果把惩罚系数和RBF核函数的系数一起看:当C比较大、 γ比较大时,会有更多的支持向量,模型会比较复杂,较容易过拟合
当C比较小、γ比较小时,模型会变得简单,支持向量的个数会少
1.2 SVM回归模型
SVM回归模型的RBF核比分类模型要复杂一点,因为此时除了惩罚系数C和RBF核函数的系数γ之外,还多了一个损失距离度量ϵ。如果是nu-SVR的话,损失距离度量ϵ代替为分类错误率上限nu,由于损失距离度量ϵ和分类错误率上限nu起的作用等价,因此本文只讨论带距离度量ϵ的回归SVM。对于惩罚系数C和RBF核函数的系数γ,回归模型和分类模型的作用基本相同。
对于损失距离度量ϵ,它决定了样本点到超平面的距离损失.当ϵ比较大时,损失较小,更多的点在损失距离范围之内,模型较简单;当ϵ比较小时,损失函数会较大,模型也会变得复杂;scikit-learn中默认值是0.1
惩罚系数C、RBF核函数的系数γ和损失距离度量ϵ一起看当C比较大、 γ比较大、ϵ比较小时,会有更多的支持向量,模型会比较复杂,容易过拟合一些;
当C比较小、γ比较小、ϵ比较大时**,模型会变得简单,支持向量的个数会少
2 SVM RBF 主要调参方法
对于SVM的RBF核,主要的调参方法都是交叉验证。具体在scikit-learn中,主要是使用网格搜索,即GridSearchCV类。
当然也可以使用cross_val_score类来调参,但是个人觉得没有GridSearchCV方便。本文只讨论用GridSearchCV**来进行SVM的RBF核的调参。
将GridSearchCV类用于SVM RBF调参时要注意的参数有:1. estimator :即模型,此处就是带高斯核的SVC或者SVR
2. param_grid:即要调参的参数列表。 比如用SVC分类模型的话,那么param_grid可以定义为{"C":[0.1, 1, 10], "gamma": [0.1, 0.2, 0.3]},这样就会有9种超参数的组合来进行网格搜索,选择一个拟合分数最好的超平面系数。
3. cv: S折交叉验证的折数,即将训练集分成多少份来进行交叉验证。默认是3。如果样本较多的话,可以适度增大cv的值。
网格搜索结束后,可以得到最好的模型estimator、param_grid中最好的参数组合、最好的模型分数。
下面用一个具体的分类例子来观察SVM RBF调参的过程。
3 SVM RBF分类调参的例子import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets, svm
from sklearn.svm import SVC
from sklearn.datasets import make_moons, make_circles, make_classification
接着生成一些随机数据来分类,为了数据难一点,加入了一些噪音,生成数据的同时把数据归一化。X, y = make_circles(noise=0.2, factor=0.5, random_state=1)
from sklearn.preprocessing import StandardScaler
X = StandardScaler().fit_transform(X)
数据可视化如下:from matplotlib.colors import ListedColormap
cm = plt.cm.RdBu
cm_bright = ListedColormap(['#FF0000', '#0000FF'])
ax = plt.subplot()
ax.set_title("Input data")
ax.scatter(X[:, 0], X[:, 1], c=y, cmap=cm_bright)
ax.set_xticks(