您的位置:首页 > 其它

机器学习实战之SVM

2017-04-10 10:22 537 查看
1 算法概述

典型传统的SVM跟Logistic一样也是一个二分类问题,就是训练一个决策面,使数据最大程度的分布在决策面两侧。如下图所示:



中间的那条线就是一个决策面。使得图中O数据集与×数据集分布在决策面两侧。

上图中的函数可以写成

,对于位于线上的点,y=0,位于线上方的点,属于1类,此时y>0,位于线下方的点,属于-1类,此时y<0。对于一个点集分类,当决策面里数据点越远,也就是说决策面离数据点的“间隔”越大,比如上图中点C到中间那条线的距离越大,那么分类的确信度就越高,为了使决策面的分类确信度越高,那必然就得最大化这个“间隔”。如下图所示:



那么问题又来了,怎样使得这个Gap最大呢?这里引入一个函数间隔

,这里y是类别的标签,只有+1,与-1两种情况,所以,当数据点为1类时且远离决策面时,

将是一个较大的数,从而

也将是一个较大的数;当数据点为-1类且远离决策面时,

将是一个很大的负数,再乘上-1,最终的

结果也将是一个较大的数。所以如果要找到“间隔”Gap最大的点,就是要找到离决策面最近的数据点,也就是必须找到支持向量。这里引入一个几何间隔

,现在就是想这个几何间隔最大化,那么现在的目标函数就是

,可以转化成

,就是在

下,使得

最大。

2 通过SMO实现w,b的最优

工作原理:首先初始化两个alpha,然后每循环进行优化处理,一旦找到两个“合适”的alpha,就同时进行相同的修改,但方向相反。这里的“合适”指的是满足一定条件,即两个alpha必须在间隔边界之外,不在间隔边界上。

def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
dataMatrix = mat(dataMatIn); labelMat = mat(classLabels).transpose() #transpose()求转置的函数
b = 0; m,n = shape(dataMatrix) # m,n=shape(A):求矩阵A的大小,m返回矩阵的行,n返回矩阵的列,这里m=100 n=2
alphas = mat(zeros((m,1)))#初始化alphas,整个SVM的目的就是求最优化的alphas与常数b
iter = 0
while (iter < maxIter):
alphaPairsChanged = 0
for i in range(m):
#.T是Numpy当中实现的矩阵转置的方法,[i,:]是Numpy花式索引
#这句话的意思是对每个样本预测类别
fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
Ei = fXi - float(labelMat[i])#误差
#不管样本属于正间隔范围还是负间隔范围其alpha都需要优化
if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
j = selectJrand(i,m) #随机选择第二个alpha
fXj = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
Ej = fXj - float(labelMat[j])
alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
#将alpha控制在0与C之间,L,H分别为alpha的最小与最大值
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])
#当L==H,则alpha已经到了边界,成为了支持向量,就跳出内循环
if L==H: print "L==H"; continue
#eta表示对alpha的修改量
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


求得最优化alphas系列 与b两组参数之后,就很容易计算权重向量,进而,得到分隔面。

def calcWs(alphas,dataArr,classLabels):
X = mat(dataArr); labelMat = mat(classLabels).transpose()
m,n = shape(X)
w = zeros((n,1))
for i in range(m):
w += multiply(alphas[i]*labelMat[i],X[i,:].T)
return w


3 复杂数据集上应用的核函数

对于线性不可分的数据,SVM选择用核函数处理。就是通过核函数,它可以事先在低维空间上计算,然后将数据映射到高维空间,实现分类效果,也就是说,在高维空间解决线性问题等价于在低维空间解决非线性问题。如下图所示



首先,我们定义一下核函数:如果原始特征内积是

,映射后为

,那么定义核函数为:

。(这里的

表示从原始输入空间X到内积特征空间F的映射)

在高维特征空间中对训练数据通过超平面进行分类,避免了直接在原输入空间中寻找非线性函数来进行分类。支持向量机的分类函数具有这样的性质:它是一组以支持向量为参数的非线性函数的线性组合,因此分类函数的表达式仅和支持向量的数量有关,而独立于空间的维度。

用核函数进行分类:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  机器学习