引言:
前边几篇文章中提到的分类数据点,我们都假设是线性可分的,即存在超平面将样本正确分类,然而现实生活中,存在许多线性不可分的情况,例如“异或”问题就不是线性可分的,看一下西瓜书上的一个"异或"的例子,对于二维数据点,[0,0],[1,1]属于0类,[0,1],[1,0]属于1类,我们就无法用一条直线超平面将样本数据分类.
线性可分-常规数据
线性不可分-异或问题
对于上述问题,无论如何我们都无法找到一条直线将这两类数据分开,这时一种分类方法就是将原始数据从原始空间映射到高维空间,使得样本在高维特征空间中线性可分.
二维转三维-解决线性不可分
我们通过二维→三维的转化,用一个斜切面将数据点划分,两个蓝色标记在面下面,两个红色标记在面上面,从而完成了在高维空间的数据分类.
数据映射:
令φ(x)为X映射后的特征向量,在特征空间中划分超平面的模型可以表示为:
类似于低维超平面寻找最优间隔,映射后的数据有:
同前,转化为对偶问题:
核函数的引入:
上面的计算涉及到计算 φ(xi).T*φ(xj) ,这是xi,xj映射到高维空间后的内积,文章开头的数据是两维且数据量少,所以到三维就解决了问题,但现实生活中,我们遇到问题的可能包含多个属性,这时不是简单的升高一维就可以实现分类,甚至可能是无穷维,此时我们计算φ(xi).T*φ(xj)就很困难.
所以就想到有没有一个函数可以满足:
即在低维通过k(i,j)计算特征空间的内积,省去高维计算的复杂情况,这样就简化了问题.
于是优化问题转化为:
和之前的对偶问题解决方式一样,通过拉格朗日乘子引入与求导化简,这里我们可以得到:
这里的k(xi,x)就是核函数(Kernel Function),上式显示模型的最优间隔可以通过训练样本核函数展开,所以这个式子也称为支持向量展式.
核函数的条件:
上面是我们在想有这样一个核函数,但是问题也随之而来,φ(xi)的具体形式是怎么样,即合适的核函数是什么样子的,西瓜书上有这个定理:
令X为输入空间,k(·,·)为X*X上的对称函数,K是核函数当且仅当对于任意数据D={x1,x2,x3...,xm},核矩阵K总是半正定的.
Tips:半正定(广义):A是n阶方阵,对于任何非零向量X,都有X.T*A*X≥0,则称矩阵A是半正定的.
定理表示,只要一个对称函数所对应的核矩阵半正定,它就能作为核函数使用. 而对于一个半正定矩阵而言,总能找到一个与之对应的 φ(·) ,从而任何一个核函数都隐式的定义了一个“再生希尔伯特空间”的特征空间.
核函数的选择:
我们希望样本在特征空间中线性可分,因此特征空间的好坏对支持向量机的性能至关重要,但是在不知道特征映射的情况下,我们是不知道什么样的核函数是适合的,而核函数也只是隐式的定义了特征空间,所以,核函数的选择对于一个支持向量机而言就显得至关重要,若选择了一个不合适的核函数,则数据将映射到不合适的样本空间,从而支持向量机的性能将大大折扣.
下面介绍几个常用的核函数,在调参的时候,我们可以使用不同的核函数,看看哪个核函数是最适合样本数据的:
线性核(linear):
多项式核(poly):
高斯核(rbf):
拉普拉斯核(laplace):
Sigmoid核(sigmoid):
核函数python编码:
上面介绍了几种常见的核函数,针对一般的二维数据点分类,lin线性核就能够完成任务,而比较复杂的二维数据点或者更高维的数据点,则需要我们尝试不同的核函数,一般来说,可以先使用rbf高斯核来试验.这里我们给出几中核函数的转换代码,之后我们就可以在给定的数据上用这些核函数完成特征映射,从而让支持向量机发挥更好的性能:
def kernelTrans(X, A, kTup): #通过数据计算转换后的核函数
m,n = shape(X)
K = mat(zeros((m,1)))
if kTup[0]=='lin': #线性核函数
K = X * A.T
elif kTup[0]=='rbf':#高斯核
for j in range(m):
deltaRow = X[j,:] - A
K[j] = deltaRow*deltaRow.T
K = exp(K/(-1*kTup[1]**2))
elif kTup[0] == 'laplace':#拉普拉斯核
for j in range(m):
deltaRow = X[j,:] - A
K[j] = deltaRow*deltaRow.T
K[j] = sqrt(K[j])
K = exp(-K/kTup[1])
elif kTup[0] == 'poly':#多项式核
K = X * A.T
for j in range(m):
K[j] = K[j]**kTup[1]
elif kTup[0] == 'sigmoid':#Sigmoid核
K = X * A.T
for j in range(m):
K[j] = tanh(kTup[1]*K[j]+kTup[2])
else: raise NameError('Houston We Have a Problem -- \
That Kernel is not recognized')
return K
总结:
这里对核函数进行了简单的介绍,它在数据转换,特征映射中能大显身手,但其中也存在许多黑箱,很多时候映射的具体形式,映射的高维空间我们都无法知悉,这里只是显式的使用它,而许多隐式的东西还需更多的探索.最后的核函数转换函数将在下一篇用核函数分类的支持向量机中体现价值.