• 支持向量机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('	')
            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

  • 相关阅读:
    Android App上架流程
    php字符串操作
    SpringBoot配置MongoDB多数剧源
    Spring boot使用influxDB总结
    Spring boot配置MongoDB以及Morphia踩坑记录
    使用Kubernetes的java-client实现Deployment的部署及更新操作
    Golang循环中调用go func参数异常分析
    git tag本地删除以及远程删除
    SpringBoot之GZip压缩,HTTP/2,文件上传,缓存配置
    Java服务使用Redis实现分布式全局唯一标识
  • 原文地址:https://www.cnblogs.com/whatyouknow123/p/6740732.html
Copyright © 2020-2023  润新知