《机器学习实战》(六)—— SVM(SMO算法)
2017-08-14 本文已影响185人
033a1d1f0c58
http://blog.csdn.net/u011239443/article/details/77170119
关于SVM的讲解可以参阅《机器学习技法》的相关笔记:http://blog.csdn.net/u011239443/article/details/76572743
SMO算法
实现
# -*- coding: utf-8 -*-
from numpy import *
# 加载数据
def loadDataSet(fileName):
dataMat = [];labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr = line.strip().split('\t')
dataMat.append([float(lineArr[0]),float(lineArr[1])])
labelMat.append([float(lineArr[2])])
return dataMat,labelMat
# 从0到m中产生一个不为i的整数
def selectJrand(i,m):
j = i
while(j == i):
j = int(random.uniform(0,m))
return j
# 使得aj 在边界值[L,H]以内
def clipAlpha(aj,H,L):
if aj > H:
aj = H
if L > aj:
aj = L
return aj
#SMO 序列最小优化
def smoSimple(dataMatIn,classLabels,C,toler,maxIter):
# 这里书上的代码有误,不用mat(classLabels)不用转置
dataMat = mat(dataMatIn);labelMat = mat(classLabels);
b = 0;m,n = shape(dataMat)
alphas = mat(zeros((m,1)))
iter = 0
# alphaPairsChanged 用来更新的次数
# 当遍历 连续无更新 maxIter 轮,则认为收敛,迭代结束
while iter < maxIter:
alphaPairsChanged = 0
for i in range(m):
# KKT 条件计算出
fXi = float(multiply(alphas,labelMat).T * (dataMat*dataMat[i,:].T))+b
# 误差
Ei = fXi - float(labelMat[i])
# toler:容忍错误的程度
# labelMat[i]*Ei < -toler 则需要alphas[i]增大,但是不能>=C
# labelMat[i]*Ei > toler 则需要alphas[i]减小,但是不能<=0
if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
# 从0到m中产生一个不为i的整数
j = selectJrand(i,m)
fXj = float(multiply(alphas,labelMat).T * (dataMat*dataMat[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
# 见式 7.107
eta = -2.0* dataMat[i,:] * dataMat[j,:].T + dataMat[i,:] *\
dataMat[i,:].T + dataMat[j,:] * dataMat[j,:].T
if eta <= 0:print "eta <= 0";continue
# 见式 7.106
alphas[j] += labelMat[j]*(Ei-Ej)/eta
# 见式 7.108 ,讲alphas[j] 约束在 [L,H]
alphas[j] = clipAlpha(alphas[j],H,L)
if(abs(alphas[j] - alphaJold) < 0.00001):
print "j not moving"
# 见式 7.109
alphas[i] += labelMat[j]*labelMat[i]*(alphaJold-alphas[j])
# 见式 7.114
b1 = b - Ei -labelMat[i]*(alphas[i]-alphaIold)*dataMat[i,:]*dataMat[i,:].T\
- labelMat[j]*(alphas[j]-alphaJold)*dataMat[i,:]*dataMat[j,:].T
b2 = b - Ej - labelMat[i] * (alphas[i] - alphaIold) * dataMat[i, :] * dataMat[j, :].T \
- labelMat[j] * (alphas[j] - alphaJold) * dataMat[j, :] * dataMat[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: %d" %(iter,i,alphaPairsChanged)
if alphaPairsChanged == 0:
iter += 1
else:
iter = 0
print "iter %d" %iter
return b,alphas
SOM背后的含义
我们来看下SVM的对偶问题:
没错,我们在不断的调整alphas,其实就是在不断的调整alpha来优化问题。
就如我们在《机器学习技法》中说的,无论是SVM 还是 PLA,w都是$y_nz_n$的组合,可以看成是由原始的数据表示出来的:
而有些数据中的记录没用,我们就将它的alpha调整为0,有用记录 alpha > 0。所谓的有用的,也就是我们边界上边的点,即支持向量。
b:
[[-3.83903814]]
alphas[alphas>0],即支持向量所对应的alpha:
[[ 0.12744319 0.24145985 0.36890304]]