【菜菜的sklearn课堂笔记】支持向量机-非线性SVM与核函数

时间:2022-11-21 11:22:56

视频作者:菜菜TsaiTsai 链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili

这一节是核函数的过度

如果把数据推广到非线性数据,比如说环形数据上

from sklearn.datasets import make_circles
X,y = make_circles(100, factor=0.1,noise=0.1)

X.shape
---
(100, 2)

y.shape
---
(100,)

plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")

【菜菜的sklearn课堂笔记】支持向量机-非线性SVM与核函数

clf = SVC(kernel='linear').fit(X,y)
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap='rainbow')
plot_svc_decision_function(clf)

【菜菜的sklearn课堂笔记】支持向量机-非线性SVM与核函数

明显,现在线性SVM已经不适合于我们的状况了,我们无法找出一条直线来划分我们的数据集,让直线的两边分别是两种类别。这个时候,如果我们能够在原本的X和y的基础上,添加一个维度r,变成三维,我们可视化这个数据,来看看添加维度让我们的数据如何变化。

r = np.exp(-(X**2).sum(1))
# sum(1)每行求和
# np.exp表示e的x次方,x为输入的数字

r.shape
---
(100,)

from mpl_toolkits import mplot3d

def plot_3D(elev=30,azim=30,X=X,y=y):
    ax = plt.subplot(projection="3d")
    ax.scatter3D(X[:,0],X[:,1],r,c=y,s=50,cmap="rainbow")
    # 多了一个维度r
    ax.view_init(elev=elev,azim=azim)
    # 旋转视图的角度,elev上下旋转的角度,azim左右旋转的角度
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    ax.set_zlabel("z")
    plt.show()
    
plot_3D()

【菜菜的sklearn课堂笔记】支持向量机-非线性SVM与核函数

可以看见,此时此刻我们的数据明显是线性可分的了:我们可以使用一个平面来将数据完全分开,并使平面的上方的所有数据点为一类,平面下方的所有数据点为另一类。

from ipywidgets import interact,fixed
interact(plot_3D,elev=[0,30],azip=(-180,180),X=fixed(X),y=fixed(y))
# 用到啥说啥
# elev和azip后面传入元组,就是一个可平滑调节的按钮,传入列表,就是一个下拉菜单,只能选择菜单中的角度

【菜菜的sklearn课堂笔记】支持向量机-非线性SVM与核函数

此时我们的数据在三维空间中,我们的超平面就是一个二维平面。我们刚才做的,计算r,并将r作为数据的第三维度来将数据升维的过程,被称为“核变换”,即是将数据投影到高维空间中,以寻找能够将数据完美分割的超平面,即是说寻找能够让数据线性可分的高维空间。

SVC在非线性数据上的推广

为了能够找出去非线性数据的线性决策边界,我们需要将数据从原始的空间$x$投射到新空间$\Phi (x)$中。$\Phi (x)$是一个映射函数,它代表了某种非线性的变换,如同我们之前所做过的使用r来升维一样。使用这种变换,线性SVM的原理可以被很容易推广到非线性情况下,其推导过程和逻辑都与线性SVM一模一样,只不过在定义决策边界之前,我们必须先对数据进行升维度,即将原始的$x$转换成$\Phi (x)$ 如此,非线性SVM的损失函数的初始形态为 $$ \left{\begin{aligned}&\mathop{\text{min }}\limits_{\omega,b}\frac{||\omega||^{2}}{2}\ &y_{i}(\omega \cdot \Phi (x_{i})+b)\geq 1,i=1,2,\cdots,N\end{aligned}\right. $$ 同理,非线性SVM的拉格朗日函数和拉格朗日对偶函数也可得 $$ \begin{aligned} L(\omega,b,\alpha)&=\frac{1}{2}||\omega||^{2}- \sum\limits_{i=1}^{N}\alpha_{i}(y_{i}(\omega \cdot \Phi (x_{i})+b)-1)\ L_{d}&=\sum\limits_{i=1}^{N}\alpha_{i}- \frac{1}{2}\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_{i}\alpha_{j}y_{i}y_{j}\Phi (x_{i})\Phi (x_{j}) \end{aligned} $$ 使用同样的推导方式,让拉格朗日函数满足KKT条件并在拉格朗日函数上对每个参数求导,经过和线性SVM相同的变换后,就可以得到拉格朗日对偶函数。同样使用梯度下降或SMO等方式对$\alpha$进行求解,最后可以求得决策边界,并得到最终的决策函数 $$ f(x_{test})=sign(\omega \cdot \Phi (x_{test})+b)=sign\left(\sum\limits_{i=1}^{N}\alpha_{i}y_{i}\Phi (x_{i})\cdot \Phi (x_{test})+b\right) $$

重要参数kernel

这种变换非常巧妙,但也带有一些实现问题。 首先,我们可能不清楚应该什么样的数据应该使用什么类型的映射函数来确保可以在变换空间中找出线性决策边界。极端情况下,数据可能会被映射到无限维度的空间中,这种高维空间可能不是那么友好,维度越多,推导和计算的难度都会随之暴增。其次,即使已知适当的映射函数,我们想要计算类似于$\Phi (x_{i})\cdot \Phi (x_{test})$这样的点积,计算量可能会无比巨大,要找出超平面所付出的代价是非常昂贵的。 而解决这些问题的数学方式,叫做**“核技巧”(Kernel Trick),是一种能够使用数据原始空间中的向量计算来表示升维后的空间中的点积结果的数学方式**。具体表现为,**$K(u,v)=\Phi (u)\cdot \Phi (v)$。而这个原始空间中的点积函数$K(u,v)$,就被叫做“核函数”(Kernel Function)**。

这里超出个人能力范围了,只能跑一下代码,以后再研究吧

核函数能够帮助我们解决三个问题:

  1. 有了核函数之后,我们无需去担心$\Phi$究竟应该是什么样,因为非线性SVM中的核函数都是正定核函数(positive definite kernel functions),他们都满足美世定律(Mercer's theorem),确保了高维空间中任意两个向量的点积一定可以被低维空间中的这两个向量的某种计算来表示(多数时候是点积的某种变换)。
  2. 使用核函数计算低维度中的向量关系比计算原本的$\Phi (x_{i})\cdot \Phi (x_{test})$要简单太多了
  3. 因为计算是在原始空间中进行,所以避免了维度诅咒的问题。

选用不同的核函数,就可以解决不同数据分布下的寻找超平面问题。在SVC中,这个功能由参数“kernel”和一系列与核函数相关的参数来进行控制。参数“kernel"在sklearn中可选以下几种选项:

输入 含义 解决问题 核函数表达式 参数gamma 参数degree 参数coef0
linear 线性核 线性 $K(x,y)=x^{T}y=x \cdot y$
poly 多项式核 偏线性 $K(x,y)=(\gamma(x \cdot y)+r)^{d}$
sigmoid 双曲正切核 非线性 $K(x,y)=\tanh(\gamma (x \cdot y)+r)$
rbf 高斯径向基 偏非线性 $K(x,y)=e^{-\gamma|x-y|^{2}},\gamma>0$

可以看出,除了选项"linear"之外,其他核函数都可以处理非线性问题。多项式核函数有次数d,当d为1的时候它就是再处理线性问题,当d为更高次项的时候它就是在处理非线性问题。

我们之前画图时使用的是选项“linear",自然不能处理环形数据这样非线性的状况。而刚才我们使用的计算r的方法,其实是高斯径向基核函数所对应的功能,在参数”kernel“中输入”rbf“就可以使用这种核函数。我们来看看模型找出的决策边界时什么样:

clf = SVC(kernel="rbf").fit(X,y)
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plot_svc_decision_function(clf)

【菜菜的sklearn课堂笔记】支持向量机-非线性SVM与核函数

可以看到,决策边界被完美地找了出来