支持向量机svm

一.基本概念

  svm是现成的很好的分类器,因为它能够不加修改的,直接应用于训练集,并且效果也不错。svm从直观上来时是找到分割两类数据的最佳的gap,即最大的间隔(margin)。

  那既然svm是在找最大间隔,那什么是间隔呢?间隔指的就是支持向量和分割超平面之间距离。那支持向量又是什么呢?支持向量指的就是离分割超平面距离最近的那些点。

  那要怎么寻找这个最大化间隔呢?从它的定义上,我们可以知道只要我们确定了分割平面就可以求出一个间隔,然后将这个间隔的最大化,这就是我们要求的最大化间隔。所以svm从本质上说是在分割超平面。把它转换成数学表达如下:
    

  在上图中蓝线表示最佳的分类超平面,虚线之间的就是gap。那么svm问题就是要最大这个gap。目标函数为:

  arg max{min lable * wTx*1/||w||}

  s.t:

  lable * wTx >=1

  利用拉格朗日函数将其进行变换,就可以得到:

  max{}

  s.t:

        

  当数据集中出现一些噪声点干扰时,需要加入松弛变量,松弛变量就是为了保证当数据点落在gap中时,依然能够被正确分类。要满足这个要求,只需要改变一下约束条件,目标函数不变,此时约束条件变为:
  s.t:

  

  可见加不加松弛变量,他们的区别在于a的取值范围。

  优点:计算的开销比较小,并且泛化错误率低,结果也比较容易理解。未加修改的原始的svm分类器,可以直接应用于二分类问题。

  缺点:对于参数和核函数的选择很敏感。

二.smo高效优化算法

  smo算法是实现svm的一个最常用的算法。全称是序列最小化算法。

  smo算法的工作原理是每次循环选择两个alpha进行处理。一旦找到合适的alpha就对其中的一个进行增加,另一个进行减小。合适的alpha,指的是它要满足一定的条件,一个是这两个alpha必须在边界之外,另一个是这两个alpha还没有进行过区间化处理或者不在边界上。

三.简化版的smo算法实现

  首先要知道几个公式:

  (1)

  (2)

  (3)

   (4)

  (5)

总的伪代码:

初始化alpha向量

初始化b

当迭代次数小于最大迭代次数:
  记录alpha对变化的次数

  对于每一数据向量:

    计算出Ei的值

    如果alphai可以进行更改:

      随机选择除i外的数据向量j

      计算出Ej的值

      记录此时alphai,j的值

      根据第一个公式计算出此时的H,L的值

      如果H==L,那么直接跳出本次循环

      根据第二公式计算出eta的值

      如果eta的值大于0,跳出本次循环

      根据公式二计算出此时的alphaj的值

      限制alphaj的值不能大于等于C,不能小于等于0

      如果alphaj的变化量太小(比如小于0.0001),跳出本次循环

      根据第三个公式计算出alphai的值

      根据第四个公式计算出b1,b2的值

      根据第五个公式确定b的值

      将alpha对变化的次数加1

  判断alpha对变化的次数是不是等于0,是的话迭代次数加一,否则迭代次数置0

   

它的python实现

                                                                                                                                                                                 

from random import random
from numpy import *
# load the special data
def loaddata(filename):
    dataset = []
    datalabel = []
    fr = open(filename)
    for line in fr.readlines():
        frlines = line.strip().split('\t')
        dataset.append([float(frlines[0]), float(frlines[1])])
        datalabel.append(float(frlines[2]))
    return dataset, datalabel

# select j  where j != i and j in range(0,m)
def selectJ(i, m):
    j = i
    while j == i:
        j = int(random.uniform(0, m))
    return j

# limit i smaller than H, and bigger than L
def limiti(i, l, h):
    if i > l:
        i = l
    if i < h:
        i = h
    return i

def smosimple(dataset, datalable, C, toler, timeinter):
    data = mat(dataset)
    classlable = mat(datalable).transpose()
    m, n = shape(data)
    alpha = mat(zeros((m,1)))
    b = 0
    inter = 0
    while inter<timeinter:
        alphapairchange = 0
        for i in range(m):
            fxi = float(multiply(alpha, classlable).T*data*data[i,:].T) + b
            ei = fxi - classlable[i]
            if (classlable[i]*ei<-toler and alpha[i]<C) or (classlable[i]*ei > toler and alpha[i] >0):
                j = selectJ(i, m)
                fxj =float(multiply(alpha, classlable).T*data*data[j,:].T) + b
                ej = fxj - classlable[j]
                alphaiold = alpha[i].copy()
                alphajold = alpha[j].copy()
                if classlable[i] != classlable[j]:
                    h = min(C, C+alphajold-alphaiold)
                    l = max(0, alphajold-alphaiold)
                else:
                    h = min(C, alphaiold+alphajold)
                    l = max(0, alphaiold+alphajold-C)
                if h == l:
                    continue
                eta = 2.0*data[i,:]*data[j,:].T - data[i,:]*data[i,:].T -data[j,:]*data[j,:].T
                if eta>=0:
                    continue
                alpha[j] -= classlable[j]*(ei-ej)/eta
                alpha[j]=limiti(alpha[j], h, l)
                if (alpha[j]-alphajold)<0.00001:
                    continue
                alpha[i] += classlable[i]*classlable[j]*(alphajold-alpha[j])
                b1 = b - ei - classlable[i]*(alpha[i] - alphaiold)*data[i,:]*data[i,:].T\
                    - classlable[j]*(alpha[j]- alphajold)*data[i,:]*data[j,:].T
                b2 = b - ej - classlable[i]*(alpha[i] - alphaiold)*data[i,:]*data[j,:].T\
                    - classlable[j]*(alpha[j]- alphajold)*data[j,:]*data[j,:].T
                if (alpha[i] <= C) and (alpha[i] >=0):
                    b = b1
                elif (alpha[j] <= C) and (alpha[j] >= 0):
                    b = b2
                else:
                    b = (b1+b2)/2
                alphapairchange += 1
        if alphapairchange == 0:
            inter += 1
        else:
            inter = 0
    return alpha, b

上述是简单的smo算法,还有一种加速的platt smo算法。它的改进在于不是遍历每一个alpha,而是目标在于调整值位于0到C之间的alpha分量。它遍历一个alpha,找到alpha的分量值在0到C之间的分量,然后调整这些分量,不断的重复以上三个小步骤,知道收敛。根据上述方法第一个alpha分量的值,我们可以随机选择,但是第二个alpha的值,我们需要选择误差最大的alpha分量,也就是使ei-ej最大对应的alpha分量。

具体的思路:

 

以下是详细的python代码

 

                                                                                                                                                                                                                                                                                                                                                                     

四.参考资料

推荐大家看看on2way的SVM系列:

http://blog.csdn.net/on2way/article/details/47729827

posted @ 2017-04-20 20:48  whatyouknow123  阅读(217)  评论(0编辑  收藏  举报