SVM实现之SMO算法
2017-09-14 17:42
429 查看
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 def selectJrand(i,m): #随机选择 0-m 中不等于 i 的一个数 j=i while (j==i): j = int(random.uniform(0,m)) return j def clipAlpha(aj,H,L): #裁剪 aj if aj > H: aj = H if L > aj: aj = L return aj def kernelTrans(X, A, kTup): ##计算 K_ij 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)) else: raise NameError('Houston We Have a Problem -- \ That Kernel is not recognized') return K class optStruct: def __init__(self,dataMatIn, classLabels, C, toler, kTup): # 用给定的参数初始化对象 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))) # self.m*2 的矩阵,第一列是eCache是否有效的标志位,第二列是实际的E值 self.K = mat(zeros((self.m,self.m))) for i in range(self.m): #计算 K_ij self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup) def calcEk(oS, k): #计算误差 fXk = float(multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b) Ek = fXk - float(oS.labelMat[k]) return Ek def selectJ(i, oS, Ei): #选择第二个变量,并计算第二个变量对应的误差E_j maxK = -1; maxDeltaE = 0; Ej = 0 oS.eCache[i] = [1,Ei] #将第i行的误差标志位设置为有效,并载入误差 E_i validEcacheList = nonzero(oS.eCache[:,0].A)[0] // 返回一个列表,列表中的元素表示oS.eCache中标志位为1的误差的行数 if (len(validEcacheList)) > 1: for k in validEcacheList: #遍历有效的E_k,找出使 |E_i - E_j|最大的 alpha_j if k == i: continue #对于本身,不用计算,继续下一次循环 Ek = calcEk(oS, k) deltaE = abs(Ei - Ek) if (deltaE > maxDeltaE): #选择使 |E_i - E_j|最大的 alpha_j maxK = k; maxDeltaE = deltaE; Ej = Ek return maxK, Ej else: #当没有可选数时,随机选择j j = selectJrand(i, oS.m) Ej = calcEk(oS, j) return j, Ej def updateEk(oS, k):#某个alpha分量已经改变后,更新对应的误差 Ek = calcEk(oS, k) oS.eCache[k] = [1,Ek] def innerL(i, oS): Ei = calcEk(oS, i) #计算误差 Ei = f(x_i)-y_i #判断alpha_i是否违背KKT条件,如果违反,alpha_i就可作为第一个变量 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) # 选择第二个变量 alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy(); #备份 alpha_i,alpha_j if (oS.labelMat[i] != oS.labelMat[j]): #如果 y_i != y_j ,计算 L,H L = max(0, oS.alphas[j] - oS.alphas[i]) H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) else: #如果 y_i == y_j ,计算 L,H 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 = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[ 4000 j,j] #计算 eta if eta >= 0: print "eta>=0"; return 0 #如果 eta >= 0,结束本次迭代,返回到上一个函数,重新选择第一个变量 oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/eta #更新第二个变量,得到alpha_j_new_unc oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) # 裁剪alpha_j_new_unc,得到alpha_j_new updateEk(oS, j) #更新 oS.eCache[j] 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]) # 更新第一个变量,得到alpha_i_new updateEk(oS, i) # 更新 oS.eCache[i] #计算并更新b b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,i] - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[i,j] b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,j]- oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[j,j] 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 #完成一次更新,返回更新标志 1 else: return 0 def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)): # Platt SMO算法 oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler, kTup) #实例化一个optStruct对象 oS iter = 0 entireSet = True; alphaPairsChanged = 0 #循环条件:(迭代次数低于设定次数)and(在对整个数据集一轮迭代中alpha累计修改量大于0),or(还没对数据集进行完全遍历) while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): alphaPairsChanged = 0 if entireSet: #go over all for i in range(oS.m): #遍历数据集 alphaPairsChanged += innerL(i,oS) #更新alpha_i,alpha_j print "fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged) iter += 1 else:#遍历非边界数据集 nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] 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 #toggle entire set loop elif (alphaPairsChanged == 0): entireSet = True print "iteration number: %d" % iter return oS.b,oS.alphas
相关文章推荐
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
- 支持向量机(SVM)的SMO算法实现(Python)
- 经典SVM之SMO算法实现
- Andrew Ng机器学习笔记+Weka相关算法实现(六)SMO/LibSVM/SVM参数
- 基于OpenCV的 SVM算法实现数字识别(三)---SMO求解
- 支持向量机(SVM)算法的matlab的实现
- 支持向量机(Support Vector Machine)-----SVM之SMO算法(转)
- [机器学习]机器学习笔记整理08- SVM算法原理及实现
- SVM算法实现(一)
- 对SVM的推导和编码实践(二)SMO算法的推导
- 支持向量机(SVM)算法的matlab的实现
- 支持向量机(SVM)算法的matlab的实现
- SVM算法下如何使用SMO算法优化拉格朗日乘子
- 手把手教你实现SVM算法(二)
- Andrew Ng机器学习笔记+Weka相关算法实现(四)SVM和原始对偶问题
- 基于OpenCV的 SVM算法实现数字识别(四)---代码实现
- 手把手教你实现SVM算法(一)
- matlab体验svm算法【非实现】
- 机器学习实战【7】(SMO算法实现)
- 支持向量机 SVM 算法推导优缺点 代码实现 in Python