1. 程式人生 > >【機器學習實戰】第6章 支援向量機

【機器學習實戰】第6章 支援向量機

def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
    """smoSimple

    Args:
        dataMatIn    特徵集合
        classLabels  類別標籤
        C   鬆弛變數(常量值),允許有些資料點可以處於分隔面的錯誤一側。
            控制最大化間隔和保證大部分的函式間隔小於1.0這兩個目標的權重。
            可以通過調節該引數達到不同的結果。
        toler   容錯率(是指在某個體系中能減小一些因素或選擇對某個系統產生不穩定的概率。)
maxIter 退出前最大的迴圈次數 Returns: b 模型的常量值 alphas 拉格朗日乘子 """ dataMatrix = mat(dataMatIn) # 矩陣轉置 和 .T 一樣的功能 labelMat = mat(classLabels).transpose() m, n = shape(dataMatrix) # 初始化 b和alphas(alpha有點類似權重值。) b = 0 alphas = mat(zeros((m, 1))) #
沒有任何alpha改變的情況下遍歷資料的次數
iter = 0 while (iter < maxIter): # w = calcWs(alphas, dataMatIn, classLabels) # print("w:", w) # 記錄alpha是否已經進行優化,每次迴圈時設為0,然後再對整個集合順序遍歷 alphaPairsChanged = 0 for i in range(m): # print 'alphas=', alphas #
print 'labelMat=', labelMat
# print 'multiply(alphas, labelMat)=', multiply(alphas, labelMat) # 我們預測的類別 y[i] = w^Tx[i]+b; 其中因為 w = Σ(1~n) a[n]*lable[n]*x[n] fXi = float(multiply(alphas, labelMat).T*(dataMatrix*dataMatrix[i, :].T)) + b # 預測結果與真實結果比對,計算誤差Ei Ei = fXi - float(labelMat[i]) # 約束條件 (KKT條件是解決最優化問題的時用到的一種方法。我們這裡提到的最優化問題通常是指對於給定的某一函式,求其在指定作用域上的全域性最小值) # 0<=alphas[i]<=C,但由於0和C是邊界值,我們無法進行優化,因為需要增加一個alphas和降低一個alphas。 # 表示發生錯誤的概率:labelMat[i]*Ei 如果超出了 toler, 才需要優化。至於正負號,我們考慮絕對值就對了。 ''' # 檢驗訓練樣本(xi, yi)是否滿足KKT條件 yi*f(i) >= 1 and alpha = 0 (outside the boundary) yi*f(i) == 1 and 0<alpha< C (on the boundary) yi*f(i) <= 1 and alpha = C (between the boundary) ''' if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)): # 如果滿足優化的條件,我們就隨機選取非i的一個點,進行優化比較 j = selectJrand(i, m) # 預測j的結果 fXj = float(multiply(alphas, labelMat).T*(dataMatrix*dataMatrix[j, :].T)) + b Ej = fXj - float(labelMat[j]) alphaIold = alphas[i].copy() alphaJold = alphas[j].copy() # L和H用於將alphas[j]調整到0-C之間。如果L==H,就不做任何改變,直接執行continue語句 # labelMat[i] != labelMat[j] 表示異側,就相減,否則是同側,就相加。 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 # eta是alphas[j]的最優修改量,如果eta==0,需要退出for迴圈的當前迭代過程 # 參考《統計學習方法》李航-P125~P128<序列最小最優化演算法> 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]值 alphas[j] -= labelMat[j]*(Ei - Ej)/eta # 並使用輔助函式,以及L和H對其進行調整 alphas[j] = clipAlpha(alphas[j], H, L) # 檢查alpha[j]是否只是輕微的改變,如果是的話,就退出for迴圈。 if (abs(alphas[j] - alphaJold) < 0.00001): print("j not moving enough") continue # 然後alphas[i]和alphas[j]同樣進行改變,雖然改變的大小一樣,但是改變的方向正好相反 alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j]) # 在對alpha[i], alpha[j] 進行優化之後,給這兩個alpha值設定一個常數b。 # w= Σ[1~n] ai*yi*xi => b = yj- Σ[1~n] ai*yi(xi*xj) # 所以: b1 - b = (y1-y) - Σ[1~n] yi*(a1-a)*(xi*x1) # 為什麼減2遍? 因為是 減去Σ[1~n],正好2個變數i和j,所以減2遍 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)) # 在for迴圈外,檢查alpha值是否做了更新,如果在更新則將iter設為0後繼續執行程式 # 知道更新完畢後,iter次迴圈無變化,才推出迴圈。 if (alphaPairsChanged == 0): iter += 1 else: iter = 0 print("iteration number: %d" % iter) return b, alphas