机器学习:SVM代码实现,朴素实现基础上的优化
生活随笔
收集整理的這篇文章主要介紹了
机器学习:SVM代码实现,朴素实现基础上的优化
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
SVM代碼實現(xiàn),樸素實現(xiàn)基礎上的優(yōu)化:
因為二次凸優(yōu)化已經把解析結果明白表現(xiàn)出來了,所以優(yōu)化只能體現(xiàn)在兩個變量的選擇上,或者說是兩個樣本的選擇上:
1、第一個變量的選擇:這次實現(xiàn)也并不是選擇最不滿足KKT條件的樣本點,而是優(yōu)先使用邊界上的樣本點也就是0<alpha<C的樣本點,假如邊界上的樣本點均滿足KKT條件,就遍歷全體樣本去找不滿足的樣本點
2、第二個變量的選擇:選擇和第一個樣本誤差相差最大的樣本點,也就是|e1-e2|最大的點。
3、根據樣本誤差找第二個變量做了一定的優(yōu)化:只需要已經更新過樣本點誤差的樣本。
計算樣本誤差(預測值-實際值)、更新樣本誤差
def calcEkK(oS, k):"""計算第k個樣本點的誤差:param oS::param k::return:"""# 計算第k個樣本點的誤差值fXk = float(np.multiply(oS.alphas,oS.labelMat).T*(oS.X*oS.X[k,:].T)) + oS.b# 計算第k個樣本的誤差Ek = fXk - float(oS.labelMat[k])return Ekdef updateEkK(oS, k):# 更新誤差,根據當前oS里面alphas和b,來更新誤差,并標志誤差為新的Ek = calcEkK(oS, k)oS.eCache[k] = [1,Ek]啟發(fā)式選擇第二個變量:
def selectJK(i, oS, Ei):"""選擇第2個變量的過程,即內層循環(huán)中的啟發(fā)規(guī)則。選擇標準是使alpha_2有足夠大的變化。:param i:第一個變量:param oS:中間結果:param Ei:第i個點的誤差:return:"""# 用于存放最大相距誤差的樣本點,最大相距誤差,該樣本點的誤差maxK = -1; maxDeltaE = 0; Ej = 0oS.eCache[i] = [1,Ei] #設為有效# 找尋產生最大誤差變化的alphavalidEcacheList = np.nonzero(oS.eCache[:,0].A)[0] #有效位為1的誤差列表if (len(validEcacheList)) > 1:for k in validEcacheList: #遍歷列表找出最大誤差變化if k == i: continue #第二個alpha不應該等于第一個# 遍歷計算每一個樣本的誤差Ek = calcEkK(oS, k)deltaE = abs(Ei - Ek)if (deltaE > maxDeltaE):maxK = k; maxDeltaE = deltaE; Ej = Ekreturn maxK, Ejelse: #找不到,只好隨機選擇一個# 第一次假如所有的樣本都沒有更新過,就隨機選擇,假如更新過,就使用上述策略j = selectJrand(i, oS.m)Ej = calcEkK(oS, j)return j, Ejdef selectJrand(i,m):"""隨機從0到m挑選一個不等于i的數(shù):param i::param m::return:"""j=i #排除iwhile (j==i):j = int(np.random.uniform(0,m))return j選取了第一個變量之后的核心處理:
# 內層循環(huán),選擇了第一個樣本點之后,選擇第二個樣本點進行解析求解 def innerLK(i, oS):# 計算第一個樣本點的誤差Ei = calcEkK(oS, i)#如果誤差太大,且alpha滿足約束,則嘗試優(yōu)化它# 第一個樣本點滿足kkt條件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)):# 根據第一個樣本點找第二個偏離最大的樣本點,第一次eCache沒有有效的樣本誤差,隨機選擇j,Ej = selectJK(i, oS, Ei) #不再是 selectJrand 那種簡化的選擇方法alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy() # 教材中的α_1^old和α_2^old# 計算邊界if (oS.labelMat[i] != oS.labelMat[j]): # 兩者所在的對角線段端點的界L = max(0, oS.alphas[j] - oS.alphas[i])H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])else: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# 計算-dKeta = 2.0 * oS.X[i,:]*oS.X[j,:].T - oS.X[i,:]*oS.X[i,:].T - oS.X[j,:]*oS.X[j,:].Tif eta >= 0: print("eta>=0"); return 0# 計算a_2oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/etaoS.alphas[j] = clipAlpha(oS.alphas[j],H,L)# 更新第二個樣本點的誤差,并設置誤差有效updateEkK(oS, j) # 更新誤差緩存# 假如第二個樣本點改進不大,換第一個樣本點if (abs(oS.alphas[j] - alphaJold) < 0.00001): print ("j not moving enough"); return 0# 計算a_1oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j]) #更新α_1# 更新a_1的誤差updateEkK(oS, i) # # 更新誤差緩存# 計算bb1 = 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,:].Tb2 = 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,:].Tif (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2else: oS.b = (b1 + b2)/2.0return 1# 第一個樣本點不滿足kkt條件,直接下一個樣本點else: return 0第一個變量選擇及主程序:
def smoPK(dataMatIn, classLabels, C, toler, maxIter):"""完整版的Platt SMO算法:param dataMatIn::param classLabels::param C::param toler::param maxIter::return:"""oS = optStructK(np.mat(dataMatIn),np.mat(classLabels).transpose(),C,toler)iter = 0entireSet = True; alphaPairsChanged = 0# 這里的實現(xiàn)并沒有在訓練樣本中選取違反KKT條件最嚴重的樣本點,# 而是優(yōu)先順序遍歷間隔邊界上的支持向量點,若無法優(yōu)化模型則遍歷整個數(shù)據集。while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):alphaPairsChanged = 0# 第一次遍歷整個數(shù)據集if entireSet: #遍歷所有值# 遍歷每一個樣本點,alphaPairsChanged標記了樣本點是否做了操作for i in range(oS.m): alphaPairsChanged += innerLK(i,oS)print ("fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))iter += 1else: #遍歷間隔邊界上的支持向量點# 遍歷 0< alpha < C上的樣本點,也就是支持向量nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]for i in nonBoundIs:alphaPairsChanged += innerLK(i,oS)print ("non-bound, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))iter += 1if entireSet: entireSet = False #翻轉entireSet# 假如在支持向量上遍歷,沒有樣本點可以優(yōu)化,那么就在全集上遍歷elif (alphaPairsChanged == 0): entireSet = True print ("iteration number: %d" % iter)return oS.b,oS.alphas總結
以上是生活随笔為你收集整理的机器学习:SVM代码实现,朴素实现基础上的优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习:SVM的最朴素代码实现,第一个
- 下一篇: 机器学习:SVM代码实现,第一个变量选择