1. 程式人生 > >機器學習實戰:支撐向量機

機器學習實戰:支撐向量機

一、工作原理

  1. 支撐向量機(Support Vector Machine)的核心問題為:針對不同類別進行分類時,如何尋找得到最大的分類間距
  2. 通常採用超平面來對不同類別的資料進行分割,超平面方程為: wT X+b =0
  3. 支撐向量機的實現方法為:求取超平面方程,使得資料點中距離超平面距離最近的點距離最大,即可表述為:max{min label*wT X+b/||w|| },其中任意點到超平面的計算距離公式為:wT X+b/||w||,具體可參考: 空間中任一點到超平面的距離公式的推導過程

二、實現程式碼

  • 簡化版SMO演算法

輸入資料格式:

3.542485	1.977398	-1
3.018896	2.556416	-1
7.551510	-1.580030	1
2.114999	-0.004466	-1
8.127113	1.274372	1

解析資料:

def loadDataSet(fileName):
    """
    對檔案進行逐行解析,從而得到第行的類標籤和整個特徵矩陣
    Args:
        fileName 檔名
    Returns:
        dataMat  特徵矩陣
        labelMat 類標籤
    """
    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

簡化版SMO演算法的完整程式碼:

#!/usr/bin/python
# -*- coding:utf-8 -*-


from
numpy import * import matplotlib.pyplot as plt def loadDataSet(fileName): """ 對檔案進行逐行解析,從而得到第行的類標籤和整個特徵矩陣 Args: fileName 檔名 Returns: dataMat 特徵矩陣 labelMat 類標籤 """ 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): """ 隨機選擇一個整數 Args: i 第一個alpha的下標 m 所有alpha的數目 Returns: j 返回一個不為i的隨機數,在0~m之間的整數值 """ j = i while j == i: j = int(random.uniform(0, m)) return j def clipAlpha(aj, H, L): """clipAlpha(調整aj的值,使aj處於 L<=aj<=H) Args: aj 目標值 H 最大值 L 最小值 Returns: aj 目標值 """ if aj > H: aj = H if L > aj: aj = L return aj 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 = 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 def calcWs(alphas, dataArr, classLabels): """ 基於alpha計算w值 Args: alphas 拉格朗日乘子 dataArr feature資料集 classLabels 目標變數資料集 Returns: wc 迴歸係數 """ X = mat(dataArr) labelMat = mat(classLabels).transpose() m, n = shape(X) w = zeros((n, 1)) for i in range(m): w += multiply(alphas[i] * labelMat[i], X[i, :].T) return w def plotfig_SVM(xMat, yMat, ws, b, alphas): """ 參考地址: http://blog.csdn.net/maoersong/article/details/24315633 http://www.cnblogs.com/JustForCS/p/5283489.html http://blog.csdn.net/kkxgx/article/details/6951959 """ xMat = mat(xMat) yMat = mat(yMat) # b原來是矩陣,先轉為陣列型別後其陣列大小為(1,1),所以後面加[0],變為(1,) b = array(b)[0] fig = plt.figure() ax = fig.add_subplot(111) # 注意flatten的用法 ax.scatter(xMat[:, 0].flatten().A[0], xMat[:, 1].flatten().A[0]) # x最大值,最小值根據原資料集dataArr[:, 0]的大小而定 x = arange(-1.0, 10.0, 0.1) # 根據x.w + b = 0 得到,其式子展開為w0.x1 + w1.x2 + b = 0, x2就是y值 y = (-b-ws[0, 0]*x)/ws[1, 0] ax.plot(x, y) for i in range(shape(yMat[0, :])[1]): if yMat[0, i] > 0: ax.plot(xMat[i, 0], xMat[i, 1], 'cx') else: ax.plot(xMat[i, 0], xMat[i, 1], 'kp') # 找到支援向量,並在圖中標紅 for i in range(100): if alphas[i] > 0.0: ax.plot(xMat[i, 0], xMat[i, 1], 'ro') plt.show() if __name__ == "__main__": # 獲取特徵和目標變數 dataArr, labelArr = loadDataSet('testSet.txt') # print(labelArr) # b是常量值, alphas是拉格朗日乘子 b, alphas = smoSimple(dataArr, labelArr, 0.6, 0.001, 40) print('/n/n/n') print('b=', b) print('alphas[alphas>0]=', alphas[alphas > 0]) print('shape(alphas[alphas > 0])=', shape(alphas[alphas > 0])) for i in range(100): if alphas[i] > 0: print(dataArr[i], labelArr[i]) # 畫圖 ws = calcWs(alphas, dataArr, labelArr) plotfig_SVM(dataArr, labelArr, ws, b, alphas)
  • 手寫數字識別完整程式碼
import matplotlib.pyplot as plt
from numpy import *
from sklearn import svm

#功能:影象矩陣轉化為m*1矩陣
#輸入:檔名
#輸出:m*1矩陣
def img2vector(filename):
    returnVect = zeros((1, 1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0, 32 * i + j] = int (lineStr[j])
    return returnVect
 
#功能:將影象內容匯入矩陣
#輸入:一級子目錄
#輸出:影象矩陣,影象標籤向量
def loadImages(dirName):
    from os import listdir
    hwLabels = []
    trainingFileList = listdir(dirName)#dirName資料夾下的檔名列表
    m = len(trainingFileList)#dirName資料夾下的檔案數目
    trainingMat = zeros((m, 1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]#檔名
        fileStr = fileNameStr.split('.')[0]#去掉.txt的檔名
        classNumStr = int(fileStr.split('_')[0])#要識別的數字
        if classNumStr == 9:#數字9
            hwLabels.append(-1)
        else:#數字1
            hwLabels.append(1)
        trainingMat[i, :] = img2vector('%s/%s' % (dirName, fileNameStr))
    return trainingMat, hwLabels

def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin',0)):
    """
    完整SMO演算法外迴圈,與smoSimple有些類似,但這裡的迴圈退出條件更多一些
    Args:
        dataMatIn    資料集
        classLabels  類別標籤
        C   鬆弛變數(常量值),允許有些資料點可以處於分隔面的錯誤一側。
            控制最大化間隔和保證大部分的函式間隔小於1.0這兩個目標的權重。
            可以通過調節該引數達到不同的結果。
        toler   容錯率
        maxIter 退出前最大的迴圈次數
    Returns:
        b       模型的常量值
        alphas  拉格朗日乘子
    """

    # 建立一個 optStruct 物件
    oS = optStruct(mat(dataMatIn), mat(classLabels).transpose(), C, toler)
    iter = 0
    entireSet = True
    alphaPairsChanged = 0

    # 迴圈遍歷:迴圈maxIter次 並且 (alphaPairsChanged存在可以改變 or 所有行遍歷一遍)
    # 迴圈迭代結束 或者 迴圈遍歷所有alpha後,alphaPairs還是沒變化
    while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
        alphaPairsChanged = 0
        # ----------- 第一種寫法 start -------------------------
        #  當entireSet=true or 非邊界alpha對沒有了;就開始尋找 alpha對,然後決定是否要進行else。
        if entireSet:
            # 在資料集上遍歷所有可能的alpha
            for i in range(oS.m):
                # 是否存在alpha對,存在就+1
                alphaPairsChanged += innerL(i, oS)
                print("fullSet, iter: %d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged))
            iter += 1
        # 對已存在 alpha對,選出非邊界的alpha值,進行優化。
        else:
            # 遍歷所有的非邊界alpha值,也就是不在邊界0或C上的值。
            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
        # ----------- 第一種寫法 end -------------------------

        # ----------- 第二種方法 start -------------------------
        # if entireSet:																				#遍歷整個資料集
    	# 	alphaPairsChanged += sum(innerL(i, oS) for i in range(oS.m))
		# else: 																						#遍歷非邊界值
		# 	nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]						#遍歷不在邊界0和C的alpha
		# 	alphaPairsChanged += sum(innerL(i, oS) for i in nonBoundIs)
		# iter += 1
        # ----------- 第二種方法 end -------------------------
        # 如果找到alpha對,就優化非邊界alpha值,否則,就重新進行尋找,如果尋找一遍 遍歷所有的行還是沒找到,就退出迴圈。
        if entireSet:
            entireSet = False  # toggle entire set loop
        elif alphaPairsChanged == 0:
            entireSet = True
        print("iteration number: %d" % iter)
    return oS.b, oS.alphas

class optStruct:
    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
            
           

相關推薦

機器學習實戰支撐向量

一、工作原理 支撐向量機(Support Vector Machine)的核心問題為:針對不同類別進行分類時,如何尋找得到最大的分類間距 通常採用超平面來對不同類別的資料進行分割,超平面方程為: wT X+b =0 支撐向量機的實現方法為:求取超平面方程

機器學習實戰——SVM支援向量 實現記錄

問題:TypeError: data type not understood alphas = mat(zeros(m,1)) 原因是zeros(())格式不對,更改後: alphas = mat(zeros((m,1))) 問題:關於IDLE中換行,回車前面出現很多空格的情況

機器學習實戰】支援向量----分類庫和簡單訓練mnist

前面已經對mnist資料集進行了讀取,現在我們可以直接使用sklearn.svm模組中的演算法庫對mnist資料集進行訓練。 【svm模組】 演算法庫: sklearn.svm模組中提供了這些庫: 大概分成這幾類(除了svm_l1_min_c

機器學習實戰》支援向量的數學理解及程式實現

一、 引言最近在機器學習課上,學到的《機器學習實戰》第六章的支援向量機,這部分內容非常多,不僅要會程式設計和測試,還要理解它的數學基礎,這裡對這部分的學習進行一些總結。二、 SVM的數學原理從一個簡單的二分問題開始說吧:我們要把這兩類不同的點區分開,那麼在這個二維平面上就是找

機器學習實戰-55:支援向量分類演算法(Support Vector Machine)

支援向量機分類演算法 支援向量機(Support Vector Machine)分類演算法屬於監督學習演算法。常用分類演算法包括:邏輯迴歸(Logistic Regression, LR)、K最近鄰(k-Nearest Neighbor, KNN)、樸素貝葉斯

PYTHON機器學習實戰——SVM支援向量

支援向量機不是很好被理解,主要是因為裡面涉及到了許多數學知識,需要慢慢地理解。理論知識參考:http://www.cnblogs.com/steven-yang/p/5658362.html 一下附上原始碼:#-*- coding:utf-8 -*- #!/usr/bin/

機器學習實戰學習筆記支援向量

該節的內容是支援向量機(SVM, support vectormachine)。 一.概念描述 支援向量機,就是通過最大化支援向量到分類超平面之間的分類間隔。分類超平面就是我們想要得到的決策曲面;支援向量就是離分類超平面最近的點,而間隔即為支援向量到分類

機器學習之支持向量(三)核函數和KKT條件的理解

麻煩 ron 現在 調整 所有 核函數 多項式 err ges 註:關於支持向量機系列文章是借鑒大神的神作,加以自己的理解寫成的;若對原作者有損請告知,我會及時處理。轉載請標明來源。 序: 我在支持向量機系列中主要講支持向量機的公式推導,第一部分講到推出拉格朗日對偶函數的對

機器學習之支持向量(一)支持向量的公式推導

根據 監督式 art 通用 利用 哪些 這就是 在線 方法 註:關於支持向量機系列文章是借鑒大神的神作,加以自己的理解寫成的;若對原作者有損請告知,我會及時處理。轉載請標明來源。 序: 我在支持向量機系列中主要講支持向量機的公式推導,第一部分講到推出拉格朗日對偶函數的對偶因

SVM學習筆記-線性支撐向量

操作 mar 向量 直觀 法向量 衡量 最優 目標 vector   對於PLA算法來說,最終得到哪一條線是不一定的,取決於算法scan數據的過程。    從VC bound的角度來說,上述三條線的復雜度是一樣的    Eout(w)≤Ein0+Ω(H)

機器學習】支持向量(SVM)

cto nom 機器 ins 神經網絡 學習 參數 mage 36-6 感謝中國人民大學胡鶴老師,課程深入淺出,非常好 關於SVM 可以做線性分類、非線性分類、線性回歸等,相比邏輯回歸、線性回歸、決策樹等模型(非神經網絡)功效最好 傳統線性分類:選出兩堆數據的質心,並

關於機器學習中支持向量相關問題

機器學習 支持向量機 svm 線性感知機 核方法前言 在機器學習中,分類問題占了很大一部分,而對於分類問題的處理有很多方法,比如決策樹、隨機森林、樸素貝葉斯、前饋神經網絡等等;而最為常見的分類需求一般是二分類問題,即將樣本分為兩個集合,然後通過學習某些參數,對新的輸入進行識別並劃分到正確的類別中。 在

機器學習(支持向量

open struct was file 擴展 基本 pos del nbsp 有人說,SVM是現成最好的分類器,指的是該分類器不加修改既可直接使用。同時意味著在數據上應用基本形式的SVM分類器可以得到低的錯誤率的結果。 SVM有很多實現,但是最流行的是實現序列最小優化SM

機器學習之支持向量(四)

應用 問題 計算過程 非線性 簡單 常熟 一段 約束 有關 引言:   SVM是一種常見的分類器,在很長一段時間起到了統治地位。而目前來講SVM依然是一種非常好用的分類器,在處理少量數據的時候有非常出色的表現。SVM是一個非常常見的分類器,在真正了解他的原理之前我們多多少少

分享《機器學習實戰基於Scikit-Learn和TensorFlow》高清中英文PDF+原始碼

下載:https://pan.baidu.com/s/1kNN4tDt58ckFoD_OWH5sGw 更多資料分享:http://blog.51cto.com/3215120 《機器學習實戰:基於Scikit-Learn和TensorFlow》高清中文版PDF+高清英文版PDF+原始碼 高清中文版PDF

分享《機器學習實戰基於Scikit-Learn和TensorFlow》高清中英文PDF+源代碼

ESS alt mark 構建 image 機器學習實戰 dff com 化學 下載:https://pan.baidu.com/s/1kNN4tDt58ckFoD_OWH5sGw 更多資料分享:http://blog.51cto.com/3215120 《機器學習實戰:基

機器學習實戰智慧製造質量預測

一、資料清洗 注意:pandas函式使用後一般是不對原表起作用的,要重新賦值 對dataframe來說,bool運算any()、all(),預設沿axis=0反向,即沿著列 初步清洗後從8209列到3074列 1.初步清洗 去除重複列,注意可能會跨幾十列重合的,需要遍歷同一個工序

機器學習 --- 軟間隔支援向量

一、軟間隔支援向量機直觀理解 之前所介紹的支援向量機形式都是要求所有的樣本都要能被正確地劃分,這又被稱作"硬間隔支援向量機",當資料是帶有噪聲的,就可能會產生一些脫離群體的點。在實際情況中,採用硬間隔的方式難以確定合適的核函式使得訓練樣本在特徵空間中線性可分,即使能確定某個核函式能進行很好的劃分

分享《機器學習實戰基於Scikit-Learn和TensorFlow》+PDF+Aurelien

ext https oss 模型 img kit 復制 mage 更多 下載:https://pan.baidu.com/s/127EzxtY9zdBU2vOfxEgIjQ 更多資料分享:http://blog.51cto.com/14087171 《機器學習實戰:基於Sc

機器學習實戰用nodejs實現人臉識別

機器學習實戰:用nodejs實現人臉識別   在本文中,我將向你展示如何使用face-recognition.js執行可靠的人臉檢測和識別 。 我曾經試圖找一個能夠精確識別人臉的Node.js庫,但是