0 声明
本文主要内容来自视频'【2020机器学习全集】菜菜的sklearn完整版,价值4999元的最全机器学习sklearn全集,赶紧收藏_哔哩哔哩_bilibili',课件来自“https://pan.baidu.com/s/1Xl4o0PMA5ysUILeCKvm_2w,提取码:a967”。
除了上述视频和课件之外,'支持向量机(SVM)原理小结(3)支持向量回归SVR_小白的专栏-CSDN博客_支持向量机回归原理'这篇文章也给了我很大帮助。
1 SVC 与SVR
Support Vector Machine(SVM)广泛应用于有监督学习、无监督学习与半监督学习,这里主要谈谈它在有监督学习中的应用。有监督学习可分为回归问题与分类问题两种,SVM都有相应的模块:分类问题对应于SVM中的Linear Support Vector Classification(支持向量线性分类,LSVC)、Support Vector Classification(支持向量非线性分类, SVC),回归问题对应于Support Vector Regression(支持向量回归, SVR),SVM在这两类问题的表现都不错。
2 支持向量机二分类器工作原理
2.1 直观理解
在几何中,超平面是一个空间的子空间,它是维度比所在空间小一维的空间。在二分类问题中,如果一个超平面能够将数据划分为两个集合,其中每个集合中包含单独的一个类别,就说这个超平面是数据的“决策边界”。
支持向量分类器所做的事情非常容易理解。如图所示,这是一组有两种标签的数据,两种标签分别由圆和方块代表。支持向量机的分类方法是在这组分布中找出一个超平面作为决策边界,使模型在在未知数据集上的分类误差(泛化误差)尽量小。
显然,对于一个数据集而言,使得误差最小的决策边界并不唯一,甚至可以有无数条:
下图有B1和B2两条可能的决策边界。现在把决策边界B1和B2向两边平移,直到碰到离这条决策边界最近的方块和圆圈后停下,这样就分别形成了两个新的超平面,分别是b11, b12和b21,b22,最后将原始的决策边界B1和B2分别移动到b11, b12和b21,b22的中间,确保B1到b11, b12;B2到b21,b22的距离相等。b11, b12或者b21,b22之间的距离,叫做决策边界B1, B2的的边际(margin),通常记作d1, d2。训练数据集的决策边界可能有无数条,但是不同的边界在测试集上的表现是不一样的,决策边界的边际d越大,该决策边界上的泛化误差就越小。下图决策边界B1的边际d1明显大于B2的边际d2。在引入和原本的数据集相同分布的测试样本(红色所示)之后,决策边界B1的正确率仍然是1,而B2就存在误分的的样本。这很好理解,如果边际很小,则任何轻微扰动都会对决策边界的分类产生很大的影响,类似于过拟合。
支持向量分类器的工作原理就是找出边际最大的决策边界来进行分类,基于此,支持向量分类器又叫做最大边际分类器。
2.2 数学原理
对于支持向量分类器的理解,一般人在直观理解就到头了,这里就不再赘述其具体的数学原理,只给出整个推导思路:
支持向量机二分类器的目的在于找出边际最大的决策边界,这显然是一个函数求最值的问题,那当然是先计算出边际d的等价表达式及其约束条件:
然后问题就转变为了在一定约束条件下求其函数最值的问题,这实际上是一个拉格朗日乘数法的典型应用:
( * )
上式也等价于:
对( * )式的w与b求偏导,并令其等于0可得:
为了求解上式,还需要将拉格朗日函数转化为拉格朗日对偶函数,转化的前提是拉格朗日函数能够满足KKT条件(Karush-Kuhn-Tucker):
幸运的是,对于支持向量机而言,KKT条件是天然满足的,那么便可得到下式:
通过上式可知只需要求解对偶函数的最大值便可以求解出,最终目标函数便可化为:
求得之后,便可以求解出w与b,最终得到决策函数:
3 LSVC在非线性数据上的推广
LSVC只能处理线性数据的分类问题,针对非线性数据的处理效果并不好。主要原因在于LSVC只能绘制直线进行数据分类。为了实现非线性数据的分类,需要将数据从原始的空间X中映射到新的高维空间中(是一个映射,代表一种非线性变换,使用这种变换很容易将LSVC的原理推广到非线性情况,数学推导过程也是类似的,只需要将第2节公式中的x转换为即可)。
下图是一个使用LSVC处理非线性数据分类的例子:
可以明显地看出,分类效果并不理想,下面使用某种变换,把数据升到三维空间中,可得:
将二维数据利用某种变换升维到三维空间后,就可以很容易通过一个平面(线性的)对数据进行划分,下面再利用LSVC的分类逻辑,便可以得到下图:
这分类效果属实是太棒了。不过现在还存在一个问题,应该如何确定,或者说不同数据类型的数据应该使用什么样的。同样幸运的是,数学家已经找出了问题的解决之道,解决的办法就是核技巧(Kernel Trick)。这是一种能够使用数据原始空间中的向量计算来表示升维后的空间中的点积结果的数学方式,写成数学表达式就是:,其中的被叫做核函数(Kernel Function)。有了核函数之后,就无需担心的表达式是什么样子,因为非线性SVM中的核函数都是正定核函数 (positive definite kernel functions),都满足美世定律(Mercer's theorem),这确保了高维空间中任意两个向量的点积一定可以被低维空间中的这两个向量的某种计算来表示(多数时候是点积的某种变换)。
下表示常用核函数的简要介绍:
可以看出,除了选项"linear"之外,其他核函数都可以处理非线性问题。多项式核函数有次数d,当d为1的时候就是在处理线性问题,当d为更高次项的时候它就是在处理非线性问题。
对于核函数的使用,有以下几点技巧:
(1)一般而言,对于线性数据集,应该使用线性核或者d为1的多项式核;
(2)对于非线性数据应该使用高斯径向核;
(3)多项式核函数计算高次项非常缓慢;
(4)另外,使用SVM之前,一定要先无量纲化,因为SVM的本质还是计算的是距离,跟KNN算法类似,对于数据的量纲较为敏感;
(5)线性核没有参数,不需要调参,高斯径向核只有一个参数,可以使用学习曲线调参,另外两个需要使用网格法调参。
4 LSVC在软间隔数据上的推广
当两组数据是完全线性可分,可以找出一个决策边界使得训练集上的分类误差为0,这两种数据就被称为是存在”硬间隔“的。当两组数据几乎是完全线性可分的,但决策边界在训练集上存在较小的训练误差,这两组数据就被称为是存在”软间隔“。下图所示的两组数据就是典型的软间隔数距,因为这些软间隔数据的存在,决策边界B1的准确率会低于B2,但事实上决策边界B1的分类效果还是要优于B2的。
为了使得支持向量及能够解决软间隔数据的问题,需要重新修改对决策边界的定义,让其能够忍受少部分训练误差,修改方法实际上也就是将超平面往d增大的方法适当移动个单位。然而这种移动又会引起新的问题:原本正确分类的点因为超平面的一定又被错误分类了。因此,必须在求解最大边际的损失函数中加上一个惩罚项C,用来惩罚具有巨大松弛系数的决策超平面:
基于上式,按照第2节的推导思路,重新获得拉格朗日函数、KKT条件、拉格朗日对偶函数,最终获得考虑了软间隔的决策函数即可。
最后也是最重要的是,C是一个重要的参数,它用于权衡”训练样本的正确分类“与”决策函数的边际最大化“两个不可同时完成的目标,希望找出一个平衡点来让模型的效果最佳。C默认为1,而且必须大于等于0,如果C值设定比较大,那SVC可能会选择边际较小的,能够更好地分类所有训练点的决策边界,不过模型的训练时间也会更长。如果C的设定值较小,那SVC会尽量最大化边界,决策功能会更简单,但代价是降低训练的准确度。
5 支持向量机分类器应用实例
基于sklearn实现,数据来源于sklern自带的乳腺癌数据。
5.1 SVC基本应用
from sklearn.datasets import load_breast_cancer # 导入数据
from sklearn.svm import SVC # 支持向量机分类器
from sklearn.model_selection import train_test_split # 划分数据集
from sklearn.preprocessing import StandardScaler # 标准化
data = load_breast_cancer()
X = data.data
X = StandardScaler().fit_transform(X) # 标准化
y = data.target
Xtrain, Xtest, Ytrain, Ytest = train_test_split( # 数据标准化后效果很棒
X, y, test_size=0.3, random_state=420)
Kernel = ["linear", "poly", "rbf", "sigmoid"]
for kernel in Kernel:
clf = SVC(kernel=kernel, gamma="auto", degree=1, cache_size=5000
).fit(Xtrain, Ytrain)
print("The accuracy under kernel %s is %f" %
(kernel, clf.score(Xtest, Ytest)))
5.2 一个使用网格搜索优化多项式核函数参数的实例
from sklearn.datasets import load_breast_cancer # 导入数据
from sklearn.svm import SVC # 支持向量机分类器
from sklearn.preprocessing import StandardScaler # 标准化
from sklearn.model_selection import StratifiedShuffleSplit # 用于支持带交叉验证的网格搜索
from sklearn.model_selection import GridSearchCV # 带交叉验证的网格搜索
data = load_breast_cancer()
X = data.data
X = StandardScaler().fit_transform(X)
y = data.target
gamma_range = np.logspace(-10, 1, 20)
coef0_range = np.linspace(0, 5, 10)
param_grid = dict(gamma=gamma_range, coef0=coef0_range)
cv = StratifiedShuffleSplit(
n_splits=5, test_size=0.3, random_state=420) # 将数据分为5份,5份数据中测试集占30%
grid = GridSearchCV(SVC(kernel="poly", degree=1, cache_size=5000) ,param_grid=param_grid, cv=cv)
grid = grid.fit(X, y)
print("The best parameters are %s with a score of %0.5f" % (grid.best_params_,grid.best_score_))
5.3 一个调整参数C的例子
from sklearn.datasets import load_breast_cancer # 导入数据
from sklearn.svm import SVC # 支持向量机分类器
from sklearn.model_selection import train_test_split # 划分数据集
from sklearn.preprocessing import StandardScaler
data = load_breast_cancer()
X = data.data
X = StandardScaler().fit_transform(X)
y = data.target
Xtrain, Xtest, Ytrain, Ytest = train_test_split( # 数据归一化后效果很棒
X, y, test_size=0.3, random_state=420)
score = []
C_range = np.linspace(5,7,50)
for i in C_range:
clf = SVC(kernel="rbf",C=i,gamma =
0.012742749857031322,cache_size=5000).fit(Xtrain,Ytrain)
score.append(clf.score(Xtest,Ytest))
print(max(score), C_range[score.index(max(score))])
6 支持向量回归器工作原理
6.1 直观理解
SVM分类就是找到一个平面,让两个分类集合的支持向量或者所有的数据(LSVM)离分类平面最远;SVR回归,就是找到一个回归平面,让一个集合的所有数据到该平面的距离最近。
传统回归方法当且仅当回归f(x)完全等于y时才认为预测正确,而支持向量回归比较宽容,它认为只要f(x)与y偏离程度不要太大,既可以认为预测正确,不用计算损失。具体的,就是设置阈值α,只计算|f(x)−y|>α的数据点的loss,如下图所示,阴影部分的数据点都认为该模型预测准确了,只计算阴影外的数据点的loss:
6.2 数学原理
数学原理只说思路,不讲推导。
SVR问题可化为一个有约束的目标函数(考虑松弛变量后,且允许间隔带两侧的松弛程度不同):
然后按照第2节的思路,考虑拉格朗日函数、KKT条件以及拉格朗日对偶函数后,可以得到新的决策函数:
其中,与分别代表拉格朗日乘子与a的解,
6.3 一个利用SVR求解波士顿房价的实例
基于sklearn模块,数据来源于内嵌的波士顿房价数据集。
from sklearn.datasets import load_boston # 导入数据集
from sklearn.model_selection import train_test_split # 划分数据集
from sklearn.model_selection import GridSearchCV # 网格搜索
from sklearn.feature_selection import SelectKBest, f_regression # 使用F检验选择特征
from sklearn.preprocessing import MinMaxScaler # 导入归一化模块
from sklearn.svm import SVR # 导入支持向量分类器
from matplotlib import pyplot as plt # 导入绘图模块
x = load_boston().data
y = load_boston().target
scaler = MinMaxScaler() # 实例化
x = scaler.fit_transform(x) # 归一化数据结果
selector = SelectKBest(f_regression, k=8) # 实例化
x = selector.fit_transform(x, y) # 使用F回归选择最优的8个特征
Xtrain, Xtest, Ytrain, Ytest = train_test_split(
x, y, test_size=0.3, random_state=168)
svr = SVR(kernel="rbf") # rbf核
# 网格搜索
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
grid = GridSearchCV(svr, param_grid=param_grid, cv=5)
ypred = grid.fit(Xtrain, Ytrain).predict(Xtest)
print(grid.best_score_)
# 绘图
x_axis = range(0, len(Xtest))
y_axis1 = Ytest
y_axis2 = ypred
plt.figure(figsize=(20, 8), dpi=80)
plt.plot(x_axis, y_axis1, label='true value')
plt.plot(x_axis, y_axis2, label='predict value')
plt.grid(alpha=0.3)
plt.ylabel("housing price")
plt.legend()
plt.show()
输出结果:
0.8636732480002942