Platt SMO算法是通过一个外循环来选择第一个alpha值的,并且其选择过程会在两种方式之间进行交替:

一种方式是在所有数据集上进行单遍扫描,另一种方式则是在非边界alpha中实现单遍扫描。  

  所谓非边界alpha指的就是那些不等于边界0或者C的alpha值。对整个数据集的扫描相当容易,而实现非边界alpha值的扫描时,首先需要建立这些alpha值的列表,然后再对这个表进行遍历。同时,该步骤会跳过那些已知的不会改变的alpha值,即。

  在选择第一个alpha值后,算法会通过一个内循环来选择第二个alpha值。在优化过程中,会通过最大化步长的方式来获得第二个alpha值。在简化版SMO算发放中,我们会在选择j之后计算错误率Ej。但在这里,我们会建立一个全局的缓存用于保存误差值,并从中选择使得步长或者说Ei-Ej最大的alpha值

完整版的SMO代码及其注释:

'''#######********************************
以下是没有核函数的版本
'''#######******************************** class optStructK:
def __init__(self,dataMatIn, classLabels, C, toler): # Initialize the structure with the parameters
self.X = dataMatIn
self.labelMat = classLabels
self.C = C
self.tol = toler
self.m = shape(dataMatIn)[0]
self.alphas = mat(zeros((self.m,1)))
self.b = 0
self.eCache = mat(zeros((self.m,2))) #first column is valid flag def calcEkK(oS, k): #计算误差
fXk = float(multiply(oS.alphas,oS.labelMat).T*(oS.X*oS.X[k,:].T)) + oS.b
Ek = fXk - float(oS.labelMat[k])
return Ek def selectJK(i, oS, Ei): #用于选择第2个循环(内循环)的alpha值,内循环中的启发式方法
maxK = -1; maxDeltaE = 0; Ej = 0
oS.eCache[i] = [1,Ei] #set valid #choose the alpha that gives the maximum delta E
validEcacheList = nonzero(oS.eCache[:,0].A)[0]
if (len(validEcacheList)) > 1:
for k in validEcacheList: #loop through valid Ecache values and find the one that maximizes delta E
if k == i: continue #跳过本身
Ek = calcEk(oS, k)
deltaE = abs(Ei - Ek)
if (deltaE > maxDeltaE): #选取具有最大步长的j
maxK = k; maxDeltaE = deltaE; Ej = Ek
return maxK, Ej
else: #in this case (first time around) we don't have any valid eCache values
j = selectJrand(i, oS.m)
Ej = calcEk(oS, j)
return j, Ej def updateEkK(oS, k): #alpha改变后,更新缓存
Ek = calcEk(oS, k)
oS.eCache[k] = [1,Ek] #内部循环的代码
def innerLK(i, oS):
Ei = calcEk(oS, i)
#判断每一个alpha是否被优化过,如果误差很大,就对该alpha值进行优化,toler是容错率
if ((oS.labelMat[i]*Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i]*Ei > oS.tol) and (oS.alphas[i] > 0)):
j,Ej = selectJ(i, oS, Ei) #使用启发式方法选取第2个alpha,选取使得误差最大的alpha
alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy();
#保证alpha在0与C之间
if (oS.labelMat[i] != oS.labelMat[j]): #当y1和y2异号,计算alpha的取值范围
L = max(0, oS.alphas[j] - oS.alphas[i])
H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])
else: #当y1和y2同号,计算alpha的取值范围
L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)
H = min(oS.C, oS.alphas[j] + oS.alphas[i])
if L==H: print "L==H"; return 0
#eta是alpha[j]的最优修改量,eta=K11+K22-2*K12,也是f(x)的二阶导数,K表示内积
eta = 2.0 * oS.X[i,:]*oS.X[j,:].T - oS.X[i,:]*oS.X[i,:].T - oS.X[j,:]*oS.X[j,:].T
#如果二阶导数-eta <= 0,说明一阶导数没有最小值,就不做任何改变,本次循环结束直接运行下一次for循环
if eta >= 0: print "eta>=0"; return 0
oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/eta #利用公式更新alpha[j],alpha2new=alpha2-yj(Ei-Ej)/eta
oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) #判断alpha的范围是否在0和C之间
updateEk(oS, j) #在alpha改变的时候更新Ecache
#如果alphas[j]没有调整,就忽略下面语句,本次循环结束直接运行下一次for循环
if (abs(oS.alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; return 0
oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])#update i by the same amount as j
updateEk(oS, i) #在alpha改变的时候更新Ecache
#已经计算出了alpha,接下来根据模型的公式计算b
b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[i,:].T - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[i,:]*oS.X[j,:].T
b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[j,:].T - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[j,:]*oS.X[j,:].T
#根据公式确定偏移量b,理论上可选取任意支持向量来求解,但是现实任务中通常使用所有支持向量求解的平均值,这样更加鲁棒
if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1
elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2
else: oS.b = (b1 + b2)/2.0
return 1 #如果有任意一对alpha发生改变,返回1
else: return 0 #无核函数 Platt SMO 的外循环
def smoPK(dataMatIn, classLabels, C, toler, maxIter): #full Platt SMO
oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler)
iter = 0
entireSet = True; alphaPairsChanged = 0
#有alpha改变同时遍历次数小于最大次数,或者需要遍历整个集合
while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
alphaPairsChanged = 0
#首先进行完整遍历,过程和简化版的SMO一样
if entireSet: #go over all
for i in range(oS.m):
alphaPairsChanged += innerL(i,oS) #i是第1个alpha的下标
print "fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)
iter += 1
#非边界遍历,挑选其中alpha值在0和C之间非边界alpha进行优化
else:#go over non-bound (railed) alphas
nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] #然后挑选其中值在0和C之间的非边界alpha进行遍历
for i in nonBoundIs:
alphaPairsChanged += innerL(i,oS)
print "non-bound, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)
iter += 1
#如果这次是完整遍历的话,下次不用进行完整遍历
if entireSet: entireSet = False #终止完整循环
elif (alphaPairsChanged == 0): entireSet = True #如果alpha的改变数量为0的话,再次遍历所有的集合一次
print "iteration number: %d" % iter
return oS.b,oS.alphas

机器学习——支持向量机(SVM)之Platt SMO算法的更多相关文章

  1. 机器学习——支持向量机(SVM)之拉格朗日乘子法,KKT条件以及简化版SMO算法分析

    SVM有很多实现,现在只关注其中最流行的一种实现,即序列最小优化(Sequential Minimal Optimization,SMO)算法,然后介绍如何使用一种核函数(kernel)的方式将SVM ...

  2. 机器学习——支持向量机SVM

    前言 学习本章节前需要先学习: <机器学习--最优化问题:拉格朗日乘子法.KKT条件以及对偶问题> <机器学习--感知机> 1 摘要: 支持向量机(SVM)是一种二类分类模型, ...

  3. 统计学习方法c++实现之六 支持向量机(SVM)及SMO算法

    前言 支持向量机(SVM)是一种很重要的机器学习分类算法,本身是一种线性分类算法,但是由于加入了核技巧,使得SVM也可以进行非线性数据的分类:SVM本来是一种二分类分类器,但是可以扩展到多分类,本篇不 ...

  4. [笔记]关于支持向量机(SVM)中 SMO算法的学习(一)理论总结

    1. 前言 最近又重新复习了一遍支持向量机(SVM).其实个人感觉SVM整体可以分成三个部分: 1. SVM理论本身:包括最大间隔超平面(Maximum Margin Classifier),拉格朗日 ...

  5. 支持向量机(五)SMO算法

    11 SMO优化算法(Sequential minimal optimization) SMO算法由Microsoft Research的John C. Platt在1998年提出,并成为最快的二次规 ...

  6. <转>SVM实现之SMO算法

    转自http://blog.csdn.net/zouxy09/article/details/17292011 终于到SVM的实现部分了.那么神奇和有效的东西还得回归到实现才可以展示其强大的功力.SV ...

  7. 理解支持向量机(三)SMO算法

    在支持向量机模型的求解中,我们用到了SMO算法来求解向量α. 那么什么是SMO算法?在讲SMO算法之前.我们须要先了解下面坐标上升法. 1.坐标上升法 如果有优化问题: W是α向量的函数.利用坐标上升 ...

  8. 机器学习支持向量机SVM笔记

    SVM简述: SVM是一个线性二类分类器,当然通过选取特定的核函数也可也建立一个非线性支持向量机.SVM也可以做一些回归任务,但是它预测的时效性不是太长,他通过训练只能预测比较近的数据变化,至于再往后 ...

  9. 机器学习——支持向量机(SVM)之核函数(kernel)

    对于线性不可分的数据集,可以利用核函数(kernel)将数据转换成易于分类器理解的形式. 如下图,如果在x轴和y轴构成的坐标系中插入直线进行分类的话, 不能得到理想的结果,或许我们可以对圆中的数据进行 ...

随机推荐

  1. android AES 加密

    import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import jav ...

  2. 什么是RAID?RAID有什么用?RAID原理

    什么是RAID 硬盘是个很脆弱的东西,它经常会坏掉.所以,为了保证服务器可靠耐用,硬盘必须时时刻刻保持可用.所以有了RAID这个东西.它的目的是将好几个硬盘合并在一起,就算硬盘坏了一个,剩下还有好几个 ...

  3. Python Web.py与AJAX交互

    AJAX的使用,http://www.w3school.com.cn/ajax/index.asp  W3C的教程已经讲的很细致,实例也具有ASP与PHP,大致花不到半小时就可以掌握. 遇见了太多问题 ...

  4. WebServices:WSDL的结构分析

    WSDL(Web Services Description Language,Web服务描述语言)是为描述Web Services发布的XML格式.W3C组织没有批准1.1版的WSDL,但是2.0版本 ...

  5. Windows批处理:自动开关程序

    公司有台14年组装的PC,时常无故重启,所以编写了个然并卵的批处理来测试稳定性. 打开程序.bat @echo off title Start Software color 2F : "C: ...

  6. Linux学习笔记(17) Shell编程之基础

    1. 正则表达式 (1) 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配.grep.awk.sed等命令可以支持正则表达式:通配符用来匹配符合条件的文件名,通配符是完全匹配.ls.find ...

  7. Android Studio NDK 开发 问题记录

    Android NDK 开发 问题解决 编译:找不到gles3库 使用旧的编译方式,写Android.mk 进行编译.报错如下 gles3/gl3.h no such file or director ...

  8. [LeetCode] Bulb Switcher 灯泡开关

    There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every ...

  9. Google C++命名规范

    时间:2014.03.02 地点:基地 -------------------------------------------------------------------------------- ...

  10. IO流-----写到输出流

    输出流:---链接:http://blog.csdn.net/du_minchao/article/details/49045421 /** * 方法名:writeStream * 方法描述:写到输出 ...