机器学习—支撑向量机SVM

10.支撑向量机SVM

10.1支撑向量机SVM的实现

10.1.1什么是支撑向量机

支撑向量机的英文全称是Support Vector Machine,其思想可以解决分类问题,也可以解决回归问题。

对于二分类问题,我们需要找到一条直线,将标签为0的样本划分在直线的一侧,标签为1的样本划分在直线的另一侧,这条直线称为“线性分类器”。对于训练数据集,其线性分类器有无数条,如何找到一条泛化性能最好的线性分类器呢?

解决思想:

(1)逻辑回归

通过定义一个概率函数sigmoid,当概率p >= 0.5,其预测标签值为1;当概率p <= 0.5,其预测标签值为0。根据这样的变化关系得到了损失函数J,通过求损失函数的极小值从而得到一条决策边界。

(2)支撑向量机

为了得到好的泛化性能,线性分类器不应偏向任何一类样本,即离两个类的样本尽可能的远。SVM的目标就是寻找一个最优的决策边界,其距离两个类别的最近样本最远,如下所示。

图中,红色和蓝色样本有3个样本离分类直线最近,这3个样本称为支撑向量。把同一类型的最近样本连接起来形成两条平行直线,分类直线位于其中间;直线之间的距离称为margin。

SVM的目标就是要最大化margin。对于线性可分的问题,使用Hard Margin SVM;对于线性不可分的问题,使用Soft Margin SVM。

10.1.2 Hard Margin SVM实现思想

对于线性可分的问题,支撑向量机的目标是寻找一个分类的超平面,它不仅能正确的分类每一个样本,并且要使每一类样本中距离超平面最近的样本到超平面的距离最远。

在n维空间中,,其中

在支撑向量机中,换一种表示形式:

其中,

因此,决策边界(超平面)为wTx+b=0。

根据点到平面的距离公式,得出:

由于margin=2d,因此最大化margin就是最大化d。

在支撑向量机中,我们把标签值取为+1和-1,分别对应正样本和负样本。通过d可以得出:

->

由于超平面参数进行缩放变换,还是原来的超平面,由上式得出:

->

如下图所示:

对于开始需要求的,即求->

总结:对于线性可分的问题,Hard Margin SVM的原理是在条件下,求出。对于有条件的优化问题,可以使用拉格朗日对偶将其转换为对偶问题,再进行求解,

由于过程过于复杂,这里不再具体推导。

10.1.3 Soft Margin SVM实现思想

表示所有的样本都在的外面,若有一个样本在两条直线的中间,则无法求解。

因此,我们需要给条件增加一个松弛变量ξ,即:

为了控制ξ的大小,在中加一个L1正则项,即:

若加L2正则项,则表示为

对于线性不可分的问题,就是使用松弛变量ξ和惩罚因子C对违反不等式约束的样本进行惩罚。

总结:s.t.  ,ξ>=0;求

10.1.4使用sklearn来实现SVM

#程序10-1:Hard Margin

import numpy as np

 

from sklearn import datasets

iris = datasets.load_iris()

X = iris.data

y = iris.target

#去鸢尾花的前2个类别,前2个特征

X = X[y<2,:2]

y = y[y<2]

 

from sklearn.preprocessing import StandardScaler

#由于SVM需要求距离,因此需要标准化

std_sca = StandardScaler()

std_sca.fit(X)

X_std = std_sca.transform(X)

 

#LinearSVC表示分类问题

from sklearn.svm import LinearSVC

#Hard Margin

Lin_svc = LinearSVC(C=1e8)

Lin_svc.fit(X_std,y)

 

import matplotlib as mpl

import matplotlib.pyplot as plt

 

def plot_decision_boundary(clf, X, y, num_row=100, num_col=100):

    """

    绘制决策边界

    :param clf: 分类器, 即训练后的模型

    :param X: 输入的训练数据X

    :param y: 输入真实的训练数据y

    :param num_row: 单位行数据生成的基本个数

    :param num_col: 单位列数据生成的基本个数

    """

    #以训练数据集X的第一个特征作为x轴,第二个特征作为y轴,生成坐标轴的间距

    sigma = 1   #防止数据在图形的边上而加上的一个偏移量,设定一个较小的值即可

    x_min, x_max = np.min(X[:, 0])-sigma, np.max(X[:, 0])+sigma

    y_min, y_max = np.min(X[:, 1])-sigma, np.max(X[:, 1])+sigma

    #对间距进行等分成t1、t2,并t1按照t2的列数进行行变换、t2按照t1的行数进行列变换

    t1 = np.linspace(x_min, x_max, int(x_max-x_min)*num_row).reshape(-1,1)

    t2 = np.linspace(y_min, y_max, int(y_max-y_min)*num_col).reshape(-1,1)

    x_copy, y_copy = np.meshgrid(t1, t2)

    #将变换后的x_,y_生成坐标轴的每个点

    xy_all = np.stack((x_copy.reshape(-1,), y_copy.reshape(-1,)), axis=1)

    #对坐标轴的点进行预测,并将预测结果变换为对应点的结果

    y_predict = clf.predict(xy_all)

    y_predict = y_predict.reshape(x_copy.shape)

 

    #设置使用的颜色colors

    cm_dark = mpl.colors.ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])

    #绘制等高线,x_copy和y_copy种对应的点

    #若y_predict为0绘制#FFA0A0,若y_predict为1绘制#A0A0FF,等高线绘制#A0FFA0

    plt.contourf(x_copy, y_copy, y_predict,cmap=cm_dark)  #绘制底色

 

plot_decision_boundary(Lin_svc,X_std,y)

plt.scatter(X_std[y==0,0],X_std[y==0,1])

plt.scatter(X_std[y==1,0],X_std[y==1,1])

plt.show()

运行结果:

#程序10-2:Soft Margin

import numpy as np

 

from sklearn import datasets

iris = datasets.load_iris()

X = iris.data

y = iris.target

#去鸢尾花的前2个类别,前2个特征

X = X[y<2,:2]

y = y[y<2]

 

from sklearn.preprocessing import StandardScaler

#由于SVM需要求距离,因此需要标准化

std_sca = StandardScaler()

std_sca.fit(X)

X_std = std_sca.transform(X)

 

#LinearSVC表示分类问题

from sklearn.svm import LinearSVC

#Hard Margin

Lin_svc = LinearSVC(C=0.01)

Lin_svc.fit(X_std,y)

 

import matplotlib as mpl

import matplotlib.pyplot as plt

 

def plot_decision_boundary(clf, X, y, num_row=100, num_col=100):

    """

    绘制决策边界

    :param clf: 分类器, 即训练后的模型

    :param X: 输入的训练数据X

    :param y: 输入真实的训练数据y

    :param num_row: 单位行数据生成的基本个数

    :param num_col: 单位列数据生成的基本个数

    """

    #以训练数据集X的第一个特征作为x轴,第二个特征作为y轴,生成坐标轴的间距

    sigma = 1   #防止数据在图形的边上而加上的一个偏移量,设定一个较小的值即可

    x_min, x_max = np.min(X[:, 0])-sigma, np.max(X[:, 0])+sigma

    y_min, y_max = np.min(X[:, 1])-sigma, np.max(X[:, 1])+sigma

    #对间距进行等分成t1、t2,并t1按照t2的列数进行行变换、t2按照t1的行数进行列变换

    t1 = np.linspace(x_min, x_max, int(x_max-x_min)*num_row).reshape(-1,1)

    t2 = np.linspace(y_min, y_max, int(y_max-y_min)*num_col).reshape(-1,1)

    x_copy, y_copy = np.meshgrid(t1, t2)

    #将变换后的x_,y_生成坐标轴的每个点

    xy_all = np.stack((x_copy.reshape(-1,), y_copy.reshape(-1,)), axis=1)

    #对坐标轴的点进行预测,并将预测结果变换为对应点的结果

    y_predict = clf.predict(xy_all)

    y_predict = y_predict.reshape(x_copy.shape)

 

    #设置使用的颜色colors

    cm_dark = mpl.colors.ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])

    #绘制等高线,x_copy和y_copy种对应的点

    #若y_predict为0绘制#FFA0A0,若y_predict为1绘制#A0A0FF,等高线绘制#A0FFA0

    plt.contourf(x_copy, y_copy, y_predict,cmap=cm_dark)  #绘制底色

 

plot_decision_boundary(Lin_svc,X_std,y)

plt.scatter(X_std[y==0,0],X_std[y==0,1])

plt.scatter(X_std[y==1,0],X_std[y==1,1])

plt.show()

运行结果:

C越小,松弛变量ξ就越大,模型就存在一定的容错率。

10.1.5 SVM和多项式特征

#程序10-3

import numpy as np

 

from sklearn import datasets

X,y = datasets.make_moons(noise=0.1,random_state=123456)

 

import matplotlib as mpl

import matplotlib.pyplot as plt

def plot_decision_boundary(clf, X, y, num_row=100, num_col=100):

    """

    绘制决策边界

    :param clf: 分类器, 即训练后的模型

    :param X: 输入的训练数据X

    :param y: 输入真实的训练数据y

    :param num_row: 单位行数据生成的基本个数

    :param num_col: 单位列数据生成的基本个数

    """

    #以训练数据集X的第一个特征作为x轴,第二个特征作为y轴,生成坐标轴的间距

    sigma = 1   #防止数据在图形的边上而加上的一个偏移量,设定一个较小的值即可

    x_min, x_max = np.min(X[:, 0])-sigma, np.max(X[:, 0])+sigma

    y_min, y_max = np.min(X[:, 1])-sigma, np.max(X[:, 1])+sigma

    #对间距进行等分成t1、t2,并t1按照t2的列数进行行变换、t2按照t1的行数进行列变换

    t1 = np.linspace(x_min, x_max, int(x_max-x_min)*num_row).reshape(-1,1)

    t2 = np.linspace(y_min, y_max, int(y_max-y_min)*num_col).reshape(-1,1)

    x_copy, y_copy = np.meshgrid(t1, t2)

    #将变换后的x_,y_生成坐标轴的每个点

    xy_all = np.stack((x_copy.reshape(-1,), y_copy.reshape(-1,)), axis=1)

    #对坐标轴的点进行预测,并将预测结果变换为对应点的结果

    y_predict = clf.predict(xy_all)

    y_predict = y_predict.reshape(x_copy.shape)

 

    #设置使用的颜色colors

    cm_dark = mpl.colors.ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])

    #绘制等高线,x_copy和y_copy种对应的点

    #若y_predict为0绘制#FFA0A0,若y_predict为1绘制#A0A0FF,等高线绘制#A0FFA0

    plt.contourf(x_copy, y_copy, y_predict,cmap=cm_dark)  #绘制底色

 

from sklearn.pipeline import Pipeline

from sklearn.preprocessing import StandardScaler,PolynomialFeatures

from sklearn.svm import LinearSVC

 

def polynomia_linearSVC(degree,C=1.0,max_iter=1000):

    return Pipeline([

        ('pol_fea',PolynomialFeatures(degree=degree)),

        ('std_sca',StandardScaler()),

        ('lin_svc',LinearSVC(C=C,max_iter=max_iter))

    ])

pol_linsvc = polynomia_linearSVC(3,C=100,max_iter=1e6)

pol_linsvc.fit(X,y)

plot_decision_boundary(pol_linsvc,X,y)

plt.scatter(X[y==0,0],X[y==0,1])

plt.scatter(X[y==1,0],X[y==1,1])

plt.show()

运行结果:

10.2核函数

10.2.1什么是核函数

若样本是线性不可分的,可以对样本的特征向量映射到更高维的空间,使得它在该空间中线性可分。如下所示:
=>  

这种方法在机器学习中称为核技巧,核映射φ将特征向量变换到更高维的空间,即φ(x)。

核函数表示将两个向量的内积转化为高维向量的内积,即:

核函数是先对向量求内积,再使用函数K进行变换;等价于先对向量进行核映射(升维),然后求内积。使用核函数的方式有效的简化了问题的求解。因此,核函数分为线性核、多项式核、高斯核、sigmoid核等。

在前面的线性不可分问题中,虽然加入了松弛变量和惩罚因子来处理线性不可分问题,但其本质上还是线性分类器,只是允许一定的容错率。核函数可以使支持向量机称为非线性分类器,决策边界不再是线性的超平面,而是形状复杂的曲面。

在线性不可分问题中,使用拉格朗日对偶将其转换为对偶问题:

其中,α、β为拉格朗日乘子。在求解过程中,它会转化为

约束条件为:

xixj转换为核函数,即等价于先将样本的特征向量高维化,再求内积。如下所示:

其思想类似于多项式回归;这样就可以解决线性不可分问题。

10.2.2核函数实现-多项式核

#程序10-4

import numpy as np

 

from sklearn import datasets

X,y = datasets.make_moons(noise=0.1,random_state=123456)

 

import matplotlib as mpl

import matplotlib.pyplot as plt

def plot_decision_boundary(clf, X, y, num_row=100, num_col=100):

    """

    绘制决策边界

    :param clf: 分类器, 即训练后的模型

    :param X: 输入的训练数据X

    :param y: 输入真实的训练数据y

    :param num_row: 单位行数据生成的基本个数

    :param num_col: 单位列数据生成的基本个数

    """

    #以训练数据集X的第一个特征作为x轴,第二个特征作为y轴,生成坐标轴的间距

    sigma = 1   #防止数据在图形的边上而加上的一个偏移量,设定一个较小的值即可

    x_min, x_max = np.min(X[:, 0])-sigma, np.max(X[:, 0])+sigma

    y_min, y_max = np.min(X[:, 1])-sigma, np.max(X[:, 1])+sigma

    #对间距进行等分成t1、t2,并t1按照t2的列数进行行变换、t2按照t1的行数进行列变换

    t1 = np.linspace(x_min, x_max, int(x_max-x_min)*num_row).reshape(-1,1)

    t2 = np.linspace(y_min, y_max, int(y_max-y_min)*num_col).reshape(-1,1)

    x_copy, y_copy = np.meshgrid(t1, t2)

    #将变换后的x_,y_生成坐标轴的每个点

    xy_all = np.stack((x_copy.reshape(-1,), y_copy.reshape(-1,)), axis=1)

    #对坐标轴的点进行预测,并将预测结果变换为对应点的结果

    y_predict = clf.predict(xy_all)

    y_predict = y_predict.reshape(x_copy.shape)

 

    #设置使用的颜色colors

    cm_dark = mpl.colors.ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])

    #绘制等高线,x_copy和y_copy种对应的点

    #若y_predict为0绘制#FFA0A0,若y_predict为1绘制#A0A0FF,等高线绘制#A0FFA0

    plt.contourf(x_copy, y_copy, y_predict,cmap=cm_dark)  #绘制底色

 

from sklearn.pipeline import Pipeline

from sklearn.preprocessing import StandardScaler

#分类问题+核函数使用SVC

from sklearn.svm import SVC

#kernel参数

#linear:线性核函数;poly:多项式核函数;rbf:高斯核;sigmod:sigmod核函数;precomputed:核矩阵

def standard_SVC(degree,C=1.0,max_iter=1000):

    return Pipeline([

        ('std_sca',StandardScaler()),

        ('svc',SVC(C=C,kernel='poly',degree=degree,max_iter=max_iter))

    ])

std_svc = standard_SVC(3,C=1e4,max_iter=1e8)

std_svc.fit(X,y)

plot_decision_boundary(std_svc,X,y)

plt.scatter(X[y==0,0],X[y==0,1])

plt.scatter(X[y==1,0],X[y==1,1])

plt.show()

运行结果:

多项式核:

10.2.3核函数的实现-高斯核

高斯核:,高斯核又被称为径向基函数核。其中,γ越大,高斯分布越窄;γ越小,高斯分布越宽。

#程序10-5

import numpy as np

 

from sklearn import datasets

X,y = datasets.make_moons(noise=0.1,random_state=123456)

 

import matplotlib as mpl

import matplotlib.pyplot as plt

def plot_decision_boundary(clf, X, y, num_row=100, num_col=100):

    """

    绘制决策边界

    :param clf: 分类器, 即训练后的模型

    :param X: 输入的训练数据X

    :param y: 输入真实的训练数据y

    :param num_row: 单位行数据生成的基本个数

    :param num_col: 单位列数据生成的基本个数

    """

    #以训练数据集X的第一个特征作为x轴,第二个特征作为y轴,生成坐标轴的间距

    sigma = 1   #防止数据在图形的边上而加上的一个偏移量,设定一个较小的值即可

    x_min, x_max = np.min(X[:, 0])-sigma, np.max(X[:, 0])+sigma

    y_min, y_max = np.min(X[:, 1])-sigma, np.max(X[:, 1])+sigma

    #对间距进行等分成t1、t2,并t1按照t2的列数进行行变换、t2按照t1的行数进行列变换

    t1 = np.linspace(x_min, x_max, int(x_max-x_min)*num_row).reshape(-1,1)

    t2 = np.linspace(y_min, y_max, int(y_max-y_min)*num_col).reshape(-1,1)

    x_copy, y_copy = np.meshgrid(t1, t2)

    #将变换后的x_,y_生成坐标轴的每个点

    xy_all = np.stack((x_copy.reshape(-1,), y_copy.reshape(-1,)), axis=1)

    #对坐标轴的点进行预测,并将预测结果变换为对应点的结果

    y_predict = clf.predict(xy_all)

    y_predict = y_predict.reshape(x_copy.shape)

 

    #设置使用的颜色colors

    cm_dark = mpl.colors.ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])

    #绘制等高线,x_copy和y_copy种对应的点

    #若y_predict为0绘制#FFA0A0,若y_predict为1绘制#A0A0FF,等高线绘制#A0FFA0

    plt.contourf(x_copy, y_copy, y_predict,cmap=cm_dark)  #绘制底色

 

from sklearn.pipeline import Pipeline

from sklearn.preprocessing import StandardScaler

#分类问题+核函数使用SVC

from sklearn.svm import SVC

#kernel参数

#linear:线性核函数;poly:多项式核函数;rbf:高斯核;sigmod:sigmod核函数;precomputed:核矩阵

def standard_SVC(gamma,C=1.0,max_iter=-1):

    return Pipeline([

        ('std_sca',StandardScaler()),

        ('svc',SVC(gamma=gamma,C=C,kernel='rbf',max_iter=max_iter))

    ])

std_svc = standard_SVC(1)

std_svc.fit(X,y)

plot_decision_boundary(std_svc,X,y)

plt.scatter(X[y==0,0],X[y==0,1])

plt.scatter(X[y==1,0],X[y==1,1])

plt.show()

 

std_svc2 = standard_SVC(40)

std_svc2.fit(X,y)

plot_decision_boundary(std_svc2,X,y)

plt.scatter(X[y==0,0],X[y==0,1])

plt.scatter(X[y==1,0],X[y==1,1])

plt.show()

运行结果:

10.3 SVM解决回归问题

#程序10-6

import numpy as np

 

from sklearn import datasets

boston = datasets.load_boston()

X = boston.data

y = boston.target

 

from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=123456)

 

 

from sklearn.pipeline import Pipeline

from sklearn.preprocessing import StandardScaler

from sklearn.svm import LinearSVR

 

#epsilon参数

def standard_LinearSVR(epsilon=0.1,C=1.0):

    return Pipeline([

        ('std_sca',StandardScaler()),

        ('lin_svr',LinearSVR(epsilon=epsilon,C=C))

    ])

 

svr = standard_LinearSVR(epsilon=0.01)

svr.fit(X_train,y_train)

score = svr.score(X_test,y_test)

print(score)

运行结果:

0.7038286472455404

总结:对于分类问题,在margin范围内,要求样本越少越好;对于回归问题,在margin范围内,要求样本越多越好。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值