zoukankan      html  css  js  c++  java
  • 【笔记】核函数

    核函数

    SVM算法的本质点击这里

    将最优化问题变成

    右边的最优化问题中的最大化式子中的后半部分,套了两层求和,一个是i,一个是j,可以说,转变的式子中对于样本数据集的任意的两个向量都要进行向量间的点乘

    那么如果想要使用多项式特征的话,原先的多项式变化是先将原来的xi和xj添加上多项式特征,然后在式子中将xi和xj替换下来

    核函数的思想不同于上面,不将式子中的xi和xj转换成多项式的形式然后在做乘法,设置一个函数K,传入两个参数xi和xj,直接对原先的两个样本进行数学运算,直接计算出对应的结果,将式子变成

    核函数就是一种数学的运算技巧,即节省了存储空间,又可以在遇到很复杂的计算时不用费心费力的去计算,使用核函数这种技巧的话,不需要管将原先的函数变成了什么样子,不需要存储变化后的结果就可以直接使用计算出二者的点乘结果,大大的降低了计算的复杂度

    事实上,只要算法中存在最优化中有xi和xj的点乘操作或者类似的式子,就可以使用核函数

    以多项式核函数为例

    在多项式核函数中,K可以写成是(方便起见,使用二次为例)

    展开整理后可以得到

    那么可以说,原来的x变成了(y同样变成这种模式)

    两者相乘以后就可以得到展开以后的式子

    那么只要将原先式子其中的K转换为新的定义的K,之后使用SVM算法,就转换成了二次项的结果了

    将二次项中的1和括号外的数字换为c和d两个超参数以后就可以得到多项式核函数的式子

    线性核函数

    其中核函数中最著名的就是高斯核函数

    高斯核函数

    那么什么是高斯核函数

    高斯核函数的定义是

    为什么叫高斯核函数,因为其中的超参数实际上是和高斯函数有着类似的形式

    高斯核函数有时也被称为RBF核,有时翻译为径向基函数,有的说,高斯核函数的本质是将每一个样本点映射到一个无穷维的特征空间,通过这个说法,可以发现,其变形是很复杂的,但是变形以后的样本的点乘是很简单的

    使用多项式特征解决非线性的问题的基本原理就是依靠升维使原本线性不可分的数据线性可分,即按照某种规则扩充维度,具体可以看这里

    关于多项式特征,如果说是一维的直线上分布的点,种类掺杂在一起,使用多项式特征以后,就使得点不单单具备x值,还具备了y的值,这样操作以后,就让原来线性不可分的点,变得线性可分了,这就是升维的意义

    高斯核本质也是这样,为了方便观察,设置y的值为固定值,设置为l1和l2,作为地标,高斯核函数的升维操作主要是将x升为二维的样本点,取值为将公式中的y替换为地标的得到的值

    这样就将一维的数据升为二维的数据

    具体实现RBF函数

    (在notebook中)

    引用基本的类库,生成测试用例x和y,x用arange来生成,y用array来生成,进行分类

      import numpy as np
      import matplotlib.pyplot as plt
    
      x = np.arange(-4,5,1)
      y = np.array((x >= -2)&(x <= 2),dtype='int')
    

    x和y的内容的输出结果如下

    绘制图像

      plt.scatter(x[y==0],[0]*len(x[y==0]))
      plt.scatter(x[y==1],[0]*len(x[y==1]))
    

    图像如下

    设计高斯核函数的函数,代入公式即可,由于x和l都是一维的数,不需要计算模,就直接平方即可,设置gamma默认为1

      def gaussian(x,l):
          gamma = 1.0
          return np.exp(-gamma * (x-l)**2)
    

    设计完以后,就开始具体的映射过程,设置两个固定的L1,L2,存储新的二维的样本数据,使用循环,每次都取出来一个数据,将数据放入data中,在其中,先计算第0个特征,然后算第1个特征,调用gaussian,传入data和l1,l2即可

      l1,l2 = -1,1
    
      x_new = np.empty((len(x),2))
      for i,data in enumerate(x):
          x_new[i,0] = gaussian(data,l1)
          x_new[i,1] = gaussian(data,l2)
    

    绘制图像

      plt.scatter(x_new[y==0,0],x_new[y==0,1])
      plt.scatter(x_new[y==1,0],x_new[y==1,1])
    

    图像如下

    这样操作以后,就让原先一维线性不可分的数据变得二维线性可分了

    回顾上面的公式,不难发现,其实对于高斯核这个公式来说,其中的y的位置,其实是每一个数据点,可以说,高斯核对于每一个数据点都是landmark(地标)

    所以高斯核的本质是将mn数据映射成mm的数据,所以先前的映射进无穷维空间中的无穷维的意思就是因为有无穷多个样本点,所以映射进了无穷维的空间,这样就可以发现高斯核的训练时间会比较长

    在sklearn中的高斯核函数中的gamma

    需要注意的是,gamma越大,高斯分布越窄,gamma越小,高斯分布越宽

    具体实现RBF核函数中的gamma

    (在notebook中)

    加载好需要的包和数据,绘制图像

      import numpy as np
      import matplotlib.pyplot as plt
      from sklearn import datasets
    
      X,y = datasets.make_moons(noise=0.15,random_state=666)
    
      plt.scatter(X[y==0,0],X[y==0,1])
      plt.scatter(X[y==1,0],X[y==1,1])
    

    图像如下

    使用sklearn中的高斯核函数,设置一个函数,只传入一个参数gamma即可,首先对数据进行标准化,第二步进行SVC,参数kernel为rbf

      from sklearn.pipeline import Pipeline
      from sklearn.svm import SVC
      from sklearn.preprocessing import StandardScaler
    
      def RBFKernelSVC(gamma=1.0):
          return Pipeline([
              ("std_scaler",StandardScaler()),
              ("svc",SVC(kernel="rbf",gamma=gamma))   
          ])
    

    使用函数并实例化,然后进行fit

      svc = RBFKernelSVC(gamma=1.0)
      svc.fit(X,y)
    

    绘制函数

    from matplotlib.colors import ListedColormap
    def plot_decision_boundary(model, axis):
    
        x0,x1 = np.meshgrid(  
            np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
            np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1)
        )
        X_new = np.c_[x0.ravel(),x1.ravel()]
        y_predict = model.predict(X_new)
        zz = y_predict.reshape(x0.shape)
        custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
    
        plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
    

    调用绘制函数绘制图像

      plot_decision_boundary(svc,axis=[-1.5,2.5,-1.0,1.5])
      plt.scatter(X[y==0,0],X[y==0,1])
      plt.scatter(X[y==1,0],X[y==1,1])
    

    图像如下(gamma=1.0)

    设置gamma为100

      svc2 = RBFKernelSVC(gamma=100)
      svc2.fit(X,y)
    
      plot_decision_boundary(svc2,axis=[-1.5,2.5,-1.0,1.5])
      plt.scatter(X[y==0,0],X[y==0,1])
      plt.scatter(X[y==1,0],X[y==1,1])
    

    图像如下

    设置gamma为10

      svc3 = RBFKernelSVC(gamma=10)
      svc3.fit(X,y)
    
      plot_decision_boundary(svc3,axis=[-1.5,2.5,-1.0,1.5])
      plt.scatter(X[y==0,0],X[y==0,1])
      plt.scatter(X[y==1,0],X[y==1,1])
    

    图像如下

    设置gamma为0.5

      svc4 = RBFKernelSVC(gamma=0.5)
      svc4.fit(X,y)
    
      plot_decision_boundary(svc4,axis=[-1.5,2.5,-1.0,1.5])
      plt.scatter(X[y==0,0],X[y==0,1])
      plt.scatter(X[y==1,0],X[y==1,1])
    

    图像如下

    设置gamma为0.1

      svc5 = RBFKernelSVC(gamma=0.1)
      svc5.fit(X,y)
    
      plot_decision_boundary(svc5,axis=[-1.5,2.5,-1.0,1.5])
      plt.scatter(X[y==0,0],X[y==0,1])
      plt.scatter(X[y==1,0],X[y==1,1])
    

    图像如下

    从上面几张图可以发现gamma为100的时候,比起gamma为1的时候,决策边界针对其中的某一类,在其每一个样本点周围都形成了一个钟型图(高斯分布,俯视图为一个圆),由于gamma比较大,所以看起来圆比较小,这就是过拟合了

    在gamma为10的时候,蓝色点的周围红色就很明显比gamma为100的时候要大一些,设gamma为0.5的时候,发现更大了,gamma为0.1的时候已经快称为一条直线了,这很明显就是欠拟合了

    所以可以发现,这个gamma值实际上就是在调整模型的复杂度,越低越倾向于欠拟合,越高越倾向于过拟合,需要找到一个合适的位置才行

  • 相关阅读:
    Linux下的目录结构
    VM
    代码命名规范
    java环境及配置
    Code::Blocks 使用Cygwin编译加调试
    vscode使用体会
    openwrt编译笔记
    ubuntu20 使用root登录
    程序员如何更好的表达自己的想法- Graphviz:关系图脚本绘制工具-转
    编译codelite心得
  • 原文地址:https://www.cnblogs.com/jokingremarks/p/14337248.html
Copyright © 2011-2022 走看看