• 机器学习【六】支持向量机SVM——专治线性不可分


    SVM原理

    线性可分与线性不可分

    线性可分

    线性不可分-------【无论用哪条直线都无法将女生情绪正确分类】

    SVM的核函数可以帮助我们:

    假设‘开心’是轻飘飘的,“不开心”是沉重的

    将三维视图还原成二维:

    刚利用“开心”“不开心”的重量差实现将二维数据变成三维的过程,称为将数据投射至高维空间,这正是核函数的功能

    在SVM中,用的最普遍的两种把数据投射到高维空间的方法分别是多项式内核、径向基内核(RFB)

    多项式内核:

    通过把样本原始特征进行乘方来把数据投射到高维空间【如特征1^2,特征2^3,特征3^5......】

    RBF:

    又称高斯内核

     支持向量机的SVM核函数

    用图形直观了解:

    #导入numpy
    import numpy as np
    #导入画图工具
    import matplotlib.pyplot as plt
    #导入支持向量机SVM
    from sklearn import svm
    #导入数据集生成工具
    from sklearn.datasets import make_blobs
    #先创建50个数据点,让它们分成两类
    X,y = make_blobs(n_samples=50,centers=2,random_state = 6)
    #创建一个线性内核的支持向量机模型
    clf = svm.SVC(kernel = 'linear',C=1000)
    clf.fit(X,y)
    #把数据点画出来
    plt.scatter(X[:,0],X[:,1],c=y,s=30,cmap=plt.cm.Paired)
    #建立图像坐标
    ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    #生成两个等差数列
    xx = np.linspace(xlim[0],xlim[1],30)
    yy = np.linspace(ylim[0],ylim[1],30)
    YY,XX = np.meshgrid(yy,xx)
    xy = np.vstack([XX.ravel(),YY.ravel()]).T
    Z = clf.decision_function(xy).reshape(XX.shape)
    #把分类的边界画出来
    ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])
    ax.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1],s=100,linewidth=1,facecolors='none')
    plt.show()

    ——线性内核的SVM分类器

    【结果分析】:

    在分类器两侧有两条虚线,正好压在虚线上的数据点,即支持向量

    本例所使用的方法称为“最大边界间隔超平面”

    指,实线【在高维数据中是一个超平面】和所有支持向量的距离都是最大的

    把SVM的内核换成RBF:

    #创建一个RBF内核的支持向量机模型
    clf_rbf = svm.SVC(kernel='rbf',C=1000)
    clf_rbf.fit(X,y)
    #把数据点画出来
    plt.scatter(X[:,0],X[:,1],c=y,s=30,cmap=plt.cm.Paired)
    #建立图像坐标
    ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    #生成两个等差数列
    xx = np.linspace(xlim[0],xlim[1],30)
    yy = np.linspace(ylim[0],ylim[1],30)
    YY,XX = np.meshgrid(yy,xx)
    xy = np.vstack([XX.ravel(),YY.ravel()]).T
    Z = clf_rbf.decision_function(xy).reshape(XX.shape)
    #把分类的边界画出来
    ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])
    ax.scatter(clf_rbf.support_vectors_[:,0],clf_rbf.support_vectors_[:,1],s=100,linewidth=1,facecolors='none')
    plt.show()

     ——RBF内核的SVM分类器

    【结果分析】:

    使用RBF内核时,数据点距离计算是用如下公式计算的:

    SVM的核函数和参数选择

    1.不同核函数的SVM对比

    线性模型中提到过,linearSVM算法,就是一种使用了线性内核的SVM算法,不过linearSVM不支持对核函数进行修改【默认只能使用线性内核】

    直观体验不同内核的SVM算法在分类中的不同表现

    #导入红酒数据集
    from sklearn.datasets import load_wine
    #定义一个函数来画图
    def make_meshgrid(x,y,h=.02):
        x_min,x_max = x.min() -1,x.max() +1
        y_min,y_max = y.min() -1,y.max() +1
        xx,yy = np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
        return xx,yy
    #定义一个绘制等高线的函数
    def plot_contours(ax,clf,xx,yy, **params):
        Z = clf.predict(np.c_[xx.ravel(),yy.ravel()])
        Z = Z.reshape(xx.shape)
        out = ax.contourf(xx,yy,Z, **params)
        return out
    #使用酒的数据集
    wine = load_wine()
    #选取数据集的前两个特征
    X = wine.data[:,:2]
    y = wine.target
    C = 1.0  #SVM的正则化参数
    models = (svm.SVC(kernel='linear',C=C),svm.LinearSVC(C=C),svm.SVC(kernel='rbf',gamma=0.7,C=C),svm.SVC(kernel='poly',degree=3,C=C))
    models = (clf.fit(X,y) for clf in models)
    #设定图题
    titles = ('SVC with linear kernal','LinearSVC (linear kernal)','SVC with RBF kernal','SVC with polynomial (degree 3) kernal')
    #设定一个子图形的个数和排列方式
    fig,sub = plt.subplots(2,2)
    plt.subplots_adjust(wspace=0.4,hspace=0.4)
    #使用前面定义的函数进行画图
    X0,X1 = X[:,0],X[:,1]
    xx,yy = make_meshgrid(X0,X1)
    for clf,title,ax in zip(models,titles,sub.flatten()):
        plot_contours(ax,clf,xx,yy,cmap=plt.cm.plasma,alpha=0.8)
        ax.scatter(X0,X1,c=y,cmap=plt.cm.plasma,s=20,edgecolors='k')
        ax.set_xlim(xx.min(),xx.max())
        ax.set_ylim(yy.min(),yy.max())
        ax.set_xlabel("Feature 0")
        ax.set_ylabel("Feature 1")
        ax.set_xticks(())
        ax.set_yticks(())
        ax.set_title(title)
    plt.show()

    【结果分析】:

    线性内核的SVC与linearSVC得到的结果近似,但仍然有一点差别——原因是linearSVC对L2范数进行最小化,而线性内核的SVC是对L1进行最小化

    无论如何,线性内核的SVC和linearSVC生成的决定边界都是线性的【在更高维数据集中将会是相交的超平面】

     RBF内核的SVC和polynomial内核的SVC分类器的决定边界则完全不是线性的,更加弹性

    决定他们边界形状的是参数:

    polynomial内核的SVC分类器

    degree和正则化参数C

    【本例中degree=3,即对原始数据集的特征乘3次方操作】

    RBF内核的SVC

    gamma和正则化参数C

    RBF内核SVC的gamma参数调节

    C = 1.0  #SVM的正则化参数
    models = (svm.SVC(kernel='rbf',gamma=0.1,C=C),svm.SVC(kernel='rbf',gamma=1,C=C),svm.SVC(kernel='rbf',gamma=10,C=C))
    models = (clf.fit(X,y) for clf in models)
    #设定图题
    titles = ('gamma=0.1','gamma=1','gamma=10')
    #设置子图形个数和排列
    flg,sub = plt.subplots(1,3,figsize=(10,3))
    #使用前面定义的函数进行画图
    X0,X1 = X[:,0],X[:,1]
    xx,yy = make_meshgrid(X0,X1)
    for clf,title,ax in zip(models,titles,sub.flatten()):
     plot_contours(ax,clf,xx,yy,cmap=plt.cm.plasma,alpha=0.8)
     ax.scatter(X0,X1,c=y,cmap=plt.cm.plasma,s=20,edgecolors='k')
     ax.set_xlim(xx.min(),xx.max())
     ax.set_ylim(yy.min(),yy.max())
     ax.set_xlabel("Feature 0")
     ax.set_ylabel("Feature 1")
     ax.set_xticks(())
     ax.set_yticks(())
     ax.set_title(title)
    plt.show()

     

    【结果分析】:

    gamma值越小,RBF内核的直径越大——> 有更多的点被模型圈进决定边界中——> 边界越圆滑

    • gamma越小,模型倾向于 欠拟合
    • gamma越大,模型倾向于 过拟合

    正则化参数C,可以见线性模型一章

    • C越小,模型越受限【单个数据对模型的影响越小】,模型越简单
    • C越大,每个数据点对模型的影响越大,模型越复杂

    SVM优点

    • 可应对高维数据集和低维数据集
    • 即使数据集中样本特征的测度都比较接近,如图像识别领域,以及样本特征数和样本数比较接近的时候,都游刃有余

    SVM缺点 

    • 当数据集中特征数量在1万以内,SVM可以驾驭,但数量大于10万,就非常占内存和耗费时间
    • 对数据预处理和参数调节要求很高

     【注意】

    SVM中3个参数非常重要:

    1. 核函数的选择
    2. 核函数的参数【如RBF的gamma】
    3. 正则化参数C 

     RBF内核的gamma值是用来调节内核宽度的,gamma值和C值一起控制模型的复杂度,数值越大,模型越复杂【实际中,一起调节,才能达到最好的效果】

    实战

     SVM在回归分析中的应用——波士顿房价数据集

    1.了解数据集

    #导入波士顿房价
    from sklearn.datasets import load_boston
    boston = load_boston()
    #打印键
    print(boston.keys())

     

    #打印数据集中的短描述
    print(boston['DESCR'])

     

    【一部分】

    【结果分析】

    数据集共有506个样本,每个样本有13个特征变量,后面还有一个叫做中位数的第14个变量【这变量就是该数据集中的target】

    2.通过SVR算法建立房价预测模型


    #导入数据集拆分工具
    from sklearn.model_selection import train_test_split
    #建立数据集和测试集
    X,y = boston.data,boston.target
    X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=8)
    #打印训练集和测试集的形态
    print(X_train.shape)
    print(X_test.shape)

     

    用SVR建模

    #导入支持向量回归模型
    from sklearn.svm import SVR
    #分别测试linear核函数和rbf核函数
    for kernel in ['linear','rbf']:
       svr = SVR(kernel=kernel)
       svr.fit(X_train,y_train)
       print(kernel,'核函数模型训练集得分:',svr.score(X_train,y_train))
       print(kernel,'核函数模型测试集得分:',svr.score(X_test,y_test))

     

     SVM算法对数据预处理的要求较大,如果  数据特征量级差异较大  ,就需要预处理数据

    先用图形可视化:

    #将特征数值中的min和max用散点图画出来
    plt.plot(X.min(axis=0),'v',label='min')
    plt.plot(X.max(axis=0),'^',label='max')
    #设定纵坐标为对数形式
    plt.yscale('log')
    #设定图注位置最佳
    plt.legend(loc='best')
    plt.xlabel('features')
    plt.ylabel('feature magnitude')
    plt.show()

    显然,量级差异较大

    预处理:

    #导入数据预处理工具
    from sklearn.preprocessing import StandardScaler
    #预处理
    scaler = StandardScaler()
    scaler.fit(X_train)
    X_train_scaled = scaler.transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    #将预处理后的数据特征的max和min用散点图表示出来
    plt.plot(X_train_scaled.min(axis=0),'v',label='train set min')
    plt.plot(X_train_scaled.max(axis=0),'^',label='train set max')
    plt.plot(X_test_scaled.min(axis=0),'v',label='test set min')
    plt.plot(X_test_scaled.max(axis=0),'^',label='test set max')
    #设置图注位置
    plt.legend(loc='best')
    plt.xlabel('scaled features')
    plt.ylabel('scaled feature magnitude')
    plt.show()

     

    【结果分析】

     经过预处理,无论训练集还是测试集,所有特征的最大值不会超过10,最小值趋近0,以至图中看不到

    用预处理的数据训练模型:

    #使用预处理后的数据重新训练模型
    for kernel in ['linear','rbf']:
     svr = SVR(kernel=kernel)
     svr.fit(X_train_scaled,y_train)
     print(kernel,'训练集得分:',svr.score(X_train_scaled,y_train))
     print(kernel,'测试集得分:',svr.score(X_test_scaled,y_test))

    进一步调整参数


    #设置模型的C参数和gamma参数
    svr = SVR(C=100,gamma=0.1)
    svr.fit(X_train_scaled,y_train)
    print('训练集得分:',svr.score(X_train_scaled,y_train))
    print('测试集得分:',svr.score(X_test_scaled,y_test))

  • 相关阅读:
    平均要取多少个(0,1)中的随机数才能让和超过1
    perl学习笔记
    K-means
    Mysql数据库常用操作整理
    ETL模型设计
    c++ 面试整理
    vim display line number
    inux 下的/etc/profile、/etc/bashrc、~/.bash_profile、~/.bashrc 文件的作用
    Linux命令大总结
    perl learning
  • 原文地址:https://www.cnblogs.com/expedition/p/10779931.html
Copyright © 2020-2023  润新知