zoukankan      html  css  js  c++  java
  • 使用支持向量机(SVM) 算法进行分类

    1 支持向量机(SVM)的基本概念

      SVM是一种分类算法,其侧重于模式识别方面。使用SVM可以大大提高分类的准确性。

      分类相当于模式识别的子集合,模式识别重点在于对已知数据进行特征发现与提取。

      SVM重点在于解决线性可分的问题。但很多时候,实际的问题是线性不可分的。SVM的思想就是将线性不可分的问题转化线性可分的问题。那么如何来是实现呢?就是将空间映射到多维空间。如把二维空间映射到三维空间。以增加维数来减少方程的次数。

      比如,在二维空间中,不得不用 f(x)=ax2+b+c 这个曲线将两类样本分开,而不是用一条直线将它们分开,这样就是一个线性不可分的问题。为了解决这个问题,我们可以使用换元法将即 x^2=y1 , x=y2 , 这样一来替换为 z=a'y1+b'y2+c' 这个线性方程,从而转换到了高维空间,代价是维度的增加引入了更多的变量。这样我们就完成了从线性不可分问题到线性可分问题的转换。

      所谓支持向量,即在每一类样本集中,过离separating hyper plane 最近的样本做一个与separating hyper plane 平行的线/超平面。有几个分类,就有几个这种直线/超平面,这样的直线/超平面就叫做支持向量(Support Vector)。

    2 核函数

      那么找到一个线/超平面来完成二分类成为问题的关键。这个线/超平面的函数被我们成为“核函数”。常见的核函数有:

    • 线性核函数————linear
    • 多项式核函数————poly
    • 径向基核函数————rbf(用得较多)
    • Sigmoid核函数————sigmoid

      那么如何来选择合适的核函数呢?答案就是比较不同核函数的分类的准确率。在实际处理分类问题时,分别计算几种核函数的分类性能,将准确率最高的核函数作为最终用于预测分类的核函数即可。在本文的例子中,我们使用画图的方式来判断分类性能的好坏。

      使用模型不同,转换的方式不同,在多维空间中的图形就不同,分类的效果就不同。

      网上关于SVM、线性可不可分、核函数的博文很多,如http://www.cnblogs.com/LeftNotEasy/archive/2011/05/02/basic-of-svm.html 。这里就不再赘述。

    3 比较分类效果与子图的划分

      为了比较不同分类器的准确性,我们采用绘制散点图,然后人工观察来判断。我们将两个类的点在坐标系中用不同颜色表示出来,同时标出训练数据,看预测点与训练点的在图中的重叠情况。重叠越紧密,说明分类的效果越准确。

      在绘图的时候,我们希望在一个平面中同时展现多幅图片,这时使用matplotlib模块的子图(subplot)来展现。

    subplot的参数

    	subplot(横向划分个数,纵向划分个数,当前定位)
    

      第一个参数代表的是横向要划分的子图个数,第二个参数代表的是纵向要划分的子图的个数,第三个参数表示当前的定位。

    使用示例一:

    使用示例二:

    使用示例三:

    4 源码

    应用场景

      假设在第一象限有10个点,它们分别是[0, 0], [1, 1], ... , [9, 9]。它们[0,0],[1,1],[2,2],[3,3]属于“0”这个类(类标签为0),另外6个点属于“1”这个类(类标签为1)。
      现在第一象限构造900*900个点,纵横坐标方向上相邻的点距离为0.01。

    [ 0.00, 0.00],[ 0.01, 0.00], [ 0.02, 0.00],..., [ 8.97, 8.99], [ 8.98, 8.99],[ 8.99, 8.99]

      这样,布满区间的点作为预测数据,用各种分类模型进行二分类。最后通过绘图模块给不同类的点上色以判断分类性能。

    import numpy as npy
    import matplotlib.pyplot as plt
    from sklearn import svm
    x=[]#存储样本数据
    y=[]#存储类标号
    for i in range(0,10):#构造10个点作为训练数据
        if(i<=3):#if(i<=3 or i>=8):
            x.append([i,i])
            y.append(0)
        else:
            x.append([i,i])
            y.append(1)
    
    train_x=npy.array(x)#转换为数组
    train_y=npy.array(y)
    
    
    '''
    创建svm分类器的格式:
    svm.SVC(kernel=某个核函数).fit(训练样本,类标签)
    '''
    #linear
    linear_svc=svm.SVC(kernel="linear").fit(train_x,train_y)
    
    #poly 要定义维度,degree决定了多项式的最高次幂.关于SVC参数的意义请参见文章后头的内容。
    poly_svc=svm.SVC(kernel="poly",degree=4).fit(train_x,train_y)
    
    #径向基核函数(这时SVC默认的核函数)
    rbf_svc=svm.SVC().fit(train_x,y)
    
    #Sigmoid
    sigmoid_svc=svm.SVC(kernel="sigmoid").fit(train_x,train_y)
    
    #下面就可以进行预测了
    x1,x2=npy.meshgrid(npy.arange(train_x[:,0].min(),train_x[:,0].max(),0.01),npy.arange(train_x[:,1].min(),train_x[:,1].max(),0.01))
    
    #先生成各个点。定义最小值和最大值后,定义隔多少值建立一个点。
    #npy.arange(train_x[:,1].min(),train_x[:,1].max(),0.01))返回的是900个元素的数组
    #meshgrid函数用来产生矩阵。上面的语句也是就是numpy.meshgrid(numpy.arange(0,9,0.01),numpy.arange(0,9,0.01))
    
    '''
    x1是矩阵 
          [[ 0.  ,  0.01,  0.02, ...,  8.97,  8.98,  8.99],
           [ 0.  ,  0.01,  0.02, ...,  8.97,  8.98,  8.99],
           [ 0.  ,  0.01,  0.02, ...,  8.97,  8.98,  8.99],
           ..., 
           [ 0.  ,  0.01,  0.02, ...,  8.97,  8.98,  8.99],
           [ 0.  ,  0.01,  0.02, ...,  8.97,  8.98,  8.99],
           [ 0.  ,  0.01,  0.02, ...,  8.97,  8.98,  8.99]]
    
    x2是矩阵
          [[ 0.  ,  0.  ,  0.  , ...,  0.  ,  0.  ,  0.  ],
           [ 0.01,  0.01,  0.01, ...,  0.01,  0.01,  0.01],
           [ 0.02,  0.02,  0.02, ...,  0.02,  0.02,  0.02],
           ..., 
           [ 8.97,  8.97,  8.97, ...,  8.97,  8.97,  8.97],
           [ 8.98,  8.98,  8.98, ...,  8.98,  8.98,  8.98],
           [ 8.99,  8.99,  8.99, ...,  8.99,  8.99,  8.99]]
           
    '''
    splocation=1
    for i in [linear_svc,poly_svc,rbf_svc,sigmoid_svc]:#遍历各个模型以便绘图,以看哪个核函数的准确率更高
        rst = i.predict(npy.c_[x1.ravel(),x2.ravel()])#横坐标和纵坐标的组合。x1.ravel()和x2.ravel()都是长度为810000的数组。c_[]用来将前后两个数组串联成一个810000行、2列的矩阵。
    
        #因为上面用到了四种分类模型,那么一个2×2的图就能够显示完全了。
        plt.subplot(2,2,splocation)#第一个参数代表的是横向要划分的子图个数,第二个参数代表的是纵向要划分的子图的个数,第三个参数表示当前的定位
        plt.contourf(x1,x2,rst.reshape(x1.shape))#contourf用来填充颜色。(当前横坐标,当前纵坐标,预测的分类结果(转为x1的规模维数))
    
        #训练数据的点也绘制出来
        for j in range(0,len(y)):
            if(int(y[j])==0):
                plt.plot(train_x[j:j+1,0],train_x[j:j+1],"yo")#y代表黄色,o代表散点图
            else:
                plt.plot(train_x[j:j+1,0],train_x[j:j+1],"ko")#类别为1填充为黑色。k代表黑色
        splocation+=1
    plt.show()
    

    运行结果:

      可见,在比较这种分布下,径向基核函数表现出更好的分类性能。

    5 SVC的参数

      具体参数的意义与使用请参见链接:http://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html

    • C:目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0;

    C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样对训练集测试时准确率很高,但泛化能力弱。C值小,对误分类的惩罚减小,允许容错,将他们当成噪声点,泛化能力较强。

    • kernel :核函数,默认是rbf,可以是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’

    • degree :多项式poly函数的维度,默认是3,选择其他核函数时会被忽略。

    • gamma : ‘rbf’,‘poly’ 和‘sigmoid’的核函数参数。默认是’auto’,则gamma=1/n_features

    • coef0 :核函数的常数项。对于‘poly’和 ‘sigmoid’有用。

    • probability :是否采用概率估计。默认为False。要采用的话必须先于调用fit,这个过程会增加用时。

    • shrinking :是否采用shrinking heuristic方法,默认为true

    • tol :停止训练的误差值大小,默认为1e-3

    • cache_size :核函数cache缓存大小,默认为200

    • class_weight :类别的权重,字典形式传递。设置第几类的参数C为weight*C(C-SVC中的C)

    • verbose :允许冗余输出。跟多线程有关系。默认为False。

    • max_iter :最大迭代次数。-1为无限制。

    • decision_function_shape :是否返回模型中每一个类别的样本的ovr决策函数,或者ovo决策函数。 默认为None

    • random_state :数据洗牌时的种子值,int值

    主要调节的参数有:C、kernel、degree、gamma、coef0。

    6 推广

      官方文档是学习的绝佳利器。传送门:http://scikit-learn.org/dev/modules/svm.html

    6.1 多分类

      SVM算法最初是为二值分类问题设计的,当处理多类问题时,就需要构造合适的多类分类器。目前,构造SVM多类分类器的方法主要有两类:一类是直接法,直接在目标函数上进行修改,将多个分类面的参数求解合并到一个最优化问题中,通过求解该最优化问题“一次性”实现多类分类。这种方法看似简单,但其计算复杂度比较高,实现起来比较困难,只适合用于小型问题中;另一类是间接法,主要是通过组合多个二分类器来实现多分类器的构造,常见的方法有one-against-one和one-against-all两种。

    1. 一对多法(one-versus-rest,简称1-v-r SVMs)。训练时依次把某个类别的样本归为一类,其他剩余的样本归为另一类,这样k个类别的样本就构造出了k个SVM。分类时将未知样本分类为具有最大分类函数值的那类。
    2. 一对一法(one-versus-one,简称1-v-1 SVMs)。其做法是在任意两类样本之间设计一个SVM,因此k个类别的样本就需要设计k(k-1)/2个SVM。当对一个未知样本进行分类时,最后得票最多的类别即为该未知样本的类别。Libsvm中的多类分类就是根据这个方法实现的。
    3. 层次支持向量机(H-SVMs)。层次分类法首先将所有类别分成两个子类,再将子类进一步划分成两个次级子类,如此循环,直到得到一个单独的类别为止。 对c和d两种方法的详细说明可以参考论文《支持向量机在多类分类问题中的推广》(计算机工程与应用。2004)
    4. 其他多类分类方法。除了以上几种方法外,还有有向无环图SVM(Directed Acyclic Graph SVMs,简称DAG-SVMs)和对类别进行二进制编码的纠错编码SVMs。

    6.2 回归

      支持分类的支持向量机可以推广到解决回归问题,这种方法称为支持向量回归。

      支持向量分类所产生的模型仅仅依赖于训练数据的一个子集,因为构建模型的成本函数不关心在超出边界范围的点,类似的,通过支持向量回归产生的模型依赖于训练数据的一个子集,因为构建模型的函数忽略了靠近预测模型的数据集。

      有三种不同的实现方式:支持向量回归SVR,nusvr和linearsvr。linearsvr提供了比SVR更快实施但只考虑线性核函数,而nusvr实现比SVR和linearsvr略有不同。
    作为分类类别,训练函数将X,y作为向量,在这种情况下y是浮点数

  • 相关阅读:
    第十四周 Leetcode 315. Count of Smaller Numbers After Self(HARD) 主席树
    POJ1050 To the Max 最大子矩阵
    POJ1259 The Picnic 最大空凸包问题 DP
    POJ 3734 Blocks 矩阵递推
    POJ2686 Traveling by Stagecoach 状态压缩DP
    iOS上架ipa上传问题那些事
    深入浅出iOS事件机制
    iOS如何跳到系统设置里的各种设置界面
    坑爹的私有API
    业务层网络请求封装
  • 原文地址:https://www.cnblogs.com/d0main/p/6918818.html
Copyright © 2011-2022 走看看