机器学习:支持向量

SVM支持向量机

一、简介

支持向量机(support vector machines)是一种二分类模型,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化,最终转化为一个凸二次规划问题来求解。由简至繁的模型包括:
●当训练样本线性可分时,通过硬间隔最大化,学习一个线性可分支持向量机
●当训练样本线性不可分时,通过核技巧和软间隔最大化,学习一个非线性支持向量机

二、线性可分支持向量机

具体介绍参阅以下网址
1.支持向量机的原理介绍
2.拉格朗日数乘以及KKT介绍
SMO求解算法(简化版)
1.数据的收集处理:

def load_data_set(file):
    orig_data = file.as_matrix()   
    cols = orig_data.shape[1]
    data_mat = orig_data[:,0:cols-1]
    label_mat = orig_data[:,cols-1:cols]
    return data_mat, label_mat

2.还需要定义一个select_jrand函数,该函数的功能是给定输入i和m,随机输出一个0到m之间的与i不同的整数。这个函数在后面将会用到:

def select_jrand(i, m):
    j = i
    while(j==i):
        j = int(random.uniform(0,m))
    return j

3.此外还需要定义一个clip_alpha函数,该函数的功能是输入将aj限制在L和H之间

def clip_alpha(aj, H, L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj

4.接下来是主体功能的实现函数,由于这个函数太长,为了方便理解,将以下代码分成一小段一小段的,这样就可以理解每一小段的功能。
1)循环外的初始化工作:首先该函数的输入为特征矩阵、类标签向量,常数C,容错率,最大迭代次数。首先将输入的特征矩阵和类标签向量都转化为矩阵(若特征矩阵和类标签向量已经是矩阵,则不需要这个步骤,若输入的是列表的形式,则需要该步骤),设置b为0,m和n分别为特征矩阵的行数和列数。创建一个m行1列的αα向量(即有多少个样本点就有多少个αα),迭代次数初始化为0(每次迭代在αα向量中寻找一对可以改变的αα,若没有找到则迭代次数+1,达到最大迭代次数还没有找到可以改变的αα,说明已经αα已经优化的差不多了,则退出循环)。
2)内循环的初始化工作:现在开始第一轮迭代,将改变的一对αα的数量alpha_pairs_changed初始化为0,然后遍历m个αα依次作为第一个αα,再在(0,m)范围内随机的找到第二个αα(第二个αα与第一个不能是同一个,这就用到了之前定义的select_jrand函数)。
3)第一小段代码:首先从i等于0开始,已知公式W=∑niαiyiXiW=∑inαiyiXi,若第0号数据点是支持向量,则该数据点必然在虚线WTX+b+1=0WTX+b+1=0或WTX+b−1=0WTX+b−1=0上,即WTX+b=−1WTX+b=−1或WTX+b=+1WTX+b=+1。

先将0号数据点带入公式求出WW,即代码中的WT_i,再将0号数据点和求得的WW带入WTX+bWTX+b求出WTX+bWTX+b的值,即代码中的f_xi。

代码中的E_i为得到的f_xi与实际的WTX+bWTX+b之间的误差,而这个误差大有说道,最完美的情况是若数据点是支持向量,则将数据点带入WTX+bWTX+b应该等于-1或+1,即该数据点应该在虚线WTX+b+1=0WTX+b+1=0或虚线WTX+b−1=0WTX+b−1=0上,而如果该数据点的类标签yiyi和误差E_i的乘积大于容错率,说明该数据点属于+1类且在WTX+b−1=0WTX+b−1=0的上侧,或者该数据点属于-1类且在WTX+b+1=0WTX+b+1=0的下侧。也就是说该点在属于自己的那一类的群体里,但是太靠后了且靠后的超过限度了(即大于容错率),根本无法作为支持向量,而这个点对应的αα值又大于0,说明这明明就不该是靠后站的,那么就要调整这个数据点的αα了。而另一种情况是该数据点的类标签yiyi和误差E_i的乘积小于负容错率,说明该点太靠前了已经处于虚线WTX+b+1WTX+b+1和虚线WTX+b−1WTX+b−1之间了,且该点的αα值又小于常数C,说明该点也不应该是靠前的,那就要调整这个数据点的αα了

若经过上述判断,决定要调整该数据点的αα,那么就调用之前定义的select_jrand函数随机的选择另一个要调整的αα,对另一个alphaalpha对应的数据点也计算相应的误差E_j,为了记录αα的调整情况,分别copy一下作为αiαi和αjαj的旧值。

4)第二小段代码:由于有一个限制条件即∑niαiyi=0∑inαiyi=0,且任意的αα在(0,C)之间,所以当调整其中一个αiαi的时候,另一个αjαj的改变必须有一定限制,即yiαi+yjαj=kyiαi+yjαj=k。
5)第三小段代码:下面为αj的更新公式:
αj=αj−yj(Ei−Ej)η
其中η=2<Xi,Xj>−<Xi,Xi>−<Xj,Xj>η=2<Xi,Xj>−<Xi,Xi>−<Xj,Xj>。(尖括号表示两个向量的内积)
更新前先对ηη进行判断,若η≥0η≥0则退出本次循环,不进行更新。否则对αjαj进行更新。更新后需要调用之前定义的clip_alpha函数,将更新后的αjαj缩小在这个范围之内,最后检验一下αjαj值改变了多少,如果改变的太少,就不要更新了,直接退出本次循环寻找下一对αα,改变那点值没什么意义。
最后既然αjαj更新了,αiαi也得随之改变,且该变量应该是相等的,根据之前所述的yiαi+yjαj=kyiαi+yjαj=k,可以得到更新后的αi的值

6)第四小段代码:对于样本点i,已经更新了其αiαi值,若b值也是正确的,则该点应该从更新之前的不在WTX+b±1=0WTX+b±1=0上,更新到位于WTX+b±1=0WTX+b±1=0上,亦即将样本点i带入,得到Enewi=WnewTXi+bnew−yi=0Einew=WnewTXi+bnew−yi=0。
同时又已知Eoldi=WoldTXi+bold−yiEiold=WoldTXi+bold−yi,根据上述两个公式,可以得到:
bnew=bold−Eoldi+WoldTXi−WnewTXi
bnew=bold−Eiold+WoldTXi−WnewTXi
前两项不用多说,最后两项的相减,有些说道,因为W=∑ni=1αiyiXiW=∑i=1nαiyiXi,所以其实WoldWold和WnewWnew的区别只在里面的αiyiXiαiyiXi和αjyjXjαjyjXj不同,只要把公式展开成向量的形式写出来就很容易看出来,二者相减之后的结果就是:
yi(αiold−αinew)<Xi,Xi>+yj(αoldj−αnewj)<Xj,Xi>
yi(αiold−αinew)<Xi,Xi>+yj(αjold−αjnew)<Xj,Xi>

将后两项带入,就可以得到bnewbnew。
当然这里得到的是根据样本点i求得的bnewbnew,根据样本点j做同样操作,可以得到另一个bnewbnew,此时若更新后的αiαi在限定范围内,则b=bnew1b=b1new,若αjαj在限定范围内,则b=bnew2b=b2new,若αiαi和αjαj都在限定范围内,则b=b1+b22b=b1+b22。
7)收尾工作:若程序运行到此处,则已经更新了一对αα,并且也更新了bb值,则将alpha_pairs_changed加上1,代表更新了一对,继续更新下一对。若程序没有执行更新αα的操作,即alpha_pairs_changed=0,则将iter+1,代表迭代了一次,否则将iter置为1,重新开始迭代。若程序迭代的次数达到了最大迭代次数,还没有α被更新,说明已经更新的很好了,则可以退出while循环,返回b值和α向量。

def smo_simple(data_mat, class_label, C, toler, max_iter):
    # 循环外的初始化工作
    data_mat = np.mat(data_mat); label_mat = np.mat(class_label) 
    b = 0
    m,n = np.shape(data_mat)  
    alphas = np.zeros((m,1))       
    iter = 0    
    while iter < max_iter:
        # 内循环的初始化工作
        alpha_pairs_changed = 0
        for  i in range(m):   
            # 第一小段代码  
            WT_i = np.dot(np.multiply(alphas, label_mat).T, data_mat)  
            f_xi = float(np.dot(WT_i, data_mat[i,:].T)) + b   
            Ei = f_xi - float(label_mat[i])    
            if((label_mat[i]*Ei < -toler) and  (alphas[i] < C)) or \
            ((label_mat[i]*Ei > toler) and (alphas[i] > 0)):  
                j = select_jrand(i, m) 
                WT_j = np.dot(np.multiply(alphas, label_mat).T, data_mat)
                f_xj = float(np.dot(WT_j, data_mat[j,:].T)) + b    
                Ej = f_xj - float(label_mat[j])    
                alpha_iold = alphas[i].copy()
                alpha_jold = alphas[j].copy()

               # 第二小段代码
                if (label_mat[i] != label_mat[j]):  
                    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 H == L :continue

                # 第三小段代码
                eta = 2.0 * data_mat[i,:]*data_mat[j,:].T - data_mat[i,:]*data_mat[i,:].T - \
                data_mat[j,:]*data_mat[j,:].T
                if eta >= 0: continue
                alphas[j] = (alphas[j] - label_mat[j]*(Ei - Ej))/eta
                alphas[j] = clip_alpha(alphas[j], H, L)   
                if (abs(alphas[j] - alpha_jold) < 0.00001):
                    continue


                alphas[i] = alphas[i] + label_mat[j]*label_mat[i]*(alpha_jold - alphas[j])

                # 第四小段代码
                b1 = b - Ei + label_mat[i]*(alpha_iold - alphas[i])*np.dot(data_mat[i,:], data_mat[i,:].T) +\
                label_mat[j]*(alpha_jold - alphas[j])*np.dot(data_mat[i,:], data_mat[j,:].T)
                b2 = b - Ej + label_mat[i]*(alpha_iold - alphas[i])*np.dot(data_mat[i,:], data_mat[j,:].T) +\
                label_mat[j]*(alpha_jold - alphas[j])*np.dot(data_mat[j,:], data_mat[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
                alpha_pairs_changed += 1
        if (alpha_pairs_changed == 0): iter += 1
        else: iter = 0
    return b, alphas
————————————————
版权声明:本文为CSDN博主「weixin_41090915」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41090915/article/details/79177267

非线性支持向量机和核函数

对于非线性问题,线性可分支持向量机并不能有效解决,要使用非线性模型才能很好地分类。先看一个例子,如下图,很显然使用直线并不能将两类样本分开,但是可以使用一条椭圆曲线(非线性模型)将它们分开。非线性问题往往不好求解,所以希望能用解线性分类问题的方法求解,因此可以采用非线性变换,将非线性问题变换成线性问题。
在这里插入图片描述
对于这样的问题,可以将训练样本从原始空间映射到一个更高维的空间,使得样本在这个空间中线性可分,如果原始空间维数是有限的,即属性是有限的,那么一定存在一个高维特征空间使样本可分。令ϕ(x)表示将 x 映射后的特征向量,于是在特征空间中,划分超平面所对应的的模型可表示为:
f(x)=wTϕ(x)+b

于是有最小化函数:
在这里插入图片描述
其对偶问题为: 在这里插入图片描述
若要对公式(16)求解,会涉及到计算ϕ(xi)Tϕ(xj)ϕ(xi)Tϕ(xj),这是样本 xi 和 xj映射到特征空间之后的内积,由于特征空间的维数可能很高,甚至是无穷维,因此直接计算ϕ(xi)Tϕ(xj)ϕ(xi)Tϕ(xj)通常是困难的,于是想到这样一个函数:
在这里插入图片描述
即 xi和 xj在特征空间中的内积等于他们在原始样本空间中通过函数 κ(xi,xj)计算的函数值,于是公式(16)写成如下:
在这里插入图片描述
求解后得到:
在这里插入图片描述
这里的函数 κ(xi,xj) 就是核函数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值