scikit-learn中SVM的算法库分为两类,一类是分类的算法库,包括SVC, NuSVC,和LinearSVC 3个类。另一类是回归算法库,包括SVR, NuSVR,和LinearSVR 3个类。相关的类都包裹在sklearn.svm模块之中。
对于SVC, NuSVC,和LinearSVC 3个分类的类,SVC和 NuSVC差不多,区别仅仅在于对损失的度量方式不同,而LinearSVC从名字就可以看出,他是线性分类,也就是不支持各种低维到高维的核函数,仅仅支持线性核函数,对线性不可分的数据不能使用。
同样的,对于SVR, NuSVR,和LinearSVR 3个回归的类, SVR和NuSVR差不多,区别也仅仅在于对损失的度量方式不同。LinearSVR是线性回归,只能使用线性核函数。
我们使用这些类的时候,如果有经验知道数据是线性可以拟合的,那么使用LinearSVC去分类 或者LinearSVR去回归,它们不需要我们去慢慢的调参去选择各种核函数以及对应参数, 速度也快。如果我们对数据分布没有什么经验,一般使用SVC去分类或者SVR去回归,这就需要我们选择核函数以及对核函数调参了。
什么特殊场景需要使用NuSVC分类 和 NuSVR 回归呢?如果我们对训练集训练的错误率或者说支持向量的百分比有要求的时候,可以选择NuSVC分类 和 NuSVR 。它们有一个参数来控制这个百分比。
下面主要讨论LinearSVC与SVC。
svm.LinearSVC
class sklearn.svm.LinearSVC(penalty='l2', loss='squared_hinge', dual=True, tol=0.0001, C=1.0, multi_class='ovr', fit_intercept=True, intercept_scaling=1, class_weight=None, verbose=0, random_state=None, max_iter=1000)
主要超参数
- C:目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0; 一般来说,如果噪音点较多时,C需要小一些。
- loss :指定损失函数 .有‘hinge’和‘squared_hinge’两种可选,前者又称L1损失,后者称为L2损失,默认是是’squared_hinge’,其中hinge是SVM的标准损失,squared_hinge是hinge的平方。
- penalty : 仅仅对线性拟合有意义,可以选择‘l1’即L1正则化 或者 ‘l2’即L2正则化。默认是L2正则化,如果我们需要产生稀疏话的系数的时候,可以选L1正则化,这和线性回归里面的Lasso回归类似。
- dual :选择算法来解决对偶或原始优化问题。如果我们的样本量比特征数多,此时采用对偶形式计算量较大,推荐dual设置为False,即采用原始形式优化
- tol :(default = 1e - 3): svm结束标准的精度;
- multi_class:如果y输出类别包含多类,用来确定多类策略, ovr表示一对多,“crammer_singer”优化所有类别的一个共同的目标 .'crammer_singer'是一种改良版的'ovr',说是改良,但是没有比’ovr‘好,一般在应用中都不建议使用。如果选择“crammer_singer”,损失、惩罚和优化将会被被忽略。 'ovr'的分类原则是将待分类中的某一类当作正类,其他全部归为负类,通过这样求取得到每个类别作为正类时的正确率,取正确率最高的那个类别为正类;‘crammer_singer’ 是直接针对目标函数设置多个参数值,最后进行优化,得到不同类别的参数值大小。
- class_weight :指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策过于偏向这些类别。这里可以自己指定各个样本的权重,或者用“balanced”,如果使用“balanced”,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的"None"
- verbose:跟多线程有关
svm.SVC
class sklearn.svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='auto', 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)
主要超参数
- C: 同LinearSVC
- kernel:参数选择有RBF, Linear, Poly, Sigmoid, 默认的是”RBF”; ‘linear’即线性核函数, ‘poly’即多项式核函数, ‘rbf’即高斯核函数, ‘sigmoid’即sigmoid核函数。如果选择了这些核函数, 对应的核函数参数在后面有单独的参数需要调。默认是高斯核'rbf'。
- degree:如果我们在kernel参数使用了多项式核函数 'poly',那么我们就需要对这个参数进行调参。这个参数对应 \(K(x,z)=(γx∙z+r)d\) 中的d。默认是3。一般需要通过交叉验证选择一组合适的γ,r,d
- gamma:核函数的系数(‘Poly’, ‘RBF’ and ‘Sigmoid’), 默认是gamma = \(\frac{1}{特征维度}\); 如果我们在kernel参数使用了多项式核函数 'poly',高斯核函数‘rbf’, 或者sigmoid核函数,那么我们就需要对这个参数进行调参。多项式核函数中这个参数对应 \(K(x,z)=(γx∙z+r)d\) 中的γ。一般需要通过交叉验证选择一组合适的γ,r,d;
高斯核函数中这个参数对应 \(K(x,z)=exp(−γ||x−z||2)\) 中的γ。一般需要通过交叉验证选择合适的γ
sigmoid核函数中这个参数对应 \(K(x,z)=tanh(γx∙z+r)\) 中的γ。一般需要通过交叉验证选择一组合适的γ,r ;
γ默认为'auto',即 \(\frac{1}{特征维度}\) - coef0:核函数中的独立项,’RBF’ and ‘Poly’有效; coef0默认为0.如果我们在kernel参数使用了多项式核函数 'poly',或者sigmoid核函数,那么我们就需要对这个参数进行调参。
多项式核函数中这个参数对应 \(K(x,z)=(γx∙z+r)d\) 中的r。一般需要通过交叉验证选择一组合适的γ,r,d;
sigmoid核函数中这个参数对应 \(K(x,z)=tanh(γx∙z+r)\) 中的r。一般需要通过交叉验证选择一组合适的γ,r; - probablity: 可能性估计是否使用(true or false);
- shrinking:是否进行启发式;
- tol(default = 1e - 3): svm结束标准的精度;
- cache_size: 制定训练所需要的内存(以MB为单位); 在大样本的时候,缓存大小会影响训练速度,因此如果机器内存大,推荐用500MB甚至1000MB。默认是200,即200MB.
- class_weight: 同LinearSVC
- verbose: 同LinearSVC
- max_iter: 最大迭代次数,default = 1, if max_iter = -1, no limited;
- decision_function_shape : ‘ovo’ 一对一, ‘ovr’ 多对多 or None 无, default=None
- random_state :用于概率估计的数据重排时的伪随机数生成器的种子。
调参建议
一般推荐在做训练之前对数据进行归一化,当然测试集中的数据也需要归一化。。
在特征数非常多的情况下,或者样本数远小于特征数的时候,使用线性核,效果已经很好,并且只需要选择惩罚系数C即可。
- 在选择核函数时,如果线性拟合不好,一般推荐使用默认的高斯核'rbf'。这时我们主要需要对惩罚系数C和核函数参数γ进行艰苦的调参,通过多轮的交叉验证选择合适的惩罚系数C和核函数参数γ。
- 理论上高斯核不会比线性核差,但是这个理论却建立在要花费更多的时间来调参上。所以实际上能用线性核解决问题我们尽量使用线性核。
-
degree越大,分类器越灵活。太大会出现过拟合
常见问题
- Q:C对线性核的SVM有多大影响?
A:C参数告诉SVM模型,你有多希望避免对每个训练样本的错误分类。对于较大的C值,如果超平面能够更好地获得正确分类所有样本点,那么该模型将选择一个更小的间隔超平面。相反,较小的C值将导致模型寻找更大分隔的超平面,即使这个超平面错误地划分了很多的点。C越大,越要尽可能的考虑错误点(也就是说,尽量不要分错),导致的结果是,误分类尽可能越小,但分界距离也变小了。坏处很明显,若干错误的“离群点”会对分界面的位置方向影响很大。
在支持向量机中,你的目标是找到两个东西:1)具有最大最小间隔的超平面;2)能够正确分隔尽可能多实例的超平面。问题是你不可能同时得到这两种东西。C参数决定了你对后者的期望有多大。下面画了一个小例子来说明这一点。左边是一个很低的C,这就得到了一个很大的最小间隔(紫色)。然而,这要求我们忽略未能正确分类的蓝色圆离群值。右边是C较高时的情况,你不会忽视离群值,最终得到一个更小的间隔。
那么哪一个分类器是更好的呢?这取决于你预测的数据是什么样子的,当然大多数情况下你并不知道。如果数据是这样的:
那么适当跳大C是更好的选择。如果你的数据是这样的:
那么使用较小的C会好一些。 Q:LinearSVC与使用线性核的SVC的区别
A:sklearn把LinearSVC叫做SVM,而实际上LinearSVC的目标是最小化合页损失的平方(一个超参),而不仅仅是合页损失。此外,LinearSVC还引入了惩罚正则项,这是纯SVM没有的。所以不能说LinearSVC就是线性核的SVC。那么用哪一个呢?这还是得具体问题具体分析。由于没有免费午餐定理,所以不能说哪个损失函数是最好的。- Q:使用LinearSVC时,为何调整了参数C后,分类的效果没有明显的变化?
A:首先明确两个重要的事实。1)你用的是线性核;2)您的训练数据是线性可分的,“训练集上没有错误”。
有了这两个事实,如果C值在合理范围内发生变化,最优超平面会在由支持向量形成的间隔内移动。直观上,假设训练数据的间隔较小,且间隔内也没有测试数据点,则在间隔内的最优超平面的偏移不会影响测试集的分类误差。
尽管如此,如果你设置C=0,那么SVM就会忽略这些错误,只尝试最小化权值(w)的平方和,也许你会在测试集中得到不同的结果。 -
Q:我们该使用哪种核函数?
A:和数据相关。 可以尝试。尝试顺序一般:先线性核,然后再看通过使用非线性核能否提高。通常,如果数据是高维的,但只有很少的训练样本数,非线性核会导致过拟合。
除此之外,感兴趣的还可以参考这个:https://stats.stackexchange.com/questions/18030/how-to-select-kernel-for-svm?rq=1Reference
- what-is-the-influence-of-c-in-svms-with-linear-kernel
- slides:SVC实践指南
- Comparison of L1 and L2 Support Vector Machines
- scikit-learn中的SVM使用指南
- scikit-learn 支持向量机算法库使用小结