机器学习算法实战:支持向量机算法SVM如何完成调参?python实现

专栏推荐

正文

我们构造svm模型的时候是有如下的参数可以设置的。

SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,

decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',

max_iter=-1, probability=False, random_state=None, shrinking=True,

tol=0.001, verbose=False)

我们先来看一下这些参数的含义:

(1)C: 目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0;

(2)kernel:参数选择有RBF(高斯核), Linear(线性核函数), Poly(多项式核函数), Sigmoid(sigmoid核函数), 默认的是"RBF";

(3)degree:如果kernel使用多项式核函数, degree决定了多项式的最高次幂;

(4)gamma:核函数的系数('Poly', 'RBF' and 'Sigmoid'), 默认是gamma = 1 / n_features;

(5)coef0:核函数中的独立项,'RBF' and 'sigmoid'有效;

(6)probablity: 可能性估计是否使用(true or false);

(7)shrinking:是否进行启发式;

(8)tol(default = 1e - 3): svm结束标准的精度;

(9)cache_size: 制定训练所需要的内存(以MB为单位),在大样本的时候,缓存大小会影响训练速度,因此如果机器内存大,推荐用500MB甚至1000MB。默认是200,即200MB.

(10)class_weight: 指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策过于偏向这些类别。这里可以自己指定各个样本的权重,或者用"balanced",如果使用"balanced",则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的"None"(11)verbose: 跟多线程有关,不大明白啥意思具体;

(12)max_iter: 最大迭代次数,default = 1, if max_iter = -1, no limited;

(13)decision_function_shape : 分类决策

'ovo' 一对一, 'ovr' 多对多 or None 无, default=ovr

OvR(one ve rest)的思想很简单,无论你是多少元分类,我们都可以看做二元分类。具体做法是,对于第K类的分类决策,我们把所有第K类的样本作为正例,除了第K类样本以外的所有样本都作为负例,然后在上面做二元分类,得到第K类的分类模型。其他类的分类模型获得以此类推。

OvO(one-vs-one)则是每次每次在所有的T类样本里面选择两类样本出来,不妨记为T1类和T2类,把所有的输出为T1和T2的样本放在一起,把T1作为正例,T2作为负例,进行二元分类,得到模型参数。我们一共需要T(T-1)/2次分类。

从上面的描述可以看出OvR相对简单,但分类效果相对略差(这里指大多数样本分布情况,某些样本分布下OvR可能更好)。而OvO分类相对精确,但是分类速度没有OvR快。一般建议使用OvO以达到较好的分类效果。

(14)random_state :用于概率估计的数据重排时的伪随机数生成器的种子。

1)线性核函数(Linear Kernel)表达式为:K(x,z)=xzK(x,z)=x∙z,就是普通的内积,LinearSVC 和 LinearSVR 只能使用它。

2) 多项式核函数(Polynomial Kernel)是线性不可分SVM常用的核函数之一,表达式为:K(x,z)=(γxz+r)dK(x,z)=(γx∙z+r)d ,其中,γ,r,dγ,r,d都需要自己调参定义,比较麻烦。

3)高斯核函数(Gaussian Kernel),在SVM中也称为径向基核函数(Radial Basis Function,RBF),它是libsvm默认的核函数,当然也是scikit-learn默认的核函数。表达式为:K(x,z)=exp(−γ||xz||2)K(x,z)=exp(−γ||x−z||2), 其中,γγ大于0,需要自己调参定义。

4)Sigmoid核函数(Sigmoid Kernel)也是线性不可分SVM常用的核函数之一,表达式为:K(x,z)=tanhγxz+r)K(x,z)=tanh(γx∙z+r), 其中,γ,rγ,r都需要自己调参定义。

虽然有这么多的核函数,但是实际上我们常用的只有两个一个是线性核函数,还是有一个是高斯核函数,原因是它们的效果往往最好,调参数量也比较少,不是很麻烦。当我们使用线性核函数的时候我们的主要的调参的目标就是C,当我们使用高斯核函数的时候我们的主要的调参的目标就是C和gamma。

要就是调节两个参数,一个是C,一个是gamma

C是惩罚系数也就是松弛变量的系数。它在优化函数里主要是平衡支持向量的复杂度和误分类率这两者之间的关系,可以理解为正则化系数。当比较大时,我们的损失函数也会越大,这意味着我们不愿意放弃比较远的离群点。这样我们会有更加多的支持向量,也就是说支持向量和超平面的模型也会变得越复杂,也容易过拟合。反之,当比较小时,意味我们不想理那些离群点,会选择较少的样本来做支持向量,最终的支持向量和超平面的模型也会简单。scikit-learn中默认值是1。

另一个超参数是RBF核函数的参数。回忆下RBF 核函数 ,主要定义了单个样本对整个分类超平面的影响,当比较大时,单个样本对整个分类超平面的影响比较小,不容易被选择为支持向量,或者说整个模型的支持向量也会少。scikit-learn中默认值是'auto'

实际上我们最常见的就是调整这两个参数。下面案例就是实际使用高斯核函数时的调参的案例。它使用sklearn封装好的调参库进行网格调参,也叫暴力调参。

from sklearn import svm
 from sklearn.model_selection import GridSearchCV
 from sklearn import metrics
 
 import numpy as np
 import pandas as pd
 import scipy.io as sio
 
mat = sio.loadmat('ex6data3.mat')
print(mat.keys())
training = pd.DataFrame(mat.get('X'), columns=['X1', 'X2'])
training['y'] = mat.get('y')
cv = pd.DataFrame(mat.get('Xval'), columns=['X1', 'X2'])
cv['y'] = mat.get('yval')
candidate = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 100]
combination = [(C, gamma) for C in candidate for gamma in candidate]
 
 
if __name__ == "__main__":
 parameters = {'C': candidate, 'gamma': candidate}
 svc = svm.SVC()
 clf = GridSearchCV(svc, parameters, n_jobs=-1)
 clf.fit(training[['X1', 'X2']], training['y'])
 print (clf.best_params_)
 print (clf.best_score_)
 ypred = clf.predict(cv[['X1', 'X2']])
 print(metrics.classification_report(cv['y'], ypred))
举报
评论 0