机器学习记录4and5 支持向量机

本文的参考有《机器学习》,《机器学习实战》,清华深研曾龙老师《机器学习》课程。

拉格朗日乘子:

梯度 、方向导数:先理解偏导数:三维空间中,用y=a,x=0或x=a,y=0的平面去截空间中的曲面,得到一条曲线,这个平面上的曲线的切线的斜率便是偏导数的值,方向导数:上面的平面换成y=ax+b,其他同理(这个a就表示了在xy面的方向)。全导数:方向导数中切出来的这条曲线映射到xz或yz面,在这个面的切线的斜率值。梯度是最大的方向导数。(参考马同学学数学)
梯度向量:是等高线的法线,与等高线的切线垂直。
拉格朗日乘子法定义: mimax f,s.t. g=0。(几何关系可参考:马同学学数学(知乎)。)(重点:多元的,其次有一个是目标方程(表现为等高线),一个是约束条件,找到这两个线相切的点极值点,这个相切就表现为他们的梯度向量方向相等,值可以是)。(至于为什么要找极值点,是因为大多数优化问题就是找到极大值极小值)

KTT条件:

拉格朗日乘子法是等式约束,对于不等式约束条件需要再加一个h(x<=0,小于时不起约束作用,等于时起约束作用。

SVM预备知识:

线性模型:找超平面分开样本。机器学习记录4and5 支持向量机_第1张图片

三个重要的平面:如图中二分类所示,+和-指的是标签,x1、x2是属性取值(当有两种以上的属性时变成多维空间),中间是划分超平面,还有两个支持向量所在的平面(支持平面)。两个支持平面就是离两种类别最近的两个平面。
模型优化基本型:便是寻找w和b使得这两个支持平面的间隔y=1/w最大。
注意:这里1/w是优化关键,后续的数学推导都是基于此展开。

线性可分SVM(硬间隔):

使1/w最大,也就是是使w最小,另外还有约束条件,这是优化的基本公式:
机器学习记录4and5 支持向量机_第2张图片
通过一系列公式转换成对偶问题,推导公式可自行推导,不懂的可参照网上已有的,这里放出推导完成的。
机器学习记录4and5 支持向量机_第3张图片
最后模型只与支持向量有关,不需要保留训练样本。(这也称作稀疏性)
求解对偶问题的思路如下:
机器学习记录4and5 支持向量机_第4张图片
机器学习记录4and5 支持向量机_第5张图片
机器学习记录4and5 支持向量机_第6张图片
这样,解出来a,b,w训练得到支持向量后,用于测试。
为了加快收敛,有了两个启发式选择方法:(算法改进)
机器学习记录4and5 支持向量机_第7张图片

线性近似可分SVM(软间隔)

软间隔也就是样本空间不是完全线性可分,会有一些特异点。
将约束改为:在这里插入图片描述

线性不可分SVM(核技巧)

不能通过超曲面分开,需要升维。
核函数,实际上是内积,给出了两个样本之间关系的度量例如相似度,用来减少前面直接非线性转换的计算量。选用核函数就是把x1,x2,z上下左右前后拉扯得到一个好分的空间。需要根据领域知识选择核函数,经验:对文本,常采用线性核;情况不明时,可先尝试高斯核。

作业:将二分类器变成多分类器,识别手写符

思路有间接法和直接法,间接法有ovo,ovr两种,这里采用ovr,,ovr 是指训练时把某个类别作为正类,其余类别作为反类,这样构成了 k 个二分类,k 个二分类器得到的结果得到正面结果的便是最终多分类结果。
由于可能有多个二分类判别为正面结果,需要根据结果的正面程度,将正面程度更大的那个作为最终结果。
编程思路:
(1)先做十个分类器;
(2)训练时得到十个支持向量;
(3)预测时,将每个样本通过十个分类器得到十个结果,将十个结果中是正面结果的分类器的序号存储到 conindex 中,判断 conindex 中的个数。如果等于 0,说明判别失败,如果等于 1,那么恰好这个序号便是预测结果,如果大于 1,则比较不进行 sign 之前的预测值,选择更大的那个,其对应的分类器序号作为预测值。

部分核心的伪代码:

1. 先做十个分类器
def jloadImages(dirName,j): #十个分类器
m = len(trainingFileList) #m个样本向量
    for i in range(m):
        classNumStr = Function< dirName > #原始标签
        if classNumStr == j: 
            hwLabels.append(1)  #制定分类器,是j的标签为1,其余九个都为-1
        else: hwLabels.append(-1)
        trainingMat[i,:] = Function< img2vector(dirName, fileNameStr)>#样本空间

2. 然后训练
def multisvm(kTup=('rbf', 10)): 
    fname = ‘trainingDigits'
    for j in range(10)
    {
        datMat, labelMa = Function< jloadImages(fname,j)> #加载文件
        singleb,singlealphas= smoPK(dataArr, labelArr) #算单个分类器的b和a
        b←singleb;alphas← singlealphas  #将十个分类器的b和a存进去
        singlesVs,singlelabelSV =Function
#算单个分类器的支持向量
sVs←singlesVs; labelSV ←singlelabelSV#存储十个分类器的支持向量
        m,n = shape(datMat)
        errorCount = 0
        for i in range(m)
{
            kernelEval = Function#核函数
            predict=Function< predict(kernelEval>  #分类器进行预测
if sign(predict)!=sign(labelMat[i]):
 errorCount += 1
            }
        trainErr =errorCount/m #单个分类器的训练误差
    }

3. 最后预测
fname = ‘testDigits'
    trainingFileList = listdir(fname)  #加载文件
    m = len(trainingFileList)  #m个样本
    for i in range(m)
      {
        labelMat :=Function< trainingFileList > #m个原始标签
        trainingMat:=Function#样本空间(m,1024)
      }
    for k in range(m) #对每个样本都进行十个分类器预测
      {
        for j in range(10):
          {
            kernelEval = Function< kernelTrans(sVs[j],trainingMat[k,:])>
            predict[j]= Function#预测
            if sign(predict[j])==1:
                conindex.append(j) #记录十个分类器中预测值为1的分类器的序号
          }
        #下面根据分类器预测为1的分类器数量的三种情况,判断最终预测值
        if len(conindex)==0
          {
            all_error+=1  #分类器预测为1的数量为0,说明无法判断
          }
        if len(conindex)==1
          {
            finalpredict[k]=conindex[0]  #数量为1,分类器的序号也就是预测值
            if finalpredict[k]!=labelMat[k]:
{ all_error+=1 } #预测与实际不符,误差+1
          }
        if len(conindex)>1:
          {
            lenindex=len(conindex)
            for i in range(lenindex):
                y[i]=predict[conindex[i]] #把所有是1的不sign前的预测值放到一起
            chooseindex=conindex[y.index(max(y))] #找到预测值最大的那个,选择这个作为预测结果
            finalpredict[k]=chooseindex
            if  finalpredict[k]!=labelMat[k]
{ all_error+=1 } ##预测与实际不符,误差+1
          }
      }
    testErr = all_error/m #总判断错误的样本/总样本为测试误差

svm的运行时间很长,需要调整的参数多,例如:核函数的选择,krup的选择,不如KNN来得快速方便。

你可能感兴趣的:(机器学习,python,机器学习,svm)