支持向量机初步学习

来源:互联网 发布:linux修改用户名及密码 编辑:程序博客网 时间:2024/05/22 23:05

前言

svm需要一定的数学功底,我是亦步亦趋花了一个星期,才渐渐有所了解。出于学习交流目的,我将自己的学习思路整理出来。由于对svm的理解有所不足,如有错误,敬请指正。

svm简介

支持向量机(support vertor machines,SVM)是一种二分类模型。它的基本模型是定义在特征空间上的最大间隔分类器,核技巧使它称为线性分类器。支持向量机的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题,也等价于正则化的合页损失最小化问题。支持向量机的学习算法是求解凸二次规划的最优化算法。

最大间隔的分类器

ok,让我们从最简单的线性分类说起,如图:
这里写图片描述
在一个平面上有两类点,中间的实线表示一个分类器。我们知道,空间中的一个(超)平面(在二维是直线)可以表示为

f(x)=wx+b

我们不妨设所有满足f(x)>0的点其y等于1,而f(x)<0的点其y等于-1(至于为什么是1和-1,读者如果感兴趣,可自行查阅相关资料)。当超平面的方程给定后,我们就可以将需要预测的点带入方程,如果得到的值大于0,则分到正类(y=1),如果得到的值小于0,则分到负类(y=-1)。那么,现在剩下的问题就是,怎样确保我们的超平面是分类效果最好的?svm利用间隔最大化求最优超平面。
一般而言,一个点距离超平面的远近可以表示匪类的准确度。在超平面 w*x+b 确定的情况下|w*x+b|可以表示点x距离超平面距离的远近,而标号y可以表示正确。所以,我们用y(wx+b)表示分类的确信度。由此引出函数间隔的定义。

对于给定训练集T和超平面(w,b),定义超平面关于样本点(xi,yi)的函数间隔为

γi^=yi(wxi+b)

定义超平面(w,b)关于训练集T的函数间隔为所有样本点函数间隔的最小值即
γ^=mini=1,2...Nγi^

函数间隔虽然可以表示分类,但是如果成比例的改变w和b,函数间隔就会成比例的变化,由此我们引入几何间隔。

γ=γ^||w||

几何距离就是点到超平面的距离

用几何距离来表示间隔显然要比函数间隔好。那么,我们的目的就是使几何距离最大化,即

maxγ^(1)

当然,还有个附加条件
yi(ωTxi+b)=γi^γ^,i=1,2...,n

其中γ=fracγ^||w||,出于简化计算的考虑,令 γ^=1(对目标函数的优化没有影响,证明略),此时,我们的目标由(1)转换为
s.t.max1||w||(2)yi(wTxi+b)=γi^1i=1,2,...,n(3)

通过求解上面这个问题,我们就可以得到图中超平面的方程。

什么是支持向量?
从图中可以看出,两个支撑着中间间隙的超平面,它们到中间分类超平面的距离相等,即几何间隔γ,而支撑这两个超平面的点便叫做支持向量。

从原本是问题到对偶问题

之前我们要求解式(2),由于对||w||求最大等价于对1||ω|| 求最小,则原问题等价于

s.t.min12||w||2(4)yi(wTxi+b)=γi^1i=1,2,...,n(5)

到了这一步,可以看出来这是一个二次凸优化问题。由于其特殊结构我们可以通过Lagrange对偶变换来求解出问题。
下面对Lagrange对偶性的进行简单的解释
假定f(x),ci(x),hj(x)是定义在Rn上的连续可微函数,考虑约束最优化问题
s.t.minf(x)ci(x)0,i=1,2,3...,khj(x)=0,j=1,2,...,l

引入广义拉格朗日函数
L(x,α,β)=f(x)+i=1nαici(x)+j=1lβihj(x)

这里αi0
然后代入在我们的问题中,有
L(x,α,β)=frac12||ω||2+i=1nαici(x)+j=1lβihj(x)(6)

然后令θ(ω)=maxα>0L(ω,b,α)
则问题转化为
minmaxθ(ω)(7)

在满足KKT条件的情况下(KKT条件略,但是可证明,我们这个问题是满足KKT条件的),该问题转换为
maxminθ(ω)(8)

求解对偶问题

于是接下来我们的任务就是:(1)固定αθ(ω)求极小,得到关于α的表达式(2)对α求极大,(3)利用SMO求对偶因子。
第一步 先固定α,对θ(ω)求偏导。

callω=0ω=i=1nαiyixi(9)

callb=0i=1nαiyi=0(10)

将结果代入式(6)得
L(x,α,β)=i=1nαi12i,j=1nαiαjyiyjxixj(11)

第二步 由于有了式(11),问题转化为
s.t.maxαi=1nαi12i,j=1nαiαjyiyjxixjα0,i=1,2,...,ni=1nαiyi=0

要对α求极大,最有效地方法是SMO算法。

用松弛变量处理离群点

在讨论SMO算法之前,我们先说说另一个问题————离群点的处理。我们起初的假设是数据都是线性可分的,假如我们的数据中存在离群点,原有的模型会受到很大的影响,如下图
这里写图片描述
用黑色圈出来的蓝色点就是一个离群点。如果没有这个点,我们的模型会得到红色实线所示的分类器。但是由于有了这个点,现在得到的分类器会是如虚线所示,显然这个分类器的间隔比之前分类器的间隔要小。要是该离群点还往上一点,我们甚至无法利用我们的模型来构造分类超平面。
为了解决离群点问题,svm在一定程度上可以支持离群点。如上图,将离群点移动到蓝色实线所示的支持平面上,超平面就不会改变了。为此,我们引入了松弛变量ξ。我们原来的约束条件是

yi(wTxi+b)=γi^1i=1,2,...,n

现在有了离群点,约束条件变为
yi(wTxi+b)=γi^1ξii=1,2,...,n

ξ表示的是离群点偏离函数间隔的量,如果我们允许ξi任意大,那么任意超平面都是符合条件的。所以,我们还要子啊优化目标上加上一项,使得ξi的总和最小,新优化目标是
s.t.min12||w||2+Ci=1nξi(12)yi(wTxi+b)=γi^1i=1,2,...,nξi0,i=1,2,...,n

其中C是控制目标函数中2项的权重的参数。然后我们按照之前的步骤对式(12)求偏导,回代,会得到一个和原来一样的目标函数(巧合?)不过由于我们有Cαiri=0又有ri0(拉格朗日乘数法的条件),因此有αiC,所以最后的问题转化为
s.t.minα12i,j=1nαiαjyiyjxixji=1nαi(13)0αC,i=1,2,...,n(14)i=1nαiyi=0(15)

SMO算法

到这一步,我们有了式(13)-(15),我们现在来看一看SMO是怎样求解的。
首先,更具KKT条件得出αi的取值意义:
ui=ωx+b

yiui>1α=0(16)yiui=10<α<C(17)yiui<1α=C(18)

  • 式(16)表示分类正常,点在边界内部。
  • 式(17)表示点在边界上。
  • 式(18)表示点在边界之间。

以下情况会出现不满足:

yiui>1,α>0(16)yiui=1,α=0|C(17)yiui<1α<C(18)

在引入松弛变量后,上述不满足条件变为
Ei=uiyi
αi<C,yiEi<ξαi>0,yiEi>ξ

我们要将所有不满足条件的αi调整为满足条件,然而,由于ni=1αiyi=0,所以我们需要通过某种方法同时调整两个α。SMO算法住主要步骤就是(1)选择接下来需要更新的一对αiαj:采用启发式的方式进行选择,从而使目标函数最大程度接近全局最优值。(2)将目标函数对αiαj进行优化。然后重复直到收敛。更新αiαj的步骤如下:
假定需要更新某两个αiαj,有αnewiyi+alphanewjyj=alphaiyi+αjxj
利用上式,我们可以得到
αnewj=αjyj(EiEj)η

其中$$\eta = 2*

αj=HαnewjHαL<αnewj<HLαjL

其中,H和L分别为

{L=max(0,αjαi)H=min(C,C+αjαi)αiαjL=max(0,αi+αjC)H=min(C,αj+αi)αi=αj

然后就有
αi=αi+yiyj(αoldjαj)

而关于αiαj的选择,包括两点:
1.扫描所有α,选择第一个违反KKT的作为αj
2.在不违反KKT的乘子中,选取使得|EjEi|最大的αi
然后,可计算出b

b=b10<αi<Cb20<αi<C1b1+b2other

其中,
b1=bEiyi(αiαoldi<xi,xi>)yj(αjαoldj<xi,xj>)b2=bEjyi(αiαoldi<xi,xi>)yj(αjαoldj<xj,xj>)

这样,一次迭代后我们就更新了α和b,迭代多次后,我们就可以得到最优的α。然后利用f(x)=ωx+b=ni=1αiyi<xi,x>+b即可得到分类器。
最后代码

##SVMimport numpy as np;def load(filename):    fr = open(filename);    data=[];label=[];    for line in fr.readlines():        lineArr = line.strip().split('\t');        data.append([float(lineArr[0]),float(lineArr[1])]);        label.append(float(lineArr[2]));    return data,label;#简化版选择alpha_jdef Salphaj(i,m):    j = i;    while(j==i):        j = np.random.uniform(i,m);    return int(j);#规范化alpha_jdef clip(aj,H,L):    if(aj>=H):        aj=H;    elif(aj<=L) :        aj=L;    return aj;def antiKKT(alphai,ui,yi,toler,C):      if(yi*ui < -toler and alphai<C or yi*ui > toler and alphai>0 ):        return True;    return False;def LH(alphai,alphaj,a,C):    if(a):        return max(0,alphai+alphaj-C),min(C,alphai+alphaj);    else:        return max(0,alphaj-alphai),min(C,C+alphaj-alphaj);#X:数据 numpy数组格式#Y:标签 numpy数组格式#alpha 参数,numpy数组格式#C:参数 实数def SMO(X,Y,C,toler,max):    X = np.mat(X);    Y = np.mat(Y).T;    m,n = np.shape(X);    alpha = np.mat(np.zeros((m,1)));    b=0;    iter = 0;    while(iter<max):        change = 0;        for i in range(m):            xi=X[i,:]            yi=Y[i,:]            ui = np.multiply(alpha,Y).T*(X*xi.T)+b;            ei = float(ui)-float(yi);            alphai = alpha[i].copy();            #alphai满足KKT就跳过,选择下一个alphai。否则,选择alphaj进行优化            if(antiKKT(alphai,ei,yi,toler,C)):                j = Salphaj(i,m);                alphaj = alpha[j].copy();                xj = X[j,:];                yj= Y[j,:];                uj = np.multiply(alpha,Y).T*(X*xj.T)+b;                ej = float(uj)-float(yj);                L,H = LH(alphai,alphaj,yi==yj,C);                if L==H:  continue;                eta = 2*(xi*xj.T)-(xi*xi.T)-(xj*xj.T);                if eta >= 0: continue;                alpha[j] = alphaj - yj*(ei-ej)/eta;                alpha[j] = clip(alpha[j],H,L);                if(abs(alpha[j]-alphaj)<0.00001):continue;                alpha[i] = alphai+yi*yj*(alphaj-alpha[j]);                b1=b-ei-yi*(alpha[i]-alphai)*(xi*xi.T)-yj*(alpha[j]-alphaj)*(xi*xj.T);                b2=b-ej-yi*(alpha[i]-alphai)*(xi*xi.T)-yj*(alpha[j]-alphaj)*(xj*xj.T);                if(alpha[i]>0 and alpha[i]<C):  b = b1;                elif((alpha[j]>0 and alpha[j]<C)): b= b2;                else:   b = (b1+b2)/2.0;                change = change+1;        if(change == 0) :iter += 1;        else:iter=0;    return alpha,b##可视化### x特征矩阵,numpy数组格式### y类标签,numpy数组格式def plotFit(x,y,alpha,b):    import matplotlib.pyplot as plt;    x1=[]; y1=[]; #类别为1的点    x2=[]; y2=[];    m = np.shape(x)[0];    for i in range(m):        if(y[i]==-1) :            x1.append(x[i][0]);            y1.append(x[i][1]);        else:            x2.append(x[i][0]);            y2.append(x[i][1]);    plt.scatter(x1,y1,c='red');    plt.scatter(x2,y2);    a=np.arange(2.0,8.0,0.1);    x=np.mat(x);    y=np.mat(y).T;    w= sum(np.multiply(np.multiply(alpha,y),x));    w0 =w[0,0];    w1 = w[0,1];    b0 = b;    y = (-w0*a - b[0,0])/w1;    plt.plot(a,y);    plt.show();    plt.figure(2);data,label = load('testSet.txt');alpha,b = SMO(data,label,0.6,0.001,40);print(alpha[alpha>0]);print(b)plotFit(data,label,alpha,b)

下载在这:github地址

总结

可以看到,svm的思路非常清晰,首先建模利用间隔最大对点进行分类,然后 由此引出求最大间隔超平面的问题,进而将问题转换为求解凸二次规划的问题,引入拉格朗日乘子,在这里,为了处理离群点,引入了松弛变量,然后利用SMO求解该问题,即求得最优超平面。整个一气呵成,充分展现的数学之美。还要说的一点是,我只介绍了svm对线性可分的点进行分类,实际上,对于线性不可分的点,svm在引入核方法之后,也能有很好的性能。可以说核方法才是svm的精髓,大家有兴趣可以去深入学习。

参考资料:支持向量机通俗导论

0 0
原创粉丝点击