1. 程式人生 > >機器學習實戰第六章支援向量機照葫蘆畫瓢演算法實踐

機器學習實戰第六章支援向量機照葫蘆畫瓢演算法實踐

支援向量機簡要介紹

一些概念:

1.分隔超平面:在二維中直觀來說就是將資料集分隔開來的直線,三維中則是一個平面。觸類旁通。
2.超平面:分類的決策邊界,分佈在超平面一側的所有資料都屬於某個類別,另一側屬於另一個。
3.支援向量:離分隔超平面最近的那些點。
4.分類器(資料集)的間隔:資料集中所有點到分割面的最小間隔的兩倍。
5.目標之一:選找到離分隔超平面最近的點,確保其離分隔面的距離儘可能的遠。
6.分隔超平面的數學形式:wTx+b
7.二維平面上的點到分隔超平面的距離:任取一點A,則該點到分隔平面的法線長度:|wTA+b|/w
8.新的目標:計算wb。為此,必須找到具有最小間隔的資料點,也即支援向量。一旦找到具有最小間隔的資料點,接著再對該間隔點最大化。數學形式可表示為:
argmaxw,b{mini(lable(wTx+b))1w}
通過拉格朗日運算元將上式化簡(雖然我並不知道到底是怎麼轉化的。。。)有:
maxα[i=1mα12i,j=1mlabel(i)label(j)αiαjx(i),y(j)]
進一步我們引入軟間隔項C(也稱為鬆弛變數),使得允許有些資料點可以處於分割面錯誤的一側,也即:
Cα0,i1mαilabej(i)=0而這個常數C更具體來說是用於控制“最大化間隔”和“保證大部分店的函式間隔小於1.0”折兩個目標的權重。

SMO演算法:用於訓練SVM

1.含義:Sequential Minimal Optimization(序列最小化),將大優化問題分解為多個小優化問題來求解。
2.目標:求出一系列的αb,進而計算出權重向量w來得到分隔超平面。
3.工作原理:每次迴圈中選擇兩個α進行優化處理。一旦找到一對合適的α,那麼就增大其中一個同時減小另一個。其中合適的定義是這兩個α要在間隔邊界外,且沒有進行區間和處理。
4.優化辦法:啟發式選取第二個α值,即通過最大化步長的方式來獲得第二個α值。

核函式

1.作用:將資料對映到高維空間,可以將其想象為一個介面,能把資料從某個很難處理的形式轉換成另一個較容易處理的形式,也即在高維空間中解決線性問題,等價於在低維空間中解決非線性問題。
2.核技巧: kernel trick。將內機替換成核函式的方式,單純的替換即可,無須簡化。
3.常用核函式: RBF(徑向基函式,高斯核),多項式核,線性核。

接下來的py程式碼裡面實現了簡易的純暴力smo演算法和基於啟發式的smo演算法,並測試了rbf核函式,並對手寫識別問題的分類進行了再次的考證。

# -*- coding: utf-8 -*-
"""
照葫蘆畫瓢完成於2017.5.11 19:55
演算法名稱 : 支援向量機
作者:
    zzt941006
"""
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):
    j = i
    while(j == i):
        j = int(random.uniform(0,m))
    return j
def clipAlpha(aj,H,L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj

def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
    dataMatrix = mat(dataMatIn) # 100 * 2
    labelMat = mat(classLabels).transpose() # 1 * 100
    b = 0
    m,n = shape(dataMatrix)
    alphas = mat(zeros((m,1))) # 100 * 1
    iter = 0
    while (iter < maxIter):
        alphaPairsChanged = 0#標誌位用於判定這一對alpha是否已經優化
        for i in range(m):
            fXi = float(multiply(alphas,labelMat).T * (dataMatrix * dataMatrix[i,:].T)) + b #dataMatrix[i,:]取得是矩陣中第i行的所有元素
            #multiply做的是元素間的點乘,需要兩個矩陣維度一模一樣,在此alphas,labelMat點乘後得到100 * 1 維度,轉置後得到1 * 100
            #而dataMatrix * dataMatrixp[i,:] 是整個矩陣乘以該矩陣的某一行的轉置,所以最終維度是 100 * 1
            #點乘矩陣轉置維度變為1 * 100 在跟後者進行矩陣相乘,得到一個標量(1 * 1) 維度
            #在此通過這一些列的計算獲取fXi,用來代表我們預測的類別
            Ei = fXi - float(labelMat[i])#與真實標籤的誤差計算,如果誤差很大,就可以基於此對alpha值進行優化
            if((labelMat[i] * Ei < -toler) and (alphas[i] < C)) or ((labelMat[i] * i > toler) and (alphas[i] > 0)):#調優檢驗
            #不在邊界上的點,且誤差很大時,可以對值進行進一步的優化
                j = selectJrand(i,m)
                fXj = float(multiply(alphas,labelMat).T * (dataMatrix * dataMatrix[j,:].T)) + b #隨機選取第二個alpha並計算
                Ej = fXj - float(labelMat[j])
                alphaIold = alphas[i].copy()
                alphaJold = alphas[j].copy()#要用copy方法來賦值,這樣可以讓其有新的記憶體,否則無法發現改變
                if(labelMat[i] != labelMat[j]):#邊界調整,防止alpha[j] > C 或者 < 0
                    L = max(0, alphas[j] - alphas[i])
                    H = min(C, C + alphas[j] - alphas[i])
                else:
                    L = max(0, alphas[i] + alphas[j] - C)
                    H = min(C, alphas[j] + alphas[i])
                if L == H : print "L == H"; continue #相等則不做改變,進入下一次迴圈
                eta = 2.0 * dataMatrix[i,:] * dataMatrix[j,:].T - dataMatrix[i,:] * dataMatrix[i,:].T - \
                      dataMatrix[j,:] * dataMatrix[j,:].T #alpha[j]的最優修改量
                if eta >= 0: print "eta >= 0"; continue;
                alphas[j] -= labelMat[j] * (Ei - Ej) / eta #更新alpha[j]
                alphas[j] = clipAlpha(alphas[j],H,L)
                if(abs(alphas[j] - alphaJold) < 0.00001): print "j not moving enough"; continue
                alphas[i] += labelMat[j] * labelMat[i] * (alphaJold - alphas[j]) #更新alpha[i],修改量與j相同??? 方向相反顯然
                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[j]) : 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)
        if(alphaPairsChanged == 0): iter += 1
        else : iter = 0
        print "iteration number: %d" % iter
    return b,alphas
def kernelTrans(X,A,kTup):
    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.K = mat(zeros((self.m,self.m)))
        for i in range(self.m):
            self.K[:,i] = kernelTrans(self.X,self.X[i,:],kTup) # 呼叫該函式,對矩陣K進行填充
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):
    maxK = -1
    maxDeltaE = 0
    Ej  = 0
    oS.eCache[i] = [1,Ei]
    validEcacheList = nonzero(oS.eCache[:,0].A)[0] #構建一個標誌位的非零表,返回非零E值所對應的alpha表
    if (len(validEcacheList)) > 1:
        for k in validEcacheList:
            if k == i : continue
            Ek = calcEk(oS,k)
            deltaE = abs(Ei - Ek)
            if (deltaE > maxDeltaE):
                maxK = k
                maxDeltaE = deltaE
                Ej = Ek
        return maxK,Ej
    else :
        j = selectJrand(i,oS.m)
        Ej = calcEk(oS,j)
    return j,Ej
def updateEk(oS,k):
    Ek = calcEk(oS,k)
    oS.eCache[k] = [1,Ek]
def innerL(i,oS):
    Ei = calcEk(oS,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()
        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
        eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j]
        if eta >= 0 : print "eta >= 0"; return 0
        oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej) / eta
        oS.alphas[j] = clipAlpha(oS.alphas[j],H,L)
        updateEk(oS,j)
        if(abs(oS.alphas[j] - alphaJold) < 0.00001):
            print "j not moving enouth"; return 0
        oS.alphas[i] += oS.labelMat[j] * oS.labelMat[i] * (alphaJold - oS.alphas[j])
        updateEk(oS,i)
        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
    else: return 0
def smoP(dataMatIn,classLabels,C,toler,maxIter,kTup = ('lin',0)):
    oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler,kTup)
    iter = 0
    entireSet = True
    alphaPairsChanged = 0
    while(iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
        alphaPairsChanged = 0
        if entireSet:
            for i in range(oS.m):
                alphaPairsChanged += innerL(i,oS)
                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
def calcWs(alphas,dataArr,classLabels):
    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) #大部分alpha為零向量,因此非零向量即為支援向量
    return w
def testRbf(k1 = 1.30):
    dataArr,labelArr = loadDataSet('testSetRBF.txt')
    b,alphas = smoP(dataArr,labelArr,200,0.0001,10000,('rbf',k1))
    datMat = mat(dataArr)
    labelMat =mat(labelArr).transpose()
    svInd = nonzero(alphas.A > 0)[0]
    sVs = datMat[svInd]
    labelSV = labelMat[svInd]
    print "there ar %d Support Vectors" % shape(sVs)[0]
    m,n = shape(datMat)
    errorCount = 0
    for i  in range(m):
        kernelEval = kernelTrans(sVs,datMat[i,:],('rbf',k1))
        predict = kernelEval.T * multiply(labelSV,alphas[svInd]) + b
        if sign(predict) != sign(labelArr[i]): errorCount += 1
    print "the training error rate is: %f" % (float(errorCount) / m)
    dataArr,labelArr = loadDataSet('testSetRBF2.txt')
    b,alphas = smoP(dataArr,labelArr,200,0.0001,10000,('rbf',k1))
    datMat = mat(dataArr)
    labelMat =mat(labelArr).transpose()
    svInd = nonzero(alphas.A > 0)[0]
    sVs = datMat[svInd]
    labelSV = labelMat[svInd]
    print "there ar %d Support Vectors" % shape(sVs)[0]
    m,n = shape(datMat)
    errorCount = 0
    for i  in range(m):
        kernelEval = kernelTrans(sVs,datMat[i,:],('rbf',k1))
        predict = kernelEval.T * multiply(labelSV,alphas[svInd]) + b
        if sign(predict) != sign(labelArr[i]): errorCount += 1
    print "the training error rate is: %f" % (float(errorCount) / m)
def img2vector(filename):
    returnVect = zeros((1,1024));#將32*32的二進位制影象轉化為1*1024維度的矩陣
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
       # print lineStr
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])#第一行為0-31 第二行加在後面為32-63....直到第32行的32個數字對映為 992-1023
    return returnVect
def loadImapge(dirName):
    from os import listdir
    hwLabels = []
    trainingFileList = listdir(dirName)
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('_')[0]
        classNumStr = int(fileStr.split('_')[0])
        if classNumStr == 9:hwLabels.append(-1)
        else: hwLabels.append(1)
        trainingMat[i,:] = img2vector('%s/%s' %(dirName,fileNameStr))
    return trainingMat,hwLabels
def testDigits(kTup = ('rbf',10)):
    dataArr,labelArr = loadImages('trainingDigits')
    b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, kTup)
    datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
    svInd=nonzero(alphas.A>0)[0]
    sVs=datMat[svInd] 
    labelSV = labelMat[svInd];
    print "there are %d Support Vectors" % shape(sVs)[0]
    m,n = shape(datMat)
    errorCount = 0
    for i in range(m):
        kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
        predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
        if sign(predict)!=sign(labelArr[i]): errorCount += 1
    print "the training error rate is: %f" % (float(errorCount)/m)
    dataArr,labelArr = loadImages('testDigits')
    errorCount = 0
    datMat=mat(dataArr); labelMat = mat(labelArr).transpose()
    m,n = shape(datMat)
    for i in range(m):
        kernelEval = kernelTrans(sVs,datMat[i,:],kTup)
        predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
        if sign(predict)!=sign(labelArr[i]): errorCount += 1    
    print "the test error rate is: %f" % (float(errorCount)/m) 

相關推薦

機器學習實戰支援向量葫蘆演算法實踐

支援向量機簡要介紹 一些概念: 1.分隔超平面:在二維中直觀來說就是將資料集分隔開來的直線,三維中則是一個平面。觸類旁通。 2.超平面:分類的決策邊界,分佈在超平面一側的所有資料都屬於某個類別,另一側屬於另一個。 3.支援向量:離分隔超平面最近的那些

[完]機器學習實戰 支援向量(Support Vector Machine)

[參考] 機器學習實戰(Machine Learning in Action) 本章內容 支援向量機(Support Vector Machine)是最好的現成的分類器,“現成”指的是分類器不加修改即可直接使用。基本形式的SVM分類器就可得到低錯

機器學習》 周志華學習筆記 支援向量(課後習題)python 實現

一、 1.間隔與支援向量 2.對偶問題 3.核函式 xi與xj在特徵空間的內積等於他們在原始yangben空間中通過函式k(.,.)計算的結果。 核矩陣K總是半正定的。 4.軟間隔與正則化 軟間隔允許某些samples不滿足約束  鬆弛變數 5.支援

機器學習實戰)——支援向量

第六章 支援向量機 6.1 什麼是支援向量機 支援向量機(Support Vector Machines)是目前被認為最好的現成的演算法之一 在很久以前的情人節,大俠要去救他的愛人,但魔鬼和他玩了一個遊戲。 魔鬼在桌子上似乎有規律放了兩種顏

周志華《機器學習 6 支援向量

本文是 周志華《機器學習》系列文章 之一,主要介紹支援向量機函式及核函式等概念。 第 6 章 支援向量機 6.1 間隔與支援向量 給定訓練樣本集分類學習最基本的想法就是基於訓練集 D 在樣本空間中找到一個劃分超平面,將不同類別的樣本分開。 在樣本

機器學習實戰----支援向量

支援向量機 SVM(Support Vector Machine)實際上是應用於二分類的一個分類器,其基本模型定義為特徵空間上的間隔最大的線性分類器,其學習策略便是間隔最大化,最終可轉化為一個凸二次規劃問題的求解。這裡不對整個過程進行推導,因為看了很多部落格,有幾篇大佬的部落格寫的非

機器學習實戰-支援向量

1 拉格朗日乘子法(等式約束): 目標函式:f(x)=b+wTxi+∑(αihi),s.t.hi=0 最優解條件:∂h∂xi=0 2 kkt(不等式約束): 目標函式:f(x)=b+wTxi+∑(αigi)+∑(βihi),s.t.hi=0,gi≤0

機器學習 支援向量

6.1 間隔與支援向量 在樣本空間中,劃分超平面可通過如下線性方程來描述: 6.2 對偶問題 我們希望求解式(6.6)來得到大間隔劃分超平面所對應的模型: 對式(6.6)使用拉格朗日乘子法可得到其“對偶問

機器學習實戰(五)支援向量SVM(Support Vector Machine)

目錄 0. 前言 1. 尋找最大間隔 2. 拉格朗日乘子法和KKT條件 3. 鬆弛變數 4. 帶鬆弛變數的拉格朗日乘子法和KKT條件 5. 序列最小優化SMO(Sequential Minimal Optimiz

機器學習練習()—— 支援向量

這篇文章是一系列 Andrew Ng 在 Coursera 上的機器學習課程的練習的一部分。這篇文章的原始程式碼,練習文字,資料檔案可從這裡獲得。 我們現在已經到了課程內容和本系列部落格文章的最後階段。本

機器學習實戰6 支援向量(Support Vector Machine / SVM)

第6章 支援向量機 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

機器學習實戰6支援向量(程式碼)

'''Created on Nov 4, 2010Chapter 5 source file for Machine Learing in Action@author: Peter'''from numpy import *from time import sleepdef

機器學習實戰6 支援向量

def smoSimple(dataMatIn, classLabels, C, toler, maxIter): """smoSimple Args: dataMatIn 特徵集合 classLabels 類別標籤 C 鬆弛變數

讀書筆記-《機器學習支援向量

支援向量機訓練完成後,大部分的訓練樣本都不需要保留,最終模型僅與支援向量有關 SMO的基本思路是先固定xi之外的所有引數,然後求xi上的極值。由於存在約束,因此SMO每次選擇兩個變數並固定其他引數

機器學習(周志華)》——6 支援向量

1、間隔與支援向量 (1)分類學習的最基本思想就是:基於訓練集D在樣本空間中找到一個劃分超平面,將不同類別的樣本分開。 (2)在樣本空間中,用線性方程來表示劃分超平面:ωTx + b = 0 ;其中ω = (ω1;ω2; … ; ωd)為法向量,決定超平面內的方向;b

機器學習實戰Logistic回歸

表示 article err () tail mat cycle col transpose def gradAscent(dataMatIn, classLabels): dataMatrix = mat(dataMatIn) #co

機器學習實戰7——利用AdaBoost元算法提高分類性能

nes 重要性 function mine spl 技術 可能 copy elar 將不同的分類器組合起來,這種組合結果被稱為集成方法或元算法(meta-algorithm)。 使用集成方法時會有多種形式:(1)可以是不同算法的集成(2)可以是同一種算法在不同設置下的集成

機器學習實戰8預測數值型數據:回歸

矩陣 向量 from his sca ima 用戶 targe 不可 1.簡單的線性回歸 假定輸入數據存放在矩陣X中,而回歸系數存放在向量W中,則對於給定的數據X1,預測結果將會是                  這裏的向量都默認為列向量 現在的問題是手裏有一些x

機器學習實戰11——使用 Apriori 演算法進行關聯分析

從大規模資料集中尋找物品間的隱含關係被稱作關聯分析(association analysis)或者關聯規則學習(association rule learning)。   優點:簡單 缺點:對大資料集比較慢 使用資料型別:數值型或者標稱型  

《統計學習方法》 7 支援向量”導讀

目錄 《統計學習方法》第 7 章“支援向量機”導讀 學習“支援向量機”的步驟 第 1 階段:嚴格線性可分支援向量機 第 2 階段:差一點線性可分的支援向量機 理解鬆弛變數 什麼是懲罰係數 \(C\) ?