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


第6章 支持向量機

如果公式不現實,請使用MarkDown的編輯器,加載 js 就可以看見了
<script type="text/javascript" src=" http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

支持向量機_首頁

支持向量機 概述

支持向量機(Support Vector Machines, SVM):是一種機器學習算法。

  • 支持向量(Support Vector)就是離分隔超平面最近的那些點。
  • 機(Machine)就是表示一種算法,而不是表示機器。

支持向量機 場景

  • 要給左右兩邊的點進行分類
  • 明顯發現:選擇D會比B、C分隔的效果要好很多。

線性可分

支持向量機 原理

SVM 工作原理

k_2

對於上述的蘋果和香蕉,我們想象為2種水果類型的炸彈。(保證距離最近的炸彈,距離它們最遠)

  1. 尋找最大分類間距
  2. 轉而通過拉格朗日函數求優化的問題
  • 數據可以通過畫一條直線就可以將它們完全分開,這組數據叫線性可分(linearly separable)數據,而這條分隔直線稱為分隔超平面(separating hyperplane)
  • 如果數據集上升到1024維呢?那么需要1023維來分隔數據集,也就說需要N-1維的對象來分隔,這個對象叫做超平面(hyperlane),也就是分類的決策邊界。

分隔超平面

尋找最大間隔

為什么尋找最大間隔

摘錄地址:http://slideplayer.com/slide/8610144  (第12條信息)
Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why Maximum Margin? 
denotes +1 denotes -1 f(x,w,b) = sign(w. x - b) The maximum margin linear classifier is the linear classifier with the, um, maximum margin. 
This is the simplest kind of SVM (Called an LSVM) Support Vectors are those datapoints that the margin pushes up against 

1.Intuitively this feels safest. 
2.If we’ve made a small error in the location of the boundary (it’s been jolted in its perpendicular direction) this gives us least chance of causing a misclassification. 
3.CV is easy since the model is immune to removal of any non-support-vector datapoints. 
4.There’s some theory that this is a good thing. 
5.Empirically it works very very well. 

* * *

1. 直覺上是安全的
2. 如果我們在邊界的位置發生了一個小錯誤(它在垂直方向上被顛倒),這給我們最小的錯誤分類機會。
3. CV(Computer Vision 計算機視覺 - 這縮寫看着可怕�)很容易,因為該模型對任何非支持向量數據點的去除是免疫的。
4. 有一些理論,這是一件好事。
5. 通常它的工作非常好。

怎么尋找最大間隔

點到超平面的距離

  • 分隔超平面函數間距: \(y(x)=w^Tx+b\)
  • 分類的結果: \(f(x)=sign(w^Tx+b)\) (sign表示>0為1,<0為-1,=0為0)
  • 點到超平面的幾何間距: \(d(x)=(w^Tx+b)/||w||\) (||w||表示w矩陣的二范式=> \(\sqrt{w*w^T}\), 點到超平面的距離也是類似的)

點到直線的幾何距離

拉格朗日乘子法

  • 類別標簽用-1、1,是為了后期方便 \(lable*(w^Tx+b)\) 的標識和距離計算;如果 \(lable*(w^Tx+b)>0\) 表示預測正確,否則預測錯誤。
  • 現在目標很明確,就是要找到wb,因此我們必須要找到最小間隔的數據點,也就是前面所說的支持向量
    • 也就說,讓最小的距離取最大.(最小的距離:就是最小間隔的數據點;最大:就是最大間距,為了找出最優超平面--最終就是支持向量)
    • 目標函數:\(arg: max_{關於w, b} \left( min[lable*(w^Tx+b)]*\frac{1}{||w||} \right) \)
      1. 如果 \(lable*(w^Tx+b)>0\) 表示預測正確,也稱函數間隔,\(||w||\) 可以理解為歸一化,也稱幾何間隔
      2. 令 \(lable*(w^Tx+b)>=1\), 因為0~1之間,得到的點是存在誤判的可能性,所以要保障 \(min[lable*(w^Tx+b)]=1\),才能更好降低噪音數據影響。
      3. 所以本質上是求 \(arg: max_{關於w, b} \frac{1}{||w||} \);也就說,我們約束(前提)條件是: \(lable*(w^Tx+b)=1\)
  • 新的目標函數求解: \(arg: max_{關於w, b} \frac{1}{||w||} \)
    • => 就是求: \(arg: min_{關於w, b} ||w|| \) (求矩陣會比較麻煩,如果x只是 \(\frac{1}{2}*x^2\) 的偏導數,那么。。同樣是求最小值)
    • => 就是求: \(arg: min_{關於w, b} (\frac{1}{2}*||w||^2)\) (二次函數求導,求極值,平方也方便計算)
    • 本質上就是求線性不等式的二次優化問題(求分隔超平面,等價於求解相應的凸二次規划問題)
  • 通過拉格朗日乘子法,求二次優化問題
    • 假設需要求極值的目標函數 (objective function) 為 f(x,y),限制條件為 φ(x,y)=M # M=1
    • 設g(x,y)=M-φ(x,y) # 臨時φ(x,y)表示下文中 \(label*(w^Tx+b)\)
    • 定義一個新函數: F(x,y,λ)=f(x,y)+λg(x,y)
    • a為λ(a>=0),代表要引入的拉格朗日乘子(Lagrange multiplier)
    • 那么: \(L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\)
    • 因為:\(label*(w^Tx+b)>=1, \alpha>=0\) , 所以 \(\alpha*[1-label*(w^Tx+b)]<=0\) , \(\sum_{i=1}^{n} \alpha_i * [1-label*(w^Tx+b)]<=0\)
    • 相當於求解: \(max_{關於\alpha} L(w,b,\alpha) = \frac{1}{2} *||w||^2\)
    • 如果求: \(min_{關於w, b} \frac{1}{2} *||w||^2\) , 也就是要求: \(min_{關於w, b} \left( max_{關於\alpha} L(w,b,\alpha)\right)\)
  • 現在轉化到對偶問題的求解
    • \(min_{關於w, b} \left(max_{關於\alpha} L(w,b,\alpha) \right) \) >= \(max_{關於\alpha} \left(min_{關於w, b}\ L(w,b,\alpha) \right) \)
    • 現在分2步
    • 先求: \(min_{關於w, b} L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\)
    • 就是求L(w,b,a)關於[w, b]的偏導數, 得到w和b的值,並化簡為:L和a的方程
    • 參考: 如果公式推導還是不懂,也可以參考《統計學習方法》李航-P103<學習的對偶算法> 計算拉格朗日函數的對偶函數
  • 終於得到課本上的公式: \(max_{關於\alpha} \left( \sum_{i=1}^{m} \alpha_i - \frac{1}{2} \sum_{i, j=1}^{m} label_i·label_j·\alpha_i·\alpha_j·<x_i, x_j> \right) \)
  • 約束條件: \(a>=0\) 並且 \(\sum_{i=1}^{m} a_i·label_i=0\)

松弛變量(slack variable)

  • 我們知道幾乎所有的數據都不那么干凈, 通過引入松弛變量來允許數據點可以處於分隔面錯誤的一側
  • 約束條件: \(C>=a>=0\) 並且 \(\sum_{i=1}^{m} a_i·label_i=0\)
  • 這里常量C用於控制“最大化間隔”和“保證大部分點的函數間隔小於1.0” 這兩個目標的權重。
  • 常量C是一個常數,我們通過調節該參數得到不同的結果。一旦求出了所有的alpha,那么分隔超平面就可以通過這些alpha來表示。
  • 這一結論十分直接,SVM中的主要工作就是要求解 alpha.

SMO 高效優化算法

  • SVM有很多種實現,最流行的一種實現是: 序列最小優化(Sequential Minimal Optimization, SMO)算法
  • 下面還會介紹一種稱為核函數(kernel)的方式將SVM擴展到更多數據集上。
  • 注意:SVM幾何含義比較直觀,但其算法實現較復雜,牽扯大量數學公式的推導。

序列最小優化(Sequential Minimal Optimization, SMO)

  • 創建作者:John Platt
  • 創建時間:1996年
  • SMO用途:用於訓練 SVM
  • SMO目標:求出一系列 alpha 和 b,一旦求出 alpha,就很容易計算出權重向量 w 並得到分隔超平面。
  • SMO思想:是將大優化問題分解為多個小優化問題來求解的。
  • SMO原理:每次循環選擇兩個 alpha 進行優化處理,一旦找出一對合適的 alpha,那么就增大一個同時減少一個。
    • 這里指的合適必須要符合一定的條件
      1. 這兩個 alpha 必須要在間隔邊界之外
      2. 這兩個 alpha 還沒有進行過區間化處理或者不在邊界上。
    • 之所以要同時改變2個 alpha;原因是我們有一個約束條件: \(\sum_{i=1}^{m} a_i·label_i=0\);如果只是修改一個 alpha,很可能導致約束條件失效。

SMO 偽代碼大致如下:

創建一個 alpha 向量並將其初始化為0向量
當迭代次數小於最大迭代次數時(外循環)
    對數據集中的每個數據向量(內循環):
        如果該數據向量可以被優化
            隨機選擇另外一個數據向量
            同時優化這兩個向量
            如果兩個向量都不能被優化,退出內循環
    如果所有向量都沒被優化,增加迭代數目,繼續下一次循環

SVM 開發流程

收集數據:可以使用任意方法。
准備數據:需要數值型數據。
分析數據:有助於可視化分隔超平面。
訓練算法:SVM的大部分時間都源自訓練,該過程主要實現兩個參數的調優。
測試算法:十分簡單的計算過程就可以實現。
使用算法:幾乎所有分類問題都可以使用SVM,值得一提的是,SVM本身是一個二類分類器,對多類問題應用SVM需要對代碼做一些修改。

SVM 算法特點

優點:泛化(由具體的、個別的擴大為一般的,就是說:模型訓練完后的新樣本)錯誤率低,計算開銷不大,結果易理解。
缺點:對參數調節和核函數的選擇敏感,原始分類器不加修改僅適合於處理二分類問題。
使用數據類型:數值型和標稱型數據。

課本案例(無核函數)

項目概述

對小規模數據點進行分類

開發流程

收集數據

文本文件格式:

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

分析數據: 無

訓練算法

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

完整代碼地址:SVM簡化版,應用簡化版SMO算法處理小規模數據集https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-simple.py

完整代碼地址:SVM完整版,使用完整 Platt SMO算法加速優化,優化點:選擇alpha的方式不同https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-complete_Non-Kernel.py

核函數(kernel) 使用

  • 對於線性可分的情況,效果明顯
  • 對於非線性的情況也一樣,此時需要用到一種叫核函數(kernel)的工具將數據轉化為分類器易於理解的形式。

利用核函數將數據映射到高維空間

  • 使用核函數:可以將數據從某個特征空間到另一個特征空間的映射。(通常情況下:這種映射會將低維特征空間映射到高維空間。)
  • 如果覺得特征空間很裝逼、很難理解。
  • 可以把核函數想象成一個包裝器(wrapper)或者是接口(interface),它能將數據從某個很難處理的形式轉換成為另一個較容易處理的形式。
  • 經過空間轉換后:低維需要解決的非線性問題,就變成了高維需要解決的線性問題。
  • SVM 優化特別好的地方,在於所有的運算都可以寫成內積(inner product: 是指2個向量相乘,得到單個標量 或者 數值);內積替換成核函數的方式被稱為核技巧(kernel trick)或者核"變電"(kernel substation)
  • 核函數並不僅僅應用於支持向量機,很多其他的機器學習算法也都用到核函數。最流行的核函數:徑向基函數(radial basis function)
  • 徑向基函數的高斯版本,其具體的公式為:

徑向基函數的高斯版本

項目案例: 手寫數字識別的優化(有核函數)

項目概述

你的老板要求:你寫的那個手寫識別程序非常好,但是它占用內存太大。顧客無法通過無線的方式下載我們的應用。
所以:我們可以考慮使用支持向量機,保留支持向量就行(knn需要保留所有的向量),就可以獲得非常好的效果。

開發流程

收集數據:提供的文本文件

00000000000000001111000000000000 00000000000000011111111000000000 00000000000000011111111100000000 00000000000000011111111110000000 00000000000000011111111110000000 00000000000000111111111100000000 00000000000000111111111100000000 00000000000001111111111100000000 00000000000000111111111100000000 00000000000000111111111100000000 00000000000000111111111000000000 00000000000001111111111000000000 00000000000011111111111000000000 00000000000111111111110000000000 00000000001111111111111000000000 00000001111111111111111000000000 00000011111111111111110000000000 00000111111111111111110000000000 00000111111111111111110000000000 00000001111111111111110000000000 00000001111111011111110000000000 00000000111100011111110000000000 00000000000000011111110000000000 00000000000000011111100000000000 00000000000000111111110000000000 00000000000000011111110000000000 00000000000000011111110000000000 00000000000000011111111000000000 00000000000000011111111000000000 00000000000000011111111000000000 00000000000000000111111110000000 00000000000000000111111100000000 

准備數據:基於二值圖像構造向量

將 32*32的文本轉化為 1*1024的矩陣

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 = [] print(dirName) trainingFileList = listdir(dirName) # load the training set m = len(trainingFileList) trainingMat = zeros((m, 1024)) for i in range(m): fileNameStr = trainingFileList[i] fileStr = fileNameStr.split('.')[0] # take off .txt 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

分析數據:對圖像向量進行目測

訓練算法:采用兩種不同的核函數,並對徑向基核函數采用不同的設置來運行SMO算法

def kernelTrans(X, A, kTup): # calc the kernel or transform data to a higher dimensional space """  核轉換函數  Args:  X dataMatIn數據集  A dataMatIn數據集的第i行的數據  kTup 核函數的信息   Returns:   """ m, n = shape(X) K = mat(zeros((m, 1))) if kTup[0] == 'lin': # linear kernel: m*n * n*1 = m*1 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)) # divide in NumPy is element-wise not matrix like Matlab else: raise NameError('Houston We Have a Problem -- That Kernel is not recognized') return K def smoP(dataMatIn, classLabels, C, toler, maxIter, kTup=('lin', 0)): """  完整SMO算法外循環,與smoSimple有些類似,但這里的循環退出條件更多一些  Args:  dataMatIn 數據集  classLabels 類別標簽  C 松弛變量(常量值),允許有些數據點可以處於分隔面的錯誤一側。  控制最大化間隔和保證大部分的函數間隔小於1.0這兩個目標的權重。  可以通過調節該參數達到不同的結果。  toler 容錯率  maxIter 退出前最大的循環次數  kTup 包含核函數信息的元組  Returns:  b 模型的常量值  alphas 拉格朗日乘子  """ # 創建一個 optStruct 對象 oS = optStruct(mat(dataMatIn), mat(classLabels).transpose(), C, toler, kTup) iter = 0 entireSet = True alphaPairsChanged = 0 # 循環遍歷:循環maxIter次 並且 (alphaPairsChanged存在可以改變 or 所有行遍歷一遍) while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): alphaPairsChanged = 0 # 當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 # 如果找到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

測試算法:便攜一個函數來測試不同的和函數並計算錯誤率

def testDigits(kTup=('rbf', 10)): # 1. 導入訓練數據 dataArr, labelArr = loadImages('input/6.SVM/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) # 1*m * m*1 = 1*1 單個預測結果 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)) # 2. 導入測試數據 dataArr, labelArr = loadImages('input/6.SVM/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) # 1*m * m*1 = 1*1 單個預測結果 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))

使用算法:一個圖像識別的完整應用還需要一些圖像處理的知識,這里並不打算深入介紹

完整代碼地址https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-complete.py



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM