SVM支持向量机分类模型SVC理论+python sklean.svm实践

来源:互联网 发布:追英剧用什么软件 编辑:程序博客网 时间:2024/06/03 20:33

支持向量机是啥

有一次公司项目上的同事一起吃饭(面前是一锅炒土鸡),提到了支持向量机,学文的同事就问支持向量机是什么,另一个数学物理大牛想了一下,然后说,一种鸡。。。

确实很难一句话解释清楚这只鸡。。。support vector machine从字面意思来说应该是依靠support vector来划分数据(其实也能回归啦。。)的机器学习模型。它是一个凸优化问题。

SVM的核心将数据的特征投射到高维,然后找到超平面,分割不同类别的数据点,而且要使分离的程度越大越好,至于为什么叫支持向量机,是因为每个类别都会有一些数据点作为支撑向量,这些支撑向量决定了最后分割的超平面。
@线性可分示意图|300x200

这个图里的圈圈就是两边的支撑向量。

线性可分支持向量机

我们先讲最简单的情况,也就是线性可分的平面二分类问题。
支持向量机的目标是,找到一条分界线,把两类数据分开。但是这样的线可能有很多。
@多条线分割 | 200x100

像上图。并不是每条线都是一个很好的分割线,如果紧贴着红点,那么线的另一头会立马被判为蓝色,这样对红点就很不合适了。所以SVM的目标不光是要找到这样一条分割线,而是要找到一条能最公平合理的分割线,让两类数据中最边缘的数据点距离分割线越远越好,这样这个分类器的泛化能力才会更强。于是乎支撑向量就被引入了。

分割线,分类表达式

这里写图片描述

直线的一般表达式:ax+by+c=0
对于多维,可以直接表达成:wTx+b=0,在多维情况下,它是个超平面。
对于直线上方的类别有wTx+b>0
对于直线下方的类别有wTx+b<0

距离表达式

有了直线,我们需要定义数据点到分割平面的距离,这里用的是点到直线的距离公式。

distance=|Ax0+By0+C|A2+B2

- 如果我们去掉绝对值,就可以根据大于零还是小于零来判断数据点在直线上方还是下方。
- 更进一步,我们可以把它表示成如下形式:
distance=wTx0+b||w||

最大分割距离max margin

然后我们再来看一开始的那张图:
这里写图片描述

回顾一下支持向量机是要干啥来着,是要找到一条把两类数据分得很开的割平面对不对,这需要我们找到两类数据最边缘的数据点(支撑向量),然后画出来两条平行的切面,两边支撑向量距离的垂直平分线就是最终的切割平面。

支持向量机的目标是让最边缘的点之间的距离越大越好。即ρ最大

这是我们的终极目标,敲黑板!

目标函数表达式推导

接下来,我们来分析怎么把这个目标写成数学表达式~
很简单,只需要表示support vector到分割线的距离,并且让该距离最大不就行了。

ρ=2r=2|wTxsupport+b|||w||=2ysupport(wTxsupport+b)||w||

最右边的等式成立是因为,y的sign和(直线上方的点记为1,直线下方的点记为-1)括号里的一直,保证了分子大于零。

直线上方的点 yi=1wTxi+bρ2

直线下方的点 yi=1wTxi+bρ2

等价于:yi(wTxi+b)ρ2

那么新的问题来了,我们如何知道哪个点是support vector?
答案就是离分割线最近的点对不对。
所以,目标函数是一个极小极大问题。。。

argmaxw,b{2||w||miniyi(wTxi+b)}.

之前我们有 yi(wTxi+b)ρ2,我们总可以通过缩放w和b,使该不等式右边划归到1。如此,就可以简化目标函数。

argmaxw,b2||w||s.t.yi(wTxi+b)1fori=1,2,3.....n

优化问题求解

我们把问题改为求它的对偶问题

argminw,b||w||22s.t.yi(wTxi+b)1fori=1,2,3.....n

因为目标函数是二次的,而约束在参数w和b上是线性的,因此这个问题是一个凸优化问题,可以通过标准的拉格朗日乘子来求解。

用拉格朗日乘子法:

L(w,b,α)=||w||22i=0nαi(yi(wTxi+b)1)(1)
其中,αi0

解这个优化问题的方法是先求关于α的极大,再求关于w和b的极小。

minw,bmaxαL(w,b,α)

(因为αi0, (yi(wTxi+b)1)0, 求这个式子关于α的极大,就是0,于是等价于原来的对||w||2求极小)

我们转而求它的对偶问题:

maxαminw,bL(w,b,α)

(1)先求极小问题
另L对w,b求偏导并等于0, 有

Lw=wi=1nαiyixi=0

Lb=i=1nαiyi=0

然后我们把这两个式子带入到拉格朗日函数(1)中,最终化简可以得到:

i=1nαi12i,j=1nαiαjyiyjxTixj

(2)现在求极大问题

maxαi=1nαi12i,j=1nαiαjyiyjxTixjs.t.i=1nαiyi=0αi0

还是将问题转成对偶问题,求解这个问题用到了SMO,sequential minimal optimization,即每次只挑两个拉格朗日乘子,其他乘子认为是常数,然后每次都化为两变量凸优化问题。

最终通过求得α的值,找到最优的w和b。注意,最后的结果里,只有支撑向量的α>0, 对于非支撑向量,其α=0

松弛变量

有时候数据点不会分隔的这么好,会有一些点,总是站在对方阵营。或者及时我们能找到一条线,把两个类别的数据点刚好完美分开,我们可能也不希望是这根线。。。因为我们希望模型能有较好的泛化能力,希望中间的过渡带ρ越大越好,所以我们会对某些不好的点选择性忽略。

一般用ξ来表示松弛变量。加入松弛变量后的模型优化目标和约束变成啥样了呢。

minw,b,ξ||w||22+Ci=1nξis.t.yi(wTxi+b)1ξiξ0

然后跟刚才的过程差不多,先对w,b,ξ求极小,在对α求极大。

这里需要强调的是,C越大,我们越倾向于没有松弛变量,即模型会尽可能分对每一个点,反之,C越小,模型的泛化能力越强

核函数

终于讲到核函数了。。。我最喜欢的部分。。。
之前的问题中我们都是用的x本尊,现实是,这堆数据点可能一条线不可分,比如说圆环图,斑马图。。。于是我们可以对x做高维变换,以期望在高维空间中,数据点能分开。此处盗用一张非常著名的图。
这里写图片描述

之前所有xi出现的地方,都可以改成Φ(xi)
比如最终的分割超平面:

wTΦ(xi)+bw=i=1nαiyiΦ(xi)b=yii=1nαiyi(Φ(xi)TΦ(xj))

再比如求解中的目标函数:
i=1nαi12i,j=1nαiαjyiyjΦ(xi)TΦ(xj)

因为从始至终,我们都只用到了内积,所以我们并不需要定义核函数的具体形式,而只需给出核函数的内积形式。

三种常见核函数
多项式核函数:κ(xi,xj)=(α||xixj||a+r)b α,a,b,r
RBF径向基核函数:κ(xi,xj)=exp(||xixj||22σ2) 也叫高斯核函数,因为长得像
sigmoid核函数:κ(xi,xj)=tanh(γ||xixj||a+r)

一般来讲RBF核已经很好用了,它可以投射到无穷维(回顾一下ex的tylor展开式。。。)
你可能还会有疑问,都什么函数能当核函数。答案是,所有半正定矩阵。
这里写图片描述

好了,现在我们终于可以来两行代码了。。。

from sklearn.datasets import load_irisdata = load_iris()

用sklearn自带的鸢尾花数据集,好嘛,我知道老掉牙了。。。复习一下

dir(data)返回的结果是[‘DESCR’, ‘data’, ‘feature_names’, ‘target’, ‘target_names’],比较直观,我就不解释了。

from sklearn.model_selection import train_test_splitX_train,X_test,y_train,y_test = train_test_split(data.data, data.target,test_size=0.3,random_state=30,stratify=data.target)

这一步是划分训练集和测试集,永远不要忘了这一步。

from sklearn import svmmodel=svm.SVC(C=0.5, kernel='rbf',gamma=5 )

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是松弛变量的系数
kernel是要定义核函数的名字,跟后面的系数也息息相关
gamma是这三个核函数的乘系数
degree是对多项式核函数来的。。。
coef0是另外两个核函数里的r
probability是可以允许多分类的情况
class_weight是可以实现给不同类别设不同的权重

from sklearn.metrics import accuracymodel.fit(X_train,y_train)model.score(X_test,y_test)

输出是91%
虽然如此,我们还是象征性调个参

import numpy as npfrom sklearn.model_selection import GridSearchCVparameters={'kernel':['linear','rbf','sigmoid','poly'],'C':np.linspace(0.1,20,50),'gamma':np.linspace(0.1,20,20)}svc = svm.SVC()model = GridSearchCV(svc,parameters,cv=5,scoring='accuracy')model.fit(X_train,y_train)model.best_params_model.score(X_test,y_test)

{‘C’: 1.7244897959183674, ‘gamma’: 0.10000000000000001, ‘kernel’: ‘rbf’}
accuracy=95%