机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)

先上公式推导吓吓萌新。。。嘻嘻

上图中两个决策边界(虚线)的间隔为\frac{2}{||w||},可以把它看做求两条平行直线的距离,只是这里是超直线罢了,

例如:两平行线方程分别是:Ax+By+C1=0和Ax+By+C2=0

则它们之间的距离d=\frac{C1-C2}{\sqrt{A^2+B^2}},这里的x,y写成向量形式就是x={x,y},w={A,B}.

更多详细推导原理:https://blog.csdn.net/qq_30815237/article/details/86553430


 机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第1张图片

官网地址:https://scikit-learn.org/stable/modules/classes.html#module-sklearn.svm

简介:

     支持向量机(简称SVM)是一个功能强大并且全面的机器学习模型,它能够执行线性或非线性分类、回归,甚至是异常值检测任务。它是机器学习领域最受欢迎的模型之一。SVM特别适用于中小型复杂数据集的分类。

线性SVM分类

     图中的实线代表SVM分类器的决策边界,这条线不仅分离了两个类别,并且尽可能远离了最近的训练实例。你可以将SVM分类器视为在类别之间拟合可能的最宽的街道(平行的虚线所示)。因此这也叫作大间隔分类(large margin classification)。

                                 机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第2张图片

   注意,在街道以外的地方增加更多训练实例,不会对决策边界产生影响:也就是说它完全由位于街道边缘的实例所决定(或者称之为“支持”)。这些实例被称为支持向量(在图中已圈出)。

    SVM对特征的缩放非常敏感,如图5-2所示,在左图中,垂直刻度比水平刻度大得多,因此可能的最宽的街道接近于水平。在特征缩放(例如使用Scikit-Learn的StandardScaler)后,决策边界看起来好很多(见右图)。

                  机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第3张图片

硬间隔分类

   如果我们严格地让所有实例都不在街道上,并且位于正确的一边,这就是硬间隔分类。

    硬间隔分类有两个主要问题,首先,它只在数据是线性可分离的时候才有效;其次,它对异常值非常敏感。下图显示了有一个额外异常值的鸢尾花数据:左图的数据根本找不出硬间隔,而右图最终显示的决策边界,可能无法很好地泛化。

             机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第4张图片

软间隔分类

       要避免这些问题,最好使用更灵活的模型。目标是尽可能在保持街道宽阔和限制间隔违例(即位于街道之上,甚至在错误的一边的实例)之间找到良好的平衡,这就是软间隔分类。

       在Scikit-Learn的SVM类中,可以通过超参数C来控制这个平衡:C值越小,则街道越宽,但是间隔违例也会越多。下图显示了在一个非线性可分离数据集上,两个软间隔SVM分类器各自的决策边界和间隔。

       右边使用了高C值,分类器的间隔违例较少,但是间隔也较小。

       左边使用了低C值,间隔大了很多,但是位于街道上的实例也更多。看起来第二个分类器的泛化效果更好,因为大多数间隔违例实际上都位于决策边界正确的一边,所以即便是在该训练集上,它做出的错误预测也会更少。

 机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第5张图片

SVM模型过度拟合,可以试试通过降低C,加强正则化。

使用LinearSVC类实现软间隔:

#损失函数loss="hinge"就是表示采用软间隔
##C表示正则化程度,与alpha相反。C越大,正则程度越低,边界更倾斜,margin越小

from sklearn.svm import LinearSVC
from sklearn import datasets
import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

iris=datasets.load_iris()
X=iris["data"][:,(2,3)]
y=(iris["target"]==2).astype(np.float64)
svm_clf=Pipeline([
        ("scaler",StandardScaler()),
        ("linear_svc",LinearSVC(C=1,loss="hinge",random_state=42)),       
    ])
svm_clf.fit(X,y)
svm_clf.predict([[5.5, 1.7]])

out:array([1.])#与Logistic回归分类器不同的是,SVM分类器不会输出每个类别的概率。

使用LinearSVC类,确保超参数loss设置为"hinge",因为它不是默认值 .

y=(iris["target"]==2).astype(np.float64):说明:

iris["target"]==2,print之后其实是[True True False ...],那么X[y==0],就X的前三个元素而言,分别代表返回(包含),返回(包含),不返回(不包含);astype(np.float64)用于将其转化为float型,True为“1”,False为“0”。

  那么X[y==0, 0]中,第二个0代表什么意思呢?y==1解决了行中那些返回(那些为true的返回),右边的那个数字代表就是返回那一列,0,代表返回的是第一列,就是上面那个1,4,1.4...5.1;与之类似对于“iris["data"][:, (2, 3)]”这个写法,代表列是要返回第三列和第四列。

svm.clf和scaler有几个参数需要说明:

#权重系数w
svm_clf1.coef_
#截距
svm_clf1.intercept_
#均值
scaler.mean_
#缩放比例
scaler.scale_

     除了使用LinearSVC类,还可以选择SVC类,使用SVC(kernel="linear",C=1),但是这要慢得多,特别是对于大型训练集而言,因此不推荐使用。

     另一个选择是SGDClassifier类,使用SGDClassifier(loss="hinge",alpha=1/(m*C))   [损失函数不再是“l1”“l2”]。这适用于常规随机梯度下降来训练线性SVM分类器。它不会像LinearSVC类那样快速收敛,但是对于内存处理不了的大型数据集(核外训练)或是在线分类任务,它非常有效。

hinge损失函数 

    对线性SVM分类器来说,方法之一是使用梯度下降,使从原始问题导出的成本函数最小化。线性SVM分类器成本函数:

                       
     成本函数中的第一项会推动模型得到一个较小的权重向量w,从而使间隔更大。
第二项则计算全部的间隔违例。如果没有一个示例位于街道之上,并且都在街道正确的一边,那么这个实例的间隔违例为0;如不然,则该实例的违例大小与其到街道正确一边的距离成正比。所以将这个项最小化,能够保证模型使间隔违例尽可能小,也尽可能少。

       函数max(0,1-t)被称为hinge损失函数(如下图所示)。当t≥1时,函数等于0。如果t<1,其导数(斜率)等于-1,如果t>1,则导数为0,t=1时,函数不可导。但是,在t=0处可以使用任意次导数(即-1到0之间的任意值),你还是可以使用梯度下降,就跟Lasso回归一样。

                               机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第6张图片

非线性SVM分类

      虽然在许多情况下,线性SVM分类器是有效的,但有很多数据集远不是线性可分离的。处理非线性数据集的方法之一是添加更多特征,比如多项式特征,某些情况下,这可能导致数据集变得线性可分离。

    要使用Scikit-Learn实现这个想法,可以搭建一条流水线:一个PolynomialFeatures转换器,接着一个StandardScaler,然后是LinearSVC.

from sklearn.datasets import make_moons
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures

polynomial_svm_clf = Pipeline([
        ("poly_features", PolynomialFeatures(degree=3)),
        ("scaler", StandardScaler()),
        ("svm_clf", LinearSVC(C=10, loss="hinge", random_state=42))
    ])

polynomial_svm_clf.fit(X, y)
y_pred = polynomial_svm_clf.predict(X) #Predict class labels for samples in X.
y_pred:
array([1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1,
       0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1,
       0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1,
       0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
       0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1], dtype=int64)

y_decision = polynomial_svm_clf.decision_function(X)  #自信分数Predict confidence scores for samples.

  机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第7张图片

分类结果:

        机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第8张图片        机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第9张图片

核函数

1、多项式核

  使用SVM时,有一个魔术般的数学技巧可以应用,这就是核技巧。这个技巧由SVC类来实现,LinearSVM类不支持核技巧,我们看看在卫星数据集上的测试:

poly100_kernel_svm_clf = Pipeline([
        ("scaler", StandardScaler()),
        ("svm_clf", SVC(kernel="poly", degree=10, coef0=100, C=5))
    ])
poly100_kernel_svm_clf.fit(X, y)

参数说明:

kernel : (default=’rbf’)。可选 ‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ or a callable

degree:表示多项式阶数,如果模型过度拟合,你应该降低多项式阶数;反过来,如果拟合不足,则可以尝试使之提升。

coef0: 超参数coef0控制的是模型受高阶多项式还是低阶多项式影响的程度。coef值越大,模型受高阶的影响越大。

C:正则系数。

不同参数会得到不同的决策边界,如下图所示:

机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第10张图片

2、高斯(径向基)RBF核函数

      解决非线性问题的另一种技术是添加相似特征。这些特征经过相似函数计算得出,相似函数可以测量每个实例与一个特定地标(landmark)之间的相似度。接下来,我们采用高斯径向基函数(RBF)作为相似函数:

                                             

其中:l代表函数的对称轴。\gamma控制函数的宽窄,越大,,下降越快,曲线越窄。

      以前面提到过的一维数据集为例,在x_{1}=-2x_{1}=1处添加两个地标(左图红色圆圈),例如,我们看实例 x= -1:它与
第一个地标的距离为1,与第二个地标的距离为2。因此它的新特征为:

                     x2 =eps(-0.3×1^2 )≈0.74,x3 =eps(-0.3×2^2 )≈0.30。

(就是以点x做一条垂直x1轴的直线,和图中绿色和蓝色曲线的交点的纵坐标的值,作为新的特征值,图中绿色和蓝色的钟型曲线即为高斯径向基函数曲线)

右图显示了转换后的数据集(去除了原始特征),现在你可以看出,数据呈线性可分离的。

机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第11张图片

怎么选择地标呢?

     最简单的方法是在数据集里每一个实例的位置上创建一个地标。这会创造出许多维度,因而也增加了转换后的训练集线性可分离的机会。缺点是,一个有m个实例n个特征的训练集会被转换成一个m个实例m个特征的训练集(假设抛弃了原始特征)

高斯RBF的实现:

from sklearn.svm import SVC

gamma1, gamma2 = 0.1, 5
C1, C2 = 0.001, 1000
hyperparams = (gamma1, C1), (gamma1, C2), (gamma2, C1), (gamma2, C2)

svm_clfs = []
for gamma, C in hyperparams:
    rbf_kernel_svm_clf = Pipeline([
            ("scaler", StandardScaler()),
            ("svm_clf", SVC(kernel="rbf", gamma=gamma, C=C))
        ])
    rbf_kernel_svm_clf.fit(X, y)
    svm_clfs.append(rbf_kernel_svm_clf)

gamma参数:

图中r表示gamma参数,

机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第12张图片

   增加gamma值会使钟形曲线变得更窄,因此每个实例的影响范围随之变小:决策边界变得更不规则,开始围着单个实例绕弯。

    减小gamma值使钟形曲线变得更宽,因而每个实例的影响范围增大,决策边界变得更平坦。所以就像是一个正则化的超参数:模型过度拟合,就降低它的值,如果拟合不足则提升它的值(类似超参数C)。

       核函数的选择有一个经验法则是,永远先从线性核函数开始尝试(LinearSVC比SVC(kernel="linear")快得多),特别是训练集非常大或特征非常多的时候。如果训练集不太大,你可以试试高斯RBF核,大多数情况下它都非常好用。liblinear库为线性SVM实现了一个优化算法,LinearSVC正是基于该库的。这个算法不支持核技巧,不过它的训练时间复杂度大致为O(m×n)。SVC则是基于libsvm库的,这个库的算法支持核技巧,训练时间复杂度通常在O(m^2  ×n)和O(m^3  ×n)间.

                         机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第13张图片

正如开头图片中所示公式:

    SVM的计算主要集中在样本特征向量之间的点积运算,当我们扩展特征向量的维数时,计算量会飙升,例如对于数据xi,映射到特征空间就变成了φ(xi),然后在计算φ(xi)*φ(xj). 

     而SVM的一大巧妙之处就是映射后的特征空间数据点内积的计算( φ(xi)*φ(xj). )等价于低维空间数据点在映射函数对应的核函数中的计算.这大大降低了运算量。

核函数的价值在于它虽然也是将特征进行从低维到高维的转换,但核函数绝就绝在它事先在低维上进行计算,而将实质上的分类效果表现在了高维上,也就如上文所说的避免了直接在高维空间中的复杂计算。

具体可参见:https://blog.csdn.net/qq_30815237/article/details/86553430中的核函数部分。

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)

SVR参数    参数说明
C    默认值为1:错误分类样本的惩罚因子,C越大,惩罚力度越大,倾向于选择复杂的模型,减少错分样本,C越小,惩罚力度越小,倾向于选择简答的模型
kernel    默认选择径向基核函数’rbf ,也可选择’linear’,‘poly’,'sigmod’核函数,点击kernel参数说明
degree    默认为3次多项式, 在选择kernel='poly’时有效,degree决定了多项式的最高次幂
gamma    核函数的系数(‘Poly’, ‘RBF’ and ‘Sigmoid’), 默认是gamma = 1 / n_features ,n_features为样本原始特征数量
coef0    默认为0,kernel选择’rbf’ and 'poly’有效,代表核函数中的偏置项

原文:https://blog.csdn.net/qq_37007384/article/details/88410998 

1、线性核函数kernel=‘linear’      :         

采用线性核kernel='linear’的效果和使用sklearn.svm.LinearSVC实现的效果一样,但采用线性核时速度较慢,特别是对于大数据集,推荐使用线性核时使用LinearSVC

2、多项式核函数kernel=‘poly’  :

degree代表d,表示多项式的次数
gamma为多项式的系数,coef0代表r,表示多项式的偏置

3、径向基核函数kernel=‘rbf’   :

     可以将gamma理解为支持向量影响区域半径的倒数,gamma越大,支持向量影响区域越小,决策边界倾向于只包含支持向量,模型复杂度高,容易过拟合;gamma越小,支持向量影响区域越大,决策边界倾向于光滑,模型复杂度低,容易欠拟合;
gamma的取值非常重要,即不能过小,也不能过大

4、sigmod核函数kernel=‘sigmod’  :

coef0控制r,sigmod核函数是线性核函数经过tanh函数映射变化。

原文:https://blog.csdn.net/qq_37007384/article/details/88418256 


  SVM回归

       SVM不仅支持线性和非线性 分类,而且还支持线性和非线性回归。诀窍在于将目标反转一下:不再是尝试拟合两个类别之间可能的最宽的街道的同时限制间隔违例,SVM回归要做的是让尽可能多的实例位于街道间隔内,同时限制间隔违例(也就是不在街道间隔内的实例)

     街道的宽度由超参数ε控制。下图显示了用随机线性数据训练的两个线性SVM回归模型,一个间隔较大(ε=1.5),另一个间隔较小(ε=0.5)。

       机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第14张图片

1、使用LinearSVR类来执行线性SVM回归(LinearSVR类也是LinearSVC类的回归等价物):

LinearSVR训练速度与训练集的大小线性相关(跟LinearSVC一样)

from sklearn.svm import LinearSVR
svm_reg = LinearSVR(epsilon=1.5)
svm_reg.fit(X, y)

2、使用SVR类(支持核技巧)SVR类是SVC类的回归等价物:

SVR在训练集变大时,变得很慢(SVC也是一样)。

from sklearn.svm import SVR
svm_poly_reg = SVR(kernel="poly", degree=2, C=100, epsilon=0.1)
svm_poly_reg.fit(X, y)

下图所示:左图几乎没有正则化(C值很大),右图则过度正则化(C值很小)。

            机器学习实战5-sklearn训练SVM模型分类回归(make_moons数据集)_第15张图片

完整代码请下载:https://github.com/liuzheCSDN/Scikit-Learn

你可能感兴趣的:(机器学习)