以下是我的学习笔记,以及总结,如有错误之处请不吝赐教。
本文主要介绍svm的创始人Vapnik‘s如何一步一步构建出这个经典算法模型的,同时也可以给我们以后算法之路提供一个思路,即使你对优化等数学方法不熟悉,依然可以创造出很好的算法。
下svm关键的几个idea:
KEY IDEA 1:支持向量机最关键的一个假设是我们在分类过程中,最重要的是找到一个决策边界,而且我们希望这个决策边界泛化能力是最好的,而svm则是找到一条widest street way,这条街是由支持向量所构成的。我们假设支持向量所在点与原点构成的向量为,与决策边界垂直的方向法向量为
,支持向量到决策边界的距离表示为b,那么我们就用这三个值表示出他们的关系:
KEY IDEA 2:我们假设这条street的宽度为1,那么仅针对训练集有 :,假设
,那么我们将两式相乘合并为一个公式,就可以得到第二个关键公式:
其中:取值为0的即为支持向量。
KEY IDEA 3:那么我们如何使得这条street越宽越好呢?这条街的宽度可以表示为:,分别将
代入,可以得到:
,
,得到:
因此我们只需要求得,即
,即:
s.t
KEY IDEA 4:将其代入拉格朗日多项式得到:
分别对和b求导得到:
分别令其等于0,求得:
,
代入原式:
SVM另一种理解:假设一个函数叫做合页损失函数(hinge loss):
合页损失的函数图像如下所示:
SMO算法(sequential minimal optimization):
首先介绍坐标上升法:这个方法的思想是固定其他参数变量,先求其中一个变量的最大值。
SMO算法则是在坐标上升法之上改进一下,每次选择两个变量进行优化(两个变量其实等价于一个变量):
算法流程:(具体流程参考李航的《统计学习方法》P126-130页)
核心代码:
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
dataMatrix = mat(dataMatIn); labelMat = mat(classLabels).transpose()
b = 0; m,n = shape(dataMatrix)
alphas = mat(zeros((m,1)))
iter = 0
while (iter < maxIter):
alphaPairsChanged = 0
for i in range(m):
fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
Ei = fXi - float(labelMat[i])#if checks if an example violates KKT conditions
if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
j = selectJrand(i,m)
fXj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
Ej = fXj - float(labelMat[j])
alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
if (labelMat[i] != labelMat[j]):
L = max(0, alphas[j] - alphas[i])
H = min(C, C + alphas[j] - alphas[i])
else:
L = max(0, alphas[j] + alphas[i] - C)
H = min(C, alphas[j] + alphas[i])
if L==H: print("L==H"); continue
eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T
if eta >= 0: print("eta>=0"); continue
alphas[j] -= labelMat[j]*(Ei - Ej)/eta
alphas[j] = clipAlpha(alphas[j],H,L)
if (abs(alphas[j] - alphaJold) < 0.00001): print("j not moving enough"); continue
alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#update i by the same amount as j
#the update is in the oppostie direction
b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T
b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T
if (0 < alphas[i]) and (C > alphas[i]): b = b1
elif (0 < alphas[j]) and (C > alphas[j]): b = b2
else: b = (b1 + b2)/2.0
alphaPairsChanged += 1
print("iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))
if (alphaPairsChanged == 0): iter += 1
else: iter = 0
print("iteration number: %d" % iter)
return b,alphas
软间隔分类器:当数据线性不可分时,即使映射到高维空间并不能保证线性可分,如下图所示:
而软间隔分类器则是允许数据拥有小于1的几何间隔,但是要受到惩罚:
代入拉格朗日函数得到:
从而得到新的对偶问题:
对比原来只是对做了更多约束,新约束下的SMO算法如下图:
核技法:
同时我们可以在求其支持向量时使用核函数,将很多线性不可分的情况,映射至高维空间,而不用求其映射函数,只需求:
径向基函数:是某种沿径向对称的标量函数,通常定义为样本到数据中心之间径向距离(通常是欧氏距离)的单调函数(由于距离是径向同性的)。具体参考:RBF径向基函数
多项式核函数:
对应映射函数:
加常数项的多项式核函数:
对应映射函数:
高斯核函数:
以上是几个核函数的例子,那么什么样的核是合法的呢?
Mercer定理:K是合法的核的充分必要条件是对于一个有限的数据集,对应的和矩阵都是半正定矩阵。关于半正定矩阵可自行百度。
以下是几个常用的核函数:
通过以上的叙述,可以总结SVM有以下性质:
- 数学特性:凸优化问题,保证会有全局最优解
- 模型特性:
- 可以处理高维数据
- 软间隔降低过拟合
- 求解完成后只有少数数据起作用
- 灵活的选择核函数
下次将介绍另一个经典算法:EM算法,未完,To be continue......