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是浮点数

  • 相关阅读:
    antd使用DatePicker组件出现TypeError: date.clone is not a function错误
    nrm解决npm install安装慢的问题
    antd pro显示自定义icon
    antd v4 使用后台返回的icon type的icon,并绑定事件
    复制textarea里输入的内容
    jsDelivr 缓存刷新小工具
    SweetAlert2网页弹窗---JAVASCRIPT弹窗
    Viewer.js 图片预览插件
    给你的网站加一个可爱的”躲猫猫“
    【Pyhton】随机漫步散点图
  • 原文地址:https://www.cnblogs.com/d0main/p/6918818.html
Copyright © 2011-2022 走看看