• 支撑向量机


    1、支持向量机算法原理

    支持向量机(Support Vetor Machine,SVM)由Vapnik等人于1995年首先提出,在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并推广到人脸识别、行人检测和文本分类等其他机器学习问题中。

    SVM建立在统计学习理论的VC维理论和结构风险最小原理基础上,根据有限的样本信息在模型的复杂性和学习能力之间寻求最佳平衡,以求获得最好的推广能力。SVM可以用于数值预测和分类。

    SVM从基础到复杂可以分成三种分别为线性可分支持向量机(也就是硬间隔支持向量机Hard-margin Support Vector Machine)、线性支持向量机(软间隔支持向量机Soft-margin Support Vector Machine)、非线性支持向量机(核函数支持向量机Non-Linear Support Vector Machine)

    1.1硬间隔支持向量机理论推导

    线性可分定义:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mlz7wx9v-1668145316712)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108224403865.png)]

    如果一个数据集是线性可分的,那么一定有无数多个超平面将各个类别分开,在这么多超平面中,哪一个是最好的呢?将这条直线分别向两侧移动,直到包含蓝色和红色的点,移动到蓝色、红色点位置的直线就叫做支撑向量,如果一个直线的两个支撑向量的间隔(margin)最大,那这条直线就是将红色、蓝色点分开的最优分类直线。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VwpjtzBk-1668145316713)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108095511377.png)]

    支持向量机寻找的最优分类直线应满足:

    • 该直线分来了两类
    • 该直线最大化margin
    • 该直线处于间隔的中间,到所有支持向量距离相等

    margin=2d,所以最大化margin也就是最大化d。

    直线的Ax+By+C=0拓展到n维空间即theta*xb = 0,也可以写做wt是系数,b是截距,wt和b合在一起就是theta。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gw0lTq4w-1668145316713)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108100702547.png)]

    n维空间点到直线的距离为式1.1:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fIL1Wrnt-1668145316714)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108101318332.png)]

    红色点到直线的距离大于等于d,蓝色点到直线距离小于等于d,将红色点定义为分类结果为1,蓝色点定义为分类结果为-1,然后不等式两边同时除以d:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1tQIzg3-1668145316714)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108124236263.png)]

    将分母除开,用wT(d)表示wT除以d的结果,用bd表示b除以d的结果,则不等式可以转换为如下形式,且不等式表示的意思即左侧的直线方程:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDnCXxz0-1668145316715)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108125353940.png)]

    将wT(d)重命名为wT,bd重命名为b,以上的式子就变成了:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b5Vkm1vH-1668145316715)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108130011207.png)]

    注意,这时wT和b与刚开始公式中的wT和b不相同,但由于等式两边可以同时除以d,所以原wT * x + b的绝对值也等于1

    两个不等式左右两边同时乘以y的真实值,将两个不等式合为一个不等式1.2:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEBf7Ebc-1668145316715)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108141604360.png)]

    在支撑向量上有wT * x + b的绝对值等于1,在非支撑向量上有wT * x + b的绝对值大于1,我们求的是最大化支撑向量上点到直线wT * x + b = 0的距离d,n维空间点到直线的距离的式子如右侧如图所示,而在支撑向量上wT * x + b = 1,所以最大化间隔就变成了最大化w模的倒数,也就是最小化w模的值。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a5DB0QJn-1668145316716)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108144002397.png)]

    这是一个有条件的最优化问题,s.t.表示限定条件,式1.3:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UHN68vti-1668145316716)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108150217933.png)]

    无约束条件求极值点只需要求导,梯度为零就是局部极小或极大值点,有条件的最优化问题较为复杂,需要用到拉格朗日乘子法和KKT条件。

    在求取有约束条件的优化问题时,拉格朗日乘子法和KKT条件是非常重要的两个求取方法。
    
    1)对于等式约束的优化问题,可以应用拉格朗日乘子法去求取最优值;
    
    2)如果含有不等式约束,可以用于KKT条件去求取。
    
    当然,这两个方法求得的结果只是必要条件,只有当是凸函数的情况下,才能保证是充分必要条件。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.2 软间隔支持向量机理论推导

    硬间隔支持向量机默认样本数据集是完全线性可分的,即存在一个超平面能将两个类别的数据完全分开,在数据近似可分的时候,就不能使用硬间隔支持向量机了。解决该问题的思路是:允许出现一些错误,并且要使得间隔最大的同时,错误最小化。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GSLjFSnu-1668145316716)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221108222543960.png)]

    式1.3的限定条件左侧大于等于 1 是为了使得所有样本点都在正确的分类下,这也是为什么称为硬间隔的原因。而现在数据集无法用一个超平面完全分开,这时就需要允许部分数据集不满足上述约束条件。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DVRkJVFo-1668145316717)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221109072319005.png)]

    可以看到只要每个Delta i足够大,上面的n个不等式一定可以成立,当然我们还要限制每个Delta无限制的扩大,让它在一个合理的范围内。

    改造后的支持向量机优化版本式1.4:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2n6By7Fr-1668145316717)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221109072920304.png)]

    其中C>0称为惩罚参数,C值大的时候对误分类的惩罚增大,C值小的时候对误分类的惩罚减小,上图中的式子也被称为是svm的L1正则和L2正则。

    2、sklearn中的svm

    2.1 sklearn中的线性SVM

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import datasets
    from sklearn.preprocessing import StandardScaler
    from sklearn.svm import LinearSVC
    from sklearn.model_selection import train_test_split
    
    iris = datasets.load_iris()
    X = iris.data
    y = iris.target
    
    X = X[y<2,:2]
    y = y[y<2]
    
    # plt.scatter(X[y==0,0],X[y==0,1])
    # plt.scatter(X[y==1,0],X[y==1,1])
    # plt.show()
    
    X_train,X_test,y_train,y_test = train_test_split(X, y)
    
    standard = StandardScaler()
    standard.fit(X_train)
    X_train_standard = standard.transform(X_train)
    X_test_standard = standard.transform(X_test)
    
    # 线性支持向量机解决分类问题LinearSVC
    # C就是公式中的惩罚参数,C越大越接近硬间隔支持向量机
    svc = LinearSVC(C=1e8)
    svc.fit(X_train_standard,y_train)
    print(svc.coef_)
    print(svc.intercept_)
    
    # 当C过小,Delta可以超出合理范围的大,导致允许过多的预测错误出现,使模型预测准确度下降
    print(svc.score(X_test_standard, y_test))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.2 线性svm多项式特征理论推导

    在如下图分类问题中,如果我们坚持分开两类的必须是直线,那么无论我们怎么取这条直线,预测的结果都不太准确。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZO4tbuDC-1668145316718)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110221200396.png)]

    这时候需要从低维映射到高维,使问题在高维度中重新变成线性可分问题。如下图左侧四个点在二维空间中线性不可分:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rO5jQzuj-1668145316718)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110222429366.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hIFVeiB0-1668145316718)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110222356399.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-82LPHG4P-1668145316719)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110222625659.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JzO4DlNp-1668145316719)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110222908613.png)]

    根据计算结果我们可以看到在五维空间,问题变的线性可分了。

    定理:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8TsMIBP5-1668145316719)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110223041596.png)]

    这个定理告诉我们将训练样本由低维映射到高维,可以增大线性可分的概率。

    如果我们将X映射为φ(X),式1.4转换成式1.5,这里有一个隐含的前提条件,在低维问题中wi与Xi维度相同,在高维问题中w与φ(X)维度相同,可以看到高维问题的解法与低维完全类似,都可以利用凸优化理论完成支持向量机的求解。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l9JNsDMj-1668145316720)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110225221025.png)]

    2.3 LinearSVC使用多项式特征

    编写PolynomialSVC.py文件

    from sklearn.preprocessing import PolynomialFeatures,StandardScaler
    from sklearn.pipeline import Pipeline
    from sklearn.svm import LinearSVC
    
    def PolynomialSVC(degree=2, C=1.):
        return Pipeline([
            ('poly', PolynomialFeatures(degree=degree)),
            ('std_standar', StandardScaler()),
            ('svc', LinearSVC(C=C))
        ])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试代码:

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import datasets
    from sklearn.model_selection import train_test_split
    from common.PolynomialSVC import PolynomialSVC
    from sklearn.preprocessing import PolynomialFeatures,StandardScaler
    
    
    # 默认生成100条包含两个特征的数据,默认是规则的图形,添加noise噪音可以理解为标准差
    X,y = datasets.make_moons(noise=0.1)
    
    X_train,X_test,y_train,y_test = train_test_split(X, y)
    # 使用Pipeline顺序执行PolynomialFeatures、StandardScaler、LinearSVC预测结果不好,
    # 应该由于PolynomialSVC中LinearSVC接收到的X_train经过了PolynomialFeatures添加多项式,StandardScaler归一化
    # 而X_test计算score时没有经过这两步,所以预测结果不准确
    poly_svc = PolynomialSVC(degree=2, C=1e8)
    poly_svc.fit(X_train,y_train)
    print(poly_svc.score(X_test,y_test))
    
    poly = PolynomialFeatures(degree=3)
    poly.fit(X_train,y_train)
    X_train = poly.transform(X_train)
    X_test = poly.transform(X_test)
    
    std = StandardScaler()
    std.fit(X_train,y_train)
    X_train = std.transform(X_train)
    X_test = std.transform(X_test)
    
    svc = PolynomialSVC(C=1e8)
    svc.fit(X_train,y_train)
    print(svc.score(X_test,y_test))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.4 使用SVC

    编写PolynomialKernelSVC.py文件

    from sklearn.preprocessing import StandardScaler
    from sklearn.svm import SVC
    from sklearn.pipeline import Pipeline
    
    def PolynomialKernelSVC(degree=2,C=1.0):
        return Pipeline([
            ('std_standar', StandardScaler()),
            # 使用核函数的svm
            ('kernel_svc', SVC(degree=degree, C=C))
        ])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试:

    import numpy as np
    from sklearn import datasets
    from common.PolynomialKernelSVC import PolynomialKernelSVC
    
    # 默认生成100条包含两个特征的数据,默认是规则的图形,添加noise噪音可以理解为标准差
    X,y = datasets.make_moons(noise=0.1)
    kernel_svc = PolynomialKernelSVC(degree=2, C=1e8)
    kernel_svc.fit(X,y)
    print(kernel_svc.score(X,y))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    从结果的角度,LinearSVC和使用SVC且kernel传入linear,结果是一致的。但是由于LinearSVC只能计算线性核,而SVC可以计算任意核,所以,他们的底层计算方式不一样,这使得同样使用线性核的SVC,用LinearSVC的计算速度,要比用SVC且kernel传入linear参数,快很多。

    所以,整体而言,如果你决定使用线性SVM,就使用LinearSVC,但如果你要是用其他核的SVM,就可以使用SVC。

    3、核函数

    3.1 核函数理论

    我们将φ(X)的转置乘以φ(X)称为核函数(Kernel Function),核函数是一个实数。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y6nF3YYa-1668145316720)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110224201939.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hExdpIjQ-1668145316720)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221110224032569.png)]

    已知核函数K求映射φ(X)的例子:

    假设X是一个二维向量,X1=[x11, x12]的转置,X2=[x21, x22]的转置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-44uTDBWd-1668145316720)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221111095025486.png)]

    如果φ(X)是如下五维向量的形式,核函数K就是上面的形式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QuMYuGkb-1668145316721)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221111100137669.png)]

    核函数K和映射φ(X)是一 一对应的关系,知道一个,可以求出另一个。

    Mercer定理:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oBJkat6f-1668145316721)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221111094224087.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qSVUMUwY-1668145316721)(C:\Users\11244\AppData\Roaming\Typora\typora-user-images\image-20221111100444439.png)]

    正态分布就是一个高斯函数。高斯核函数有时也被称为RBF核(Radial Basis Function Kernel),有些文章中也会把1.0/(2 * sigma ** 2)替换成gamma,sklearn中的高斯核函数似乎也是用的gamma,gamma越大,正态分布越窄,模型越趋向过拟合,gamma越小,模型越趋向欠拟合。

    高斯核函数代码演示:

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = np.arange(-4, 5, 1)
    print(x)
    y = np.array((x > -2) & (x < 3), dtype=int)
    print(y)
    
    def gaussian(x,l):
        sigma = 1.0
        # 将高斯核函数中的x2固定为l,l是地标
        return np.exp(-(1.0/(2 * sigma ** 2)) * (x - l) ** 2)
    
    l1,l2 = -1,1
    
    X_new = np.empty((len(x), 2))
    for i,data in enumerate(x):
        X_new[i,0] = gaussian(data, l1)
        X_new[i,1] = gaussian(data, l2)
    
    plt.scatter(X_new[y==0,0],X_new[y==0,1])
    plt.scatter(X_new[y==1,0],X_new[y==1,1])
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    高斯核函数也是升维,是将m * n的数据映射为m * m的数据,对于每个数据点都是一个地标(landmark)。当样本数量m小于特征数n时,使用高斯核函数就非常划算,最典型的应用领域是自然语言处理

    3.2 sklearn中的高斯核函数

    编写RBFKernelSVC.py文件

    from sklearn.preprocessing import StandardScaler
    from sklearn.pipeline import Pipeline
    from sklearn.svm import SVC
    
    def RBFKernelSVC(gamma=1.0):
        return Pipeline([
            ('std_standar', StandardScaler()),
            ('svc', SVC(kernel='rbf', gamma=gamma))
        ])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用测试数据演示:

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import datasets
    from common.RBFKernelSVC import RBFKernelSVC
    
    X,y = datasets.make_moons(noise=0.15, random_state=666)
    # plt.scatter(X[y==0,0],X[y==0,1])
    # plt.scatter(X[y==1,0],X[y==1,1])
    # plt.show()
    
    svc = RBFKernelSVC(gamma=1.0)
    svc.fit(X,y)
    print(svc.score(X,y))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4、使用svm解决回归问题

    线性回归算法就是让预测的直线的MSE的值最小,对于SVM来说,拟合的定义是指定一个margin值,在这个margin范围里面,包含的数据点越多越好,包含的越多就代表这个范围能比较好的表达样本数据点,这种情况下取中间的直线作为真正的回归结果,用其来预测其他点的相应的值。

    在训练的时候是要对margin的范围进行一个指定,这就要引入一个新的超参数epsilon,即上下两根直线到中间的直线的垂直距离。

    这和前面SVM解决分类问题的思路相反,前面是margin中的点越少越好,硬间隔支持向量机要求margin中一个点都不能有,这里是越多越好。

    编写StandardLinearSVR.py文件,这里使用LinearSVR

    from sklearn.preprocessing import StandardScaler
    from sklearn.pipeline import Pipeline
    from sklearn.svm import SVR
    from sklearn.svm import LinearSVR
    
    def StandardLinearSVR(epsilon=0.1):
        return Pipeline([
            ('std_scale', StandardScaler()),
            ('linear_svr', LinearSVR(epsilon=epsilon))
        ])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用波士顿房价数据测试:

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import datasets
    from sklearn.model_selection import train_test_split
    from common.StandardLinearSVR import StandardLinearSVR
    from sklearn.preprocessing import StandardScaler
    from sklearn.svm import LinearSVR
    
    boston = datasets.load_boston()
    X = boston.data
    y = boston.target
    
    X_train,X_test,y_train,y_test = train_test_split(X,y)
    linear_svr = StandardLinearSVR()
    linear_svr.fit(X_train,y_train)
    print(linear_svr.score(X_test,y_test))
    
    std = StandardScaler()
    std.fit(X_train,y_train)
    X_train = std.transform(X_train)
    X_test = std.transform(X_test)
    
    linear_svr = LinearSVR()
    linear_svr.fit(X_train,y_train)
    print(linear_svr.score(X_test,y_test))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    USB通讯原理
    Redis最佳实践(上)
    12 原子性|可见性|有序性|JMM内存模型
    APP安全测试详解
    Utilizing Transformer Representations Efficiently
    MySQL创建定时任务定时执行sql
    HTTP之代理、网关、隧道
    自动备份某张表-DM8:达梦数据库配置定时作业备份某张表
    企业想上MES系统?还得满足这些条件
    Java中的基本数据类型
  • 原文地址:https://blog.csdn.net/noob9527/article/details/127804737