首页 > 其他 > 详细

支持向量机SVM

时间:2014-03-04 08:37:03      阅读:555      评论:0      收藏:0      [点我收藏+]

SVM算是整本书最不好理解的一块了,也是代码最多的一块。

6.1前奏

优点:泛化错误率低,计算开销不大,结果易解释。

缺点:对参数调节和核函数的选择敏感(不懂什么是核函数?没关系,继续往下看呗),原始分类器不加修改仅适用于处理二类问题。

鉴于SVM不怎么好理解下面先给出一些概念。

①分隔超平面:N维的数据需要N-1维的某某对象来对数据集进行分隔,该对象就被称为超平面,分布在超平面一侧的所有数据都属于某个类别,而分布在另一侧的所有数据都属于另一个类别。如二维数据,分隔超平面是一条直线,三维数据,分隔超平面是一个平面等等。

②基于最大间隔来构建分类器:找到离分隔超平面最近的点,确保它们离分隔面的距离尽可能远(点到分隔面的距离称为间隔),间隔越大,结果越可信,分类器越健壮。

③支持向量:指离分隔超平面最近的那些点。

现在知道SVM(support vector machines)是什么意思了吧。然后要做的工作就是最大化支持向量到分隔面的距离。

④该如何寻找最大间隔呢?

分隔超平面的形式可以写成wTx+b,那么点A到分隔超平面的距离就是|wTA+b|/|w|, 常数b类似于Logistic回归中的截距w0。这样由向量w和常数b就刻画了所给数据的分隔线或超平面。

 ⑤单位阶跃函数,用其对wTx+b作用得到f(wTx+b),若wTx+b<0则输出-1,反之输出+1(-1,+1表类别)。

剩下的一大堆工作就是在求w和b.

找到最小间隔的数据点,再对间隔最大化,写作:(公式难写就不写了,見书吧),由于求解困难引入拉格朗日乘子最后优化目标函数转化为:(公式难写就不写了,見书吧),约束条件:C≥α≥0,和Σαi·label(i)=0

好了,去求alpha吧,求得以后和label一乘就是w了,就可以得到分隔超平面了。

6.2 SMO高效优化算法之简化版的SMO

由于存在约束条件:Σαi·label(i)=0(鉴于浏览器不支持在word里编写好的公式粘贴在这里,就这么丑丑的放着吧),所以要同时改变两个alpha,首先在数据集上遍历每一个alpha,然后再剩下的alpha集合里随机选择另一个alpha,从而构建alpha对,增大其中一个同时减小另一个。当然这两个alpha 要符合一定的条件:必须要在间隔边界之外,还没有经过区间化处理或者不在边界上。

首先当然是要构建一些辅助函数:

def loadDateSet(fileName):#准备数据,老生常谈了。
  dataMat=[];labelMat=[]
  fr=open(fileName)
  for line in fr.readlines():
    lineArr=line.strip().split(‘\t‘)
    dataMat.append([float(lineArr[0]),float(lineArr[1])])
      labelMat.append(float(lineArr[2]))
  return dataMat,labelMat


def selectJrand(i,m):#构建alpha对
  j=i
  while(j!=i):
    j=int(random.uniform(0,m))
  return j


def clipAlpha(aj,H,L):#保证alpha在H和L之间(即0到C之间)
  if aj>H:
    aj=H
  if L>aj:
    aj=L
  return aj

接下来就可以使用简化版的SMO了,先给伪代码:

创建一个alpha向量并将其初始化为0向量#因为alpha的最小值为0

当迭代次数小于最大迭代次数时(外循环)

  对数据集中的每个数据向量(内循环):

    如果该向量可以被优化:

      随机选择另外一个数据向量

      同时优化这两个向量

      如果这两个向量都不能被优化,退出内循环

如果所有向量都不能被优化,增加迭代次数目,继续下一次循环.代码来了(不要问太多问题,我也不是理解的十分十分透彻):

def smoSimple(dataMatIn, classLabels, C, toler, maxIter):#toler容错率
  dataMatrix = mat(dataMatIn); labelMat = mat(classLabels).transpose()
  b = 0; m,n = shape(dataMatrix)
  alphas = mat(zeros((m,1)))
  iter = 0#没有任何alpha改变的情况下迭代的次数
  while (iter < maxIter):
    alphaPairsChanged = 0#是否已经改变alpha
    for i in range(m):
      fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b#预估类别;multiply(alphas,labelMat)相当于w,dataMatrix*dataMatrix[i,:].T数据点为什么要这么算,呜呜呜??
      Ei = fXi - float(labelMat[i])#误差
      if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):#随机选择另一个alpha,如果alpha[i]为0或C的话则已处在边界,无需调整,进行下一次for循环。
        j = selectJrand(i,m)
      fXj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
      Ej = fXj - float(labelMat[j])
      alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();#用来比较前后变化
      if (labelMat[i] != labelMat[j]):#确保alpha在0~C之间
        L = max(0, alphas[j] - alphas[i])
        H = min(C, C + alphas[j] - alphas[i])
      else:
        L = max(0, alphas[j] + alphas[i] - C)
        H = min(C, alphas[j] + alphas[i])
      if L==H: print "L==H"; continue
      eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T#alpha[j]的最优修改量
      if eta >= 0: print "eta>=0"; continue#下边从相反方向改变alphas[i]和alphas[j]的值
      alphas[j] -= labelMat[j]*(Ei - Ej)/eta
      alphas[j] = clipAlpha(alphas[j],H,L)
      if (abs(alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; continue
      alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#update i by the same amount as j,下边设置b的值
      b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T
      b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T
      if (0 < alphas[i]) and (C > alphas[i]): b = b1
        elif (0 < alphas[j]) and (C > alphas[j]): b = b2
      else: b = (b1 + b2)/2.0
      alphaPairsChanged += 1
      print "iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)
    if (alphaPairsChanged == 0): iter += 1
    else: iter = 0
    print "iteration number: %d" % iter
  return b,alphas

就这样吧,头大,我已经写不下去了,等过段时间再看。

                                待续

支持向量机SVM,布布扣,bubuko.com

支持向量机SVM

原文:http://www.cnblogs.com/woshikafeidouha/p/3578773.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!