机器学习笔记(八)震惊!支持向量机(SVM)居然是这种机

来源:互联网 发布:万德数据库下载 编辑:程序博客网 时间:2024/05/01 11:58

今天想说的呢是SVM支持向量机(support vector machine),我觉得这个算法它初始出发的想法真的是非常符合人性,特征空间上间隔最大的分类器,你随便问一个人分开空间上的两坨点最佳的平面是什么,他的直觉也会告诉他是介于两坨之间然后比较中间的那个位置,如果不说人话,那就是SVM。

对于SVM呢,主要分为以下几种情况。

1 线性可分SVM

2 线性SVM

3 非线性SVM

针对每一个概念和它应用的情况,接下来我们详细讨论,首先引入几个概念。

第一,  线性可分。

对于两类样本,总存在着这样若干个超平面(wx+b)可以把两类完全正确的分开,那我们就称这个数据是线性可分的。退化到二维空间上来说,就是可以用若干条直线将两类数据完全正确地分开,那么这个样本就称为线性可分的。

第二,  函数间隔。

想必大家高中都学过,点(x1,y1)到直线Ax+By+C的距离是|Ax1+By1+C|/sqrt(A^2+B^2),推广到高维空间上就是样本x到超平面wx+b=0的距离是|wx+b|/||w||。假如样本分为正负两类分别用+1-1表示,那么如果分类正确的话y(wx+b)=|wx+b|,所以我们y(wx+b)这个值既能表明我们分类是否正确,还能通过距离的远近表明分类正确的确信度,所以我们把它定义为函数间隔。

第三,  几何间隔。

上面已经提到了函数间隔的概念,但有一个问题就是,对于超平面而言,只要w和b成比例的变化,那么超平面是不变的,但这样的话函数间隔就发生了变化。因此函数间隔我们是可以控制它的范围的,用它除一个w的二次模,就能得到一个定值,我们把y(wx+b) /||w||定义为几何间隔,分类正确时就表明样本到超平面的距离。

好的,有了以上这些概念我们就可以进一步探讨SVM了。

===================================================================

线性可分SVM:

对于线性可分的数据而言,我们自然有无数个超平面用于划分分类,但对每一种分类方式,其最小的几何间隔可求,当这个最小几何间隔最大的时候,上面也说了,其实意味着划分正确的确信度最高,是我们寻求的最优解。

所以,优化目标就变成了


求最小的那一项里就是我们的函数间隔,函数间隔有什么性质?可控可变乖巧听话,所以我们令所有样本的函数间隔都大于等于1,这样后面一项就变成1了,那么优化目标就变成


考虑到1/||w||和1/2||w||^2等价,可以把优化问题变成一个带约束的最小化问题,利用拉格朗日乘子法,构建拉格朗日函数


求这个函数的最大值,由于alpha始终大于等于0,所以对于函数间隔不是1的点而言,其对应的alpha一定等于0才能取到最大值,因此我们就有了拉格朗日函数的最大值就是第一项,我们想优化的目标函数,因此优化目标变成了


这里根据拉格朗日对偶性(可以参考李航博士的《统计学习方法》,但其实也只是给出了定理,并没有给出证明,所以这点还是有点晕)将这个极小极大问题转换成极大极小问题,也就是先对w,b求最小值,再求对alpha的最大值。极小问题就转化成求偏导为0,也就是


有了这两个等式,我们再把他们回代到拉格朗日函数当中,有


现在拉格朗日函数中需要优化的参数变成了alpha一个,现在只要求得了alpha的最佳值就解决了我们一开始的优化问题,也就是最后需要我们做的工作就是


实际的应用中,当我们解决了上述最优问题之后,我们再回过来求w,b的最优值。W的值很明显,根据上面求导所得的公式进行计算就成,但b的取值怎么求呢?这需要我们回到梦开始的地方,一开始我们就做了一个约束,要求对所有的样本函数间隔都大于等于1,一会儿就要用到这个。首先,alpha不可能全为0,假如alpha全为0则w也为0,我们知道样本有正负两类,这样y(wx+b)=yb不能保证始终大于1,所以必有不等于0的alpha,而对于不等于0的alpha对应的函数间隔必然为1能保证拉格朗日函数的极大值与我们一开始的优化目标等价,所以这里借的到了一个有关b的等式了,借此便可以求得b的最价值,具体如下


讲到这里,问题已经解决了,一开始寻找的最佳分离超平面就这样求得。

就这样结束了是不是有点怪,哪儿不对呢?支持向量机支持向量机,你倒是告诉我支持向量是啥啊!!!我们来观察一下上面这个式子,alpha中大部分都是0的,只在少数函数间隔为1的样本处不为0,那么这样的话w,b的取值就只和这些样本有关,其他的样本根本没有地位啊,为了突出这些样本与众不同的地位,我们把它们称为支持向量,超平面的选择之和他们有关~

===================================================================

线性SVM:

讲完线性可分SVM有什么感觉,是不是世界太美好了?实际情况中,往往遇到的是线性不可分的数据,更过分的是,如果有叛徒混在另外一类的附近,但确实又线性可分,这样求得的分离超平面泛化能力严重不足。

所以,怎么办呢?既然不能线性可分,不能严格满足函数间隔大于等于1,那我们就给它放宽条件,每个样本给一个松弛变量xi,当然这个xi也不能过分,我们需要在优化目标里加上关于它的惩罚项,所以新的优化目标就变成了


到了这里还记得怎么办吗?和线性可分SVM一模一样,只不过约束条件变成了两个,构建拉格朗日函数


下面怎么来的,拉格朗日函数的极大值和原始优化目标一致,再利用对偶性,把极小极大问题转换成极大极小问题。那么第一步就是求关于w,b,xi的函数极小值,这个时候求导大法好,得到


好的,再回代看看拉格朗日函数变成啥


哎呀,结果和线性可分SVM一模一样啊,那么最后我们的优化目标就变成了


当然根据后面三个约束条件可以得到alpha和beta的范围是0到C。

实际情况中根据上式求得最优的alpha,求w依然很轻松,根据求导那儿的公式就可以求得,那么b呢,根据线性可分SVM的思路,我们是根据一开始给定函数间隔那个式子做的,但是,但是!现在情况不一样了啊,现在多了一个松弛因子xi,怎么办呢?什么情况下xi为0呢,就是beta不为0的情况,那也就是alpha介于0和C的时候,我们就可以利用函数间隔为1求得b的值,但是这里选取不同的alpha会得到不同的结果,实际情况往往选所有点的均值,其形式和线性可分SVM一样


那这种情况下的支撑向量是怎么定义的呢,首先alpha为0的先排除掉,这些都是没地位的点。然后alpha介于0到C的,xi必为0,因此他们是函数间隔为1的样本点,那么alpha为C的呢,xi可以不为0,如果xi小于1,就是位于函数间隔为1的超平面和分离超平面之间正确分类的点,如果xi为0,则刚好落在分割超平面上,如果xi大于0,则是误分类的点,这几种样本就是线性SVM的支持向量。

===================================================================

非线性SVM。

这个不知道大家还记不记得,在线性回归里面我提到过一件事儿,就是虽然它叫线性回归,但并不表示它只能是一个超平面,我们可以通过特征的组合,来达曲面的效果。那对与SVM其实也一样,我们可以通过一个变换,把原空间的数据映射到一个新的特征空间中,原先也许是线性不可分的两类样本点到了新的特征空间,变得线性可分了,这样就可以利用线性可分SVM的办法来解决分类问题。

最常见一个例子莫过于,二维空间上,两个圆环,内环是一类,外环是一类,那在二维空间上你怎么也不能线性分开吧,但是通过变换(x^2,y^2)就可以把内环的数据映射到靠近原点的第一象限空间内,而外环则是更远处,进而变成线性可分的问题。

我想这个概念大家还是很容易接受的吧,主要因为也是很自然而然的一种想法。然后想提一下的就是核技巧,所谓kernel trick就是说我不直接定义这个映射的规则,而是直接给出核函数,这样的好处是不会限制映射的方式,因为同一个核函数可以对应若干种映射的方式。

然后关于非线性SVM的公式推导,其实和上面两种情况如出一撤,只是把本来x的内积改成了核函数,我就不去写了。

最后的最后,发现一个问题,我上面辛辛苦苦求得了w和b,得到了最佳分离超平面,但忘了给出我们最后的分类器了,其实就是加一个符号函数而已,哈哈哈,如下

===================================================================

好了,理论部分可算讲完了,码字真累,我们再撸一小段代码结束吧。老样子,还是鸢尾花数据,用SVM分一下看看,其实和前面其他的算法的调用真是一模一样,重点其实还是调参,回头专门写几篇讲调参的好了,这里就讲一下调包和用的过程吧。

mport numpy as npfrom sklearn import svmfrom sklearn.model_selection import train_test_splitfrom sklearn import datasetsiris=datasets.load_iris()x=iris.data[:,:2]y=iris.targetx_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.7, random_state=1)model=svm.SVC(C=1, kernel='linear', decision_function_shape='ovr')model.fit(x_train,y_train)y_hat=model.predict(x_test)print '训练集上的正确率为%2f%%'%( model.score(x_train, y_train)*100)print '测试集上的正确率为%2f%%'%( model.score(x_test, y_test)*100)

输出为

训练集上的正确率为83.809524%

测试集上的正确率为77.777778%

好啦,这就是SVM的内容,希望有帮到你,反正我是觉得推导的过程怎么说呢,很符合我们的思维,所以感觉很顺,中间除了一些数学上的知识还是很容易理解完全的。

抓住周末的小尾巴啊,还有半天啊哈哈哈~


2 0