機器學習實戰第六章支援向量機照葫蘆畫瓢演算法實踐
支援向量機簡要介紹
一些概念:
1.分隔超平面:在二維中直觀來說就是將資料集分隔開來的直線,三維中則是一個平面。觸類旁通。
2.超平面:分類的決策邊界,分佈在超平面一側的所有資料都屬於某個類別,另一側屬於另一個。
3.支援向量:離分隔超平面最近的那些點。
4.分類器(資料集)的間隔:資料集中所有點到分割面的最小間隔的兩倍。
5.目標之一:選找到離分隔超平面最近的點,確保其離分隔面的距離儘可能的遠。
6.分隔超平面的數學形式:wTx+b
7.二維平面上的點到分隔超平面的距離:任取一點A,則該點到分隔平面的法線長度:|wTA+b|/∥w∥
8.新的目標:計算w和b 。為此,必須找到具有最小間隔的資料點,也即支援向量。一旦找到具有最小間隔的資料點,接著再對該間隔點最大化。數學形式可表示為:
通過拉格朗日運算元將上式化簡(雖然我並不知道到底是怎麼轉化的。。。)有:
進一步我們引入軟間隔項C(也稱為鬆弛變數),使得允許有些資料點可以處於分割面錯誤的一側,也即:
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\) ?