第六章 支持向量机

试答系列:“西瓜书”-周志华《机器学习》习题试答

知识梳理

本章关于支持向量机的公式较多,存在有多种形式,容易产生混淆,为此,在这里将涉及支持向量机的各种公式进行总结,绘制了一张关系图,其中未涉及支持向量回归和和核方法部分内容:


支持向量机多种形式公式之间的关系

6.1 试证明样本空间中任意点x到超平面(w,b)的距离为式(6.2)。

证明:设点在超平面的垂足为,那么也在超平面内,应满足(1): ;另外和的连线应该垂直于超平面,或者说平行于法向量,应满足(2): , k为一常数。结合(1)和(2)消去可以得到,而到超平面的距离可以表示为:,此即(6.2)式。

6.2 试使用LIBSVM,在西瓜数据集3.0α上分别用线性核和高斯核训练一个SVM,并比较其支持向量的差别。

:本题采用python中的sklearn库下的svm.SVC类进行支持向量机算法的训练,该分类器正是基于LIBSVM (详细编程代码附后)。svm.SVC的主要参数有惩罚系数C和核函数kernel。C越大,越倾向于“硬间隔”,也就是所有样本都被正确分类。kernel='linear'表示采用线性核,kernel='rbf'表示采用高斯核。下面是在西瓜数据集3.0α上采用不同设置下的训练结果:

不同设置下的训练结果

观察以上计算结果,可见:

  1. 所有被错误划分或者处在临界带(|f(x)|≤1)内的数据点属于支持向量。
  2. 当惩罚系数C较小时,线性核和高斯核所得到决策边界基本一样,所得到的支持向量完全相同。此时支持向量较多,15个,在临界带内有大量支持向量;当惩罚系数C较大时。对于高斯核,所有样本均被正确分类,支持向量由临界线上的6个数据点组成。对于线性核,由于数据线性不可分,无法实现所有样本都正确分类,此时仍然有12个支持向量。

6.3 选择两个UCI数据集,分别用线性核和高斯核训练一个SVM,并与BP神经网络和C4.5决策树进行实验比较。

本题编程代码附后。这里的多个机器学习算法均通过scikit-learn中相应的类来实现,载入方式为:from sklearn import svm,neural_network,tree,其中决策树使用CART算法的优化版本,CART与C4.5非常相似,但是它支持数值目标变量(回归)。
在每个机器学习算法中有多个超参数调节,这里采用scikit-learn中的网格搜索方法GridSearchCV来确定超参数,对于每一组超参数,计算它的k折交叉验证平均得分(预测精度),将得分最大时的超参数作为最佳参数。
首先在iris数据集上进行实验,结果如下表所示:

算法 SVM-linear SVM-rbf BP Tree
最佳超参数 C=0.695 C=1.624 alpha=0~1
hidden_layer_sizes=(15,2~7)(5,)
max_depth=4~14,None
min_samples_leaf=1
最佳得分 0.987 0.987 0.98~0.987 0.967
对应拟合时间 0.2~0.8ms 0.6~1ms 26~83ms 0.2~0.4ms

其中在网格搜索确定超参数过程中的k折交叉验证设置cv=5。针对各个超参数的搜索,对于SVM,考察了惩罚因子C;对于BP,考察了惩罚因子alpha和隐藏层单元数hidden_layer_sizes;对于Tree,考察了最大深度max_depth和叶结点最少样本数min_samples_leaf。
iris数据各个维度幅值相当,未作归一化处理,经实验发现,归一化后,差别不大,最佳得分还略有下降。
对比各个算法,可以得出如下结论:

  • 最佳超参数方面,SVM结果很稳定,BP和Tree所得结果不稳定,这说明SVM对于超参数C较敏感,BP和Tree对于相应的超参数不太敏感。
  • 最佳得分方面,各个算法最佳预测精度相当,Tree算法略差一点点。
  • 拟合时间方面,BP算法较耗时,SVM和Tree算法较快。

然后又选取了数据集breast_cancer进行实验,该数据集有十个特征,彼此间幅值差别较大,需要进行归一化预处理。下面分别是在归一化和未归一化下计算的结果:
数据集breast_cancer上的计算结果(数据归一化)

算法 SVM-linear SVM-rbf BP Tree
最佳超参数 C=0.0545 C=3.793 alpha=1E-8~1E-4
hidden_layer_sizes=(15,2~7)
max_depth=4~12,None
min_samples_leaf=5
最佳得分 0.977ms 0.979ms 0.974~0.977ms 0.938~0.942ms
对应拟合时间 2~3ms 4~5ms 22~24ms 5~8ms

数据集breast_cancer上的计算结果(不作归一化)

算法 SVM-linear SVM-rbf BP Tree
最佳超参数 - C=0.01 alpha=1
hidden_layer_sizes=(15~25, 2~7)
max_depth=8~16
min_samples_leaf=5
最佳得分 - 0.627 0.94~0.96 0.942
对应拟合时间 ∞ms 26ms 90~170ms 6~7ms

可见:归一化对于各个算法的最佳超参数,最佳得分,对应拟合时间均产生影响。归一化之后,拟合更快些。在最佳得分方面,归一化对于BP和Tree影响较小,对SVM影响较大。
不同算法在超参数稳定性,最佳预测精度,拟合耗时方面的对比结论与前面iris数据集中得到的结论相同。

6.4 试讨论线性判别分析与线性核支持向量机在何种条件下等价。

6.5 试述高斯核SVM与RBF神经网络之间的联系。

:参考本章最后面的“休息一会儿”中的侧注所述:

SVM的确与神经网络有密切联系:若将隐层神经元数设置为训练样本数,且每个训练样本对应一个神经元中心,则以高斯径向基函数为激活函数的RBF网络恰与高斯核SVM的预测函数相同。

高斯核SVM训练得到的预测函数为:

而RBF网络的输出结果为:

假设已经训练完成一个高斯核SVM,我们可以构造出一个输出结果与SVM结果完全相同的RBF神经网络:神经元数目为m+1,令其中前m个神经元的中心,激活函数中参数,权重,最后一个神经元的中心设为任意值,参数,权重。
尽管如此,若是单独训练RBF神经网络,得到的结果未必如此。

6.6 试析SVM对噪声敏感的原因。

6.7 试给出式(6.52)的完整KKT条件。

:根据“附录B.1-拉格朗日乘子法”,每一个不等式约束将得到3个KKT条件,比如,对于约束g(x)≤0,对应的KKT条件为:g(x)≤0,γ≥0,γg(x)=0。式(6.52)中仅涉及KKT条件中的等式KKT条件部分,亦即γg(x)=0这部分。若写出原问题(6.45)的完整KKT条件,由于原问题中有4m个不等式,因此将得到3×4m=12m个KKT条件,它们是:
\left \{ \begin{array}{c} f(x_i)-y_i\le\epsilon+\xi_i\\ y_i-f(x_i)\le\epsilon+\hat{\xi_i}\\ \xi_i\ge0, \hat{\xi_i}\ge0\\ \alpha_i\ge0, \hat{\alpha_i}\ge0, \mu_i\ge0, \hat{\mu_i}\ge 0\\ \alpha_i(f(x_i)-y_i-\epsilon-\xi_i)=0\\ \alpha_i(y-f(x_i)-\epsilon-\hat{\xi_i})=0\\ \mu_i\xi_i=0, \hat{\mu_i}\hat{\xi_i}=0\\ i=1,2,...,m \end{array} \right.
将上式中的等式部分与教材中的式(6.52)对比,有几个不同的地方:

  1. (6.52)式中利用了关系,因此将“”写为“”。
  2. (6.52)式中多了两个等式:和,这而与KKT条件无关,是通过其他分析额外得到的条件。对于某个样本点,它的位置可能有几种情况:间隔带以内,上边界或以外,下边界或以外。
    若在间隔带以内,则;
    若刚好在上边界上,则;
    若刚好在下边界上,则;
    若在上边界以外,则;
    若在下边界以外,则。
    由于一个点不可能同时出现在上边界(或以外)和下边界(或以外),因此有上面两个等式成立。

6.8 以西瓜数据集3.0α的“密度”为输入,“含糖率”为输出,试使用LIBSVM训练一个SVR。

:这里仍然采用scikit-learn中相应的类来实现,载入方式为 from sklearn.svm import SVR。
SVR有两个关键的参数:C和epsilon,分别代表惩罚因子和开始计算惩罚损失的阈值,C越大,epsilon越小,拟合结果与原数据越接近。
本题详细编程代码附后。
对于西瓜数据集3.0α的计算结果如下:

Apply SVR on 西瓜数据集3.0α

核函数分别选取为linear和rbf,线性核linear所得结果为线性函数,高斯核rbf所得结果为非线性函数。
由于西瓜数据集3.0α的密度和含糖量这两个特征之间相关性较低,所以计算效果看起来不明显。可以人为生成一些数据来观察SVR计算结果:

人为生成数据,然后做SVR拟合

6.9 试使用核技巧推广对率回归,产生“核对率回归”。

:参照教材中对于“核线性判别分析(KLDA)”的做法。
对于数据集,假设通过一个映射将映射到高维特征空间,为核函数,然后在中执行对率回归模型训练,以求得:

其中参数,通过最小化目标函数来估计:

根据表示定理,参数和预测函数可以写为:

令为核矩阵,矩阵元,列向量,向量。
于是目标函数将变为估计参数和:

然后,便可以采取对率回归中同样的方法:梯度下降法或者牛顿法来求解最优参数。

6.10 试设计一个能显著减少SVM中支持向量的数目而不显著降低泛化性能的方法。

附:编程代码

习题6.2(Python)

# -*- coding: utf-8 -*-
"""
Created on Sat Nov 16 21:24:06 2019

@author: lsly
"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm

# 西瓜3.0α 样本数据
X=np.array([[0.697,0.46],[0.774,0.376],[0.634,0.264],[0.608,0.318],[0.556,0.215],
   [0.403,0.237],[0.481,0.149],[0.437,0.211],[0.666,0.091],[0.243,0.267],
   [0.245,0.057],[0.343,0.099],[0.639,0.161],[0.657,0.198],[0.36,0.37],
   [0.593,0.042],[0.719,0.103]])
Y=np.array([1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0])

# 支持向量机训练并将结果可视化
for c in [1E1,1E3,1E5]:
    for k in ['linear','rbf']:
        # 训练并提取支持向量
        clf=svm.SVC(C=c,kernel=k)  #C为惩罚系数,kernel是所用的核函数
        clf.fit(X,Y)               #fit函数对训练样本进行训练
        Xsp=X[clf.support_,:]      #参数support_为支持向量的索引号
        Ysp=Y[clf.support_]        #Xsp和Ysp分别为支持向量的特征和类标记
        # 画图
        plt.figure()
        plt.title('C=%.E, kernel=%s'%(c,k))
        # 画出正负样本(+和-符号表示)
        plt.scatter(X[Y==1,0],X[Y==1,1],marker='+',c='r',s=100)
        plt.scatter(X[Y==0,0],X[Y==0,1],marker='_',c='b',s=100)
        # 标出支持向量(画圈)(用marker='o'和c=''结合起来表示空心圆)
        plt.scatter(Xsp[Ysp==1,0],Xsp[Ysp==1,1],marker='o',c='',s=100,edgecolors='r')
        plt.scatter(Xsp[Ysp==0,0],Xsp[Ysp==0,1],marker='o',c='',s=100,edgecolors='b')
        # 画决策线
        x1,x2=np.meshgrid(np.linspace(min(X[:,0]),max(X[:,0]),100),
                  np.linspace(min(X[:,1]),max(X[:,1]),100))
        z=clf.decision_function(np.c_[x1.reshape(-1),x2.reshape(-1)]).reshape(100,100)
        # ↑   decision_function返回决策函数值,也即wx+b的值,
        #     另外还有函数predict可以返回类标记,比如1,0
        plt.contour(x1,x2,z,colors='k',linestyles=['--','-','--'],levels=[-1,0,1])

习题6.3(Python)

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 23 16:43:25 2019

@author: MS
"""

from sklearn.model_selection import GridSearchCV
from sklearn import svm,neural_network,tree
from sklearn import datasets
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler  

'''
=============载入数据集iris=======================
'''
X,y=datasets.load_iris(return_X_y=True)

normalize=0   #设为1则作归一化,否则不归一化
if normalize==1:
    X=StandardScaler().fit(X).transform(X) #对数据进行归一化

#===========1.svm-linear=======
C=np.logspace(-2,5,20)
clf1=GridSearchCV(svm.SVC(kernel='linear'),{'C':C},cv=5,return_train_score=True)
clf1.fit(X,y)

print('svm-linear-最佳参数:',clf1.best_params_,
      '最佳得分:',clf1.best_score_,
      '对应拟合耗时:',clf1.cv_results_['mean_fit_time'][clf1.best_index_])

#===========2.svm-rbf==========
clf2=GridSearchCV(svm.SVC(kernel='rbf'),{'C':C},cv=5,return_train_score=True)
clf2.fit(X,y)

print('svm-rbf-最佳参数:',clf2.best_params_,
      '最佳得分:',clf2.best_score_,
      '对应拟合耗时:',clf2.cv_results_['mean_fit_time'][clf2.best_index_])

#===========3.BP神经网络================
alpha=[0]+list(np.logspace(-8,1,10))
nodes=[(i,) for i in range(5,30,10)]+\
      [(i,j) for i in range(5,30,10) for j in range(2,10,5)]
clf3=GridSearchCV(neural_network.MLPClassifier(solver='lbfgs'),
                  {'alpha':alpha,'hidden_layer_sizes':nodes},cv=5,return_train_score=True)

clf3.fit(X,y)
print('BP-最佳参数:',clf3.best_params_,
      '最佳得分:',clf3.best_score_,
      '对应拟合耗时:',clf3.cv_results_['mean_fit_time'][clf3.best_index_])

#===========4.决策树================
deep=[None,2,4,8,10,12,14,16]
minleaf=[5,4,3,2,1]
clf4=GridSearchCV(tree.DecisionTreeClassifier(),
                  {'max_depth':deep,'min_samples_leaf':minleaf},cv=5,return_train_score=True)
clf4.fit(X,y)
print('Tree-最佳参数:',clf4.best_params_,
      '最佳得分:',clf4.best_score_,
      '对应拟合耗时:',clf4.cv_results_['mean_fit_time'][clf4.best_index_])

习题6.8(Python)

# -*- coding: utf-8 -*-
"""
Created on Wed Dec 25 15:53:59 2019

@author: MS
"""

from sklearn import svm
import numpy as np
import matplotlib.pyplot as plt

#========西瓜数据集3.0α============
X=np.array([[0.697,0.46],[0.774,0.376],[0.634,0.264],[0.608,0.318],[0.556,0.215],
   [0.403,0.237],[0.481,0.149],[0.437,0.211],[0.666,0.091],[0.243,0.267],
   [0.245,0.057],[0.343,0.099],[0.639,0.161],[0.657,0.198],[0.36,0.37],
   [0.593,0.042],[0.719,0.103]])
Y=np.array([1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0])

#西瓜数据集3.0α中的密度和含糖量数据
x=X[:,0].reshape(-1, 1)
y=X[:,1]

#人为生成数据(若要计算西瓜数据集,可以将下面两行注释掉)
x=np.linspace(0,1,20).reshape(-1, 1)
y=np.sin(x*3.14)+np.random.randn(20,1)*0.1

#分别采用线性核和高斯核来拟合
reg1=svm.SVR(C=30,kernel='linear',epsilon=0.01).fit(x,y)
reg2=svm.SVR(C=30,kernel='rbf',epsilon=0.01).fit(x,y)

#画图
px=np.linspace(min(x),max(x),20).reshape(-1, 1)
plt.scatter(x,y,c='r',label='data')
plt.plot(px,reg1.predict(px),'g--',label='linear')
plt.plot(px,reg2.predict(px),'b--',label='rbf')
plt.legend()
plt.title('SVR result\n C=30,epsilon=0.01')
plt.xlabel('rou')
plt.ylabel('Sugar ratio')

你可能感兴趣的:(第六章 支持向量机)