機器學習 | 算法筆記- 支持向量機(Support Vector Machine)

前言

本系列爲機器學習算法的總結和概括,目的爲了清晰闡述算法原理,同時附帶上手代碼實例,便於理解。

目錄

   決策樹
   線性迴歸
  組合算法(Ensemble Method)
   K-Means
  機器學習算法總結

1、簡介

1 概述

支持向量機(Support Vector Machine,常簡稱爲SVM)是一種監督式學習的方法,可普遍地應用於統計分類以及迴歸分析。支持向量機屬於通常化線性分類器,這族分類器的特色是他們可以同時最小化經驗偏差與最大化幾何邊緣區,所以支持向量機也被稱爲最大邊緣區分類器。
如上圖所示,SVM的目的是尋找一個最優分割面,使得分類分類間隔最大化。而最優分割面求解原則能夠大體概括以下:
最優決策面可以容忍更多噪聲—>全部樣本與分割超平面的距離儘量遠—>最差的樣本(離分割超平面最近的樣本)與分割超平面的距離要儘量遠。

2 數學建模

以上簡單歸納了SVM工做的大體思路,下面要進一步求解「決策面」,也就是最優化。在這個最優化問題中,目標函數對應的是「分類間隔」,而優化對象則是決策面。
 
(1)決策面方程(超平面方程)
將二維空間直線y = ax + b進行轉換和向量化,可得
其中向量w和x分別爲:
向量化後的w和r幾何意義分別是原直線的法向量和截距。
將上式推廣到n維空間就變成了超平面方程(一個超平面,在二維空間的例子就是一個直線),並且公式沒有變,只是
 
(2)「分類間隔」方程
由圖可知間隔的大小實際上就是支持向量對應的樣本點到決策面的距離的二倍。而
公式中的直線方程爲Ax0+By0+C=0,點P的座標爲(x0,y0)。
將直線方程擴展到多維,求得咱們如今的超平面方程,對公式進行以下變形:
這個d就是"分類間隔"。其中||w||表示w的二範數,求全部元素的平方和,而後再開方。所以
目的是爲了找出一個分類效果好的超平面做爲分類器。分類器的好壞的評定依據是分類間隔W=2d的大小,即分類間隔w越大,咱們認爲這個超平面的分類效果越好。此時,求解超平面的問題就變成了求解分類間隔W最大化的爲題。W的最大化也就是d最大化的。
 
(3)約束條件
得到目標函數的數學形式以後,須要將約束條件用數學語言進行描述。即如何判斷超平面是否將樣本點正確分類?以及怎麼在衆多的點中選出支持向量上的點?
首先若是徹底正確分類,會知足
若是咱們目標是求解中軸線上的決策面,而且相應的支持向量對應的樣本點到決策面的距離爲d,代入整理並簡化,最終可得SVM最優化問題的約束條件
 
(4)線性SVM優化問題基本描述
獲得咱們的目標函數,咱們的目標是d最大化。
而支持向量上的樣本點知足
所以能夠將目標函數進一步簡化,
隨後咱們求解d的最大化問題變成了||w||的最小化問題
上述等效是爲了求導方便,並不影響求解過程。所以,將最終的目標函數和約束條件放在一塊兒進行描述:
上述公式描述的是一個典型的不等式約束條件下的二次型函數優化問題,同時也是支持向量機的基本數學模型。
 
(5)求解準備
最優化前提是目標函數必須是凸函數,其幾何意義表示爲函數任意兩點連線上的值大於對應自變量處的函數值。其中根據凸集L的定義域,能夠分爲局部凸和全局凸
而咱們的目標函數是凸函數,所以能夠採用下面幾種方法求解。
 
一般咱們須要求解的最優化問題有以下幾類:
· 無約束優化問題,能夠寫爲:
· 有等式約束的優化問題,能夠寫爲:
· 有不等式約束的優化問題,能夠寫爲:
對於第(a)類的優化問題,嘗試使用的方法就是費馬大定理(Fermat),即便用求取函數f(x)的導數,而後令其爲零,能夠求得候選最優值,再在這些候選值中驗證;若是是凸函數,能夠保證是最優解。這也就是咱們高中常用的求函數的極值的方法。
 
對於第(b)類的優化問題,經常使用的方法就是拉格朗日乘子法(Lagrange Multiplier) ,即把等式約束h_i(x)用一個係數與f(x)寫爲一個式子,稱爲拉格朗日函數,而係數稱爲拉格朗日乘子。經過拉格朗日函數對各個變量求導,令其爲零,能夠求得候選值集合,而後驗證求得最優值。
 
對於第(c)類的優化問題,經常使用的方法就是KKT條件。一樣地,咱們把全部的等式、不等式約束與f(x)寫爲一個式子,也叫拉格朗日函數,係數也稱拉格朗日乘子,經過一些條件,能夠求出最優值的必要條件,這個條件稱爲KKT條件。
 
所以,求解最優化問題前,還須要學習 拉格朗日函數和KKT條件
 
(6)拉格朗日函數
使用拉格朗日方程的目的,它將約束條件放到目標函數中,從而將有約束優化問題轉換爲無約束優化問題,並使用拉格朗日對偶優化求解過程。
公式變形以下:
問題變成了求解新目標函數的最小值
新目標函數,先求最大值,再求最小值。這樣的話,咱們首先就要面對帶有須要求解的參數w和b的方程,而αi又是不等式約束,這個求解過程很差作。因此,咱們須要使用拉格朗日函數對偶性,將最小和最大的位置交換一下,這樣就變成了:
而咱們要的解是d = p,而知足這個條件,首先必須是凸優化問題,同時要知足KKT條件。
 
(7)KKT條件
KKT條件的全稱是Karush-Kuhn-Tucker條件,KKT條件是說最優值條件必須知足如下條件:
條件一:通過拉格朗日函數處理以後的新目標函數L(w,b,α)對x求導爲零:
條件二:h(x) = 0;
條件三:α*g(x) = 0;
可證以上條件均知足,詳細證實過程見參考。如今,凸優化問題和KKT都知足了,問題轉換成了對偶問題。而求解這個對偶學習問題,能夠分爲三個步驟:首先要讓L(w,b,α)關於w和b最小化,而後求對α的極大,最後利用SMO算法求解對偶問題中的拉格朗日乘子。
 
(8)SMO算法
SM表示序列最小化(Sequential Minimal Optimizaion),目標是將大優化問題分解爲多個小優化問題來求解的。這些小優化問題每每很容易求解,而且對它們進行順序求解的結果與將它們做爲總體來求解的結果徹底一致的。在結果徹底相同的同時,SMO算法的求解時間短不少。
SMO算法的目標是求出一系列alpha和b,一旦求出了這些alpha,就很容易計算出權重向量w並獲得分隔超平面。
SMO算法的工做原理是:每次循環中選擇兩個alpha進行優化處理。一旦找到了一對合適的alpha,那麼就增大其中一個同時減少另外一個。這裏所謂的"合適"就是指兩個alpha必須符合如下兩個條件,條件之一就是兩個alpha必需要在間隔邊界以外,並且第二個條件則是這兩個alpha尚未進行過區間化處理或者不在邊界上。

3 非線性SVM

在線性不可分的狀況下,SVM經過某種事先選擇的非線性映射(核函數)將輸入變量映到一個高維特徵空間,將其變成在高維空間線性可分,在這個高維空間中構造最優分類超平面。
對於線性不可分,咱們使用一個非線性映射,將數據映射到特徵空間,在特徵空間中使用線性學習器,分類函數變形以下:
創建非線性學習器分爲兩步:首先使用一個非線性映射將數據變換到一個特徵空間F;而後在特徵空間使用線性學習器分類。
使用核函數後,能夠在低維特徵空間中直接計算內積 <ϕ(xi),ϕ(x)>,簡化求解過程。
 
徑向基核函數採用向量做爲自變量的函數,可以基於向量舉例運算輸出一個標量。徑向基核函數的高斯版本的公式以下:
σ是用戶自定義的用於肯定到達率(reach)或者說函數值跌落到0的速度參數。經過調控參數σ,高斯覈實際上具備至關高的靈活性,也是使用最普遍的核函數之一。

2、代碼實戰

2.1 核函數非線性SVM實現

 
# -*-coding:utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
import random


class optStruct:
    """
    數據結構,維護全部須要操做的值
    Parameters:
        dataMatIn - 數據矩陣
        classLabels - 數據標籤
        C - 鬆弛變量
        toler - 容錯率
        kTup - 包含核函數信息的元組,第一個參數存放核函數類別,第二個參數存放必要的核函數須要用到的參數
    """
    def __init__(self, dataMatIn, classLabels, C, toler, kTup):
        self.X = dataMatIn                                #數據矩陣
        self.labelMat = classLabels                        #數據標籤
        self.C = C                                         #鬆弛變量
        self.tol = toler                                 #容錯率
        self.m = np.shape(dataMatIn)[0]                 #數據矩陣行數
        self.alphas = np.mat(np.zeros((self.m,1)))         #根據矩陣行數初始化alpha參數爲0    
        self.b = 0                                         #初始化b參數爲0
        self.eCache = np.mat(np.zeros((self.m,2)))         #根據矩陣行數初始化虎偏差緩存,第一列爲是否有效的標誌位,第二列爲實際的偏差E的值。
        self.K = np.mat(np.zeros((self.m,self.m)))        #初始化核K
        for i in range(self.m):                            #計算全部數據的核K
            self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)

def kernelTrans(X, A, kTup): 
    """
    經過核函數將數據轉換更高維的空間
    Parameters:
        X - 數據矩陣
        A - 單個數據的向量
        kTup - 包含核函數信息的元組
    Returns:
        K - 計算的核K
    """
    m,n = np.shape(X)
    K = np.mat(np.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 = np.exp(K/(-1*kTup[1]**2))                     #計算高斯核K
    else: raise NameError('核函數沒法識別')
    return K                                             #返回計算的核K

def loadDataSet(fileName):
    """
    讀取數據
    Parameters:
        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 calcEk(oS, k):
    """
    計算偏差
    Parameters:
        oS - 數據結構
        k - 標號爲k的數據
    Returns:
        Ek - 標號爲k的數據偏差
    """
    fXk = float(np.multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b)
    Ek = fXk - float(oS.labelMat[k])
    return Ek

def selectJrand(i, m):
    """
    函數說明:隨機選擇alpha_j的索引值

    Parameters:
        i - alpha_i的索引值
        m - alpha參數個數
    Returns:
        j - alpha_j的索引值
    """
    j = i                                 #選擇一個不等於i的j
    while (j == i):
        j = int(random.uniform(0, m))
    return j

def selectJ(i, oS, Ei):
    """
    內循環啓發方式2
    Parameters:
        i - 標號爲i的數據的索引值
        oS - 數據結構
        Ei - 標號爲i的數據偏差
    Returns:
        j, maxK - 標號爲j或maxK的數據的索引值
        Ej - 標號爲j的數據偏差
    """
    maxK = -1; maxDeltaE = 0; Ej = 0                         #初始化
    oS.eCache[i] = [1,Ei]                                      #根據Ei更新偏差緩存
    validEcacheList = np.nonzero(oS.eCache[:,0].A)[0]        #返回偏差不爲0的數據的索引值
    if (len(validEcacheList)) > 1:                            #有不爲0的偏差
        for k in validEcacheList:                           #遍歷,找到最大的Ek
            if k == i: continue                             #不計算i,浪費時間
            Ek = calcEk(oS, k)                                #計算Ek
            deltaE = abs(Ei - Ek)                            #計算|Ei-Ek|
            if (deltaE > maxDeltaE):                        #找到maxDeltaE
                maxK = k; maxDeltaE = deltaE; Ej = Ek
        return maxK, Ej                                        #返回maxK,Ej
    else:                                                   #沒有不爲0的偏差
        j = selectJrand(i, oS.m)                            #隨機選擇alpha_j的索引值
        Ej = calcEk(oS, j)                                    #計算Ej
    return j, Ej                                             #j,Ej

def updateEk(oS, k):
    """
    計算Ek,並更新偏差緩存
    Parameters:
        oS - 數據結構
        k - 標號爲k的數據的索引值
    Returns:
        無
    """
    Ek = calcEk(oS, k)                                        #計算Ek
    oS.eCache[k] = [1,Ek]                                    #更新偏差緩存


def clipAlpha(aj,H,L):
    """
    修剪alpha_j
    Parameters:
        aj - alpha_j的值
        H - alpha上限
        L - alpha下限
    Returns:
        aj - 修剪後的alpah_j的值
    """
    if aj > H: 
        aj = H
    if L > aj:
        aj = L
    return aj

def innerL(i, oS):
    """
    優化的SMO算法
    Parameters:
        i - 標號爲i的數據的索引值
        oS - 數據結構
    Returns:
        1 - 有任意一對alpha值發生變化
        0 - 沒有任意一對alpha值發生變化或變化過小
    """
    #步驟1:計算偏差Ei
    Ei = calcEk(oS, i)
    #優化alpha,設定必定的容錯率。
    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)):
        #使用內循環啓發方式2選擇alpha_j,並計算Ej
        j,Ej = selectJ(i, oS, Ei)
        #保存更新前的aplpha值,使用深拷貝
        alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy();
        #步驟2:計算上下界L和H
        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
        #步驟3:計算eta
        eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j]
        if eta >= 0: 
            print("eta>=0")
            return 0
        #步驟4:更新alpha_j
        oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej)/eta
        #步驟5:修剪alpha_j
        oS.alphas[j] = clipAlpha(oS.alphas[j],H,L)
        #更新Ej至偏差緩存
        updateEk(oS, j)
        if (abs(oS.alphas[j] - alphaJold) < 0.00001): 
            print("alpha_j變化過小")
            return 0
        #步驟6:更新alpha_i
        oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])
        #更新Ei至偏差緩存
        updateEk(oS, i)
        #步驟7:更新b_1和b_2
        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]
        #步驟8:根據b_1和b_2更新b
        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)):
    """
    完整的線性SMO算法
    Parameters:
        dataMatIn - 數據矩陣
        classLabels - 數據標籤
        C - 鬆弛變量
        toler - 容錯率
        maxIter - 最大迭代次數
        kTup - 包含核函數信息的元組
    Returns:
        oS.b - SMO算法計算的b
        oS.alphas - SMO算法計算的alphas
    """
    oS = optStruct(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler, kTup)                #初始化數據結構
    iter = 0                                                                                         #初始化當前迭代次數
    entireSet = True; alphaPairsChanged = 0
    while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):                            #遍歷整個數據集都alpha也沒有更新或者超過最大迭代次數,則退出循環
        alphaPairsChanged = 0
        if entireSet:                                                                                #遍歷整個數據集                           
            for i in range(oS.m):        
                alphaPairsChanged += innerL(i,oS)                                                    #使用優化的SMO算法
                print("全樣本遍歷:第%d次迭代 樣本:%d, alpha優化次數:%d" % (iter,i,alphaPairsChanged))
            iter += 1
        else:                                                                                         #遍歷非邊界值
            nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]                        #遍歷不在邊界0和C的alpha
            for i in nonBoundIs:
                alphaPairsChanged += innerL(i,oS)
                print("非邊界遍歷:第%d次迭代 樣本:%d, alpha優化次數:%d" % (iter,i,alphaPairsChanged))
            iter += 1
        if entireSet:                                                                                #遍歷一次後改成非邊界遍歷
            entireSet = False
        elif (alphaPairsChanged == 0):                                                                #若是alpha沒有更新,計算全樣本遍歷 
            entireSet = True  
        print("迭代次數: %d" % iter)
    return oS.b,oS.alphas                                                                             #返回SMO算法計算的b和alphas


def testRbf(k1 = 1.3):
    """
    測試函數
    Parameters:
        k1 - 使用高斯核函數的時候表示到達率
    Returns:
        無
    """
    dataArr,labelArr = loadDataSet('testSetRBF.txt')                        #加載訓練集
    b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 100, ('rbf', k1))        #根據訓練集計算b和alphas
    datMat = np.mat(dataArr); labelMat = np.mat(labelArr).transpose()
    svInd = np.nonzero(alphas.A > 0)[0]                                        #得到支持向量
    sVs = datMat[svInd]                                                     
    labelSV = labelMat[svInd];
    print("支持向量個數:%d" % np.shape(sVs)[0])
    m,n = np.shape(datMat)
    errorCount = 0
    for i in range(m):
        kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))                #計算各個點的核
        predict = kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b     #根據支持向量的點,計算超平面,返回預測結果
        if np.sign(predict) != np.sign(labelArr[i]): errorCount += 1        #返回數組中各元素的正負符號,用1和-1表示,並統計錯誤個數
    print("訓練集錯誤率: %.2f%%" % ((float(errorCount)/m)*100))             #打印錯誤率
    dataArr,labelArr = loadDataSet('testSetRBF2.txt')                         #加載測試集
    errorCount = 0
    datMat = np.mat(dataArr); labelMat = np.mat(labelArr).transpose()         
    m,n = np.shape(datMat)
    for i in range(m):
        kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1))                 #計算各個點的核            
        predict=kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b         #根據支持向量的點,計算超平面,返回預測結果
        if np.sign(predict) != np.sign(labelArr[i]): errorCount += 1        #返回數組中各元素的正負符號,用1和-1表示,並統計錯誤個數
    print("測試集錯誤率: %.2f%%" % ((float(errorCount)/m)*100))             #打印錯誤率


def showDataSet(dataMat, labelMat):
    """
    數據可視化
    Parameters:
        dataMat - 數據矩陣
        labelMat - 數據標籤
    Returns:
        無
    """
    data_plus = []                                  #正樣本
    data_minus = []                                 #負樣本
    for i in range(len(dataMat)):
        if labelMat[i] > 0:
            data_plus.append(dataMat[i])
        else:
            data_minus.append(dataMat[i])
    data_plus_np = np.array(data_plus)              #轉換爲numpy矩陣
    data_minus_np = np.array(data_minus)            #轉換爲numpy矩陣
    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1])   #正樣本散點圖
    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #負樣本散點圖
    plt.show()

if __name__ == '__main__':
    testRbf()
View Code

執行結果:html

2.2 Sklearn實現手寫數字識別

sklearn.svm模塊提供了不少模型供咱們使用,本文使用的是svm.SVC,它是基於libsvm實現的。
SVC這個函數,一共有14個參數。具體每一個參數表明內容參見官方材料 https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html
SVC非常強大,咱們不用理解算法實現的具體細節,不用理解算法的優化方法。同時,它也知足咱們的多分類需求。

# -*- coding: UTF-8 -*-
import numpy as np
import operator
from os import listdir
from sklearn.svm import SVC


def img2vector(filename):
    """
    將32x32的二進制圖像轉換爲1x1024向量。
    Parameters:
        filename - 文件名
    Returns:
        returnVect - 返回的二進制圖像的1x1024向量
    """
    #建立1x1024零向量
    returnVect = np.zeros((1, 1024))
    #打開文件
    fr = open(filename)
    #按行讀取
    for i in range(32):
        #讀一行數據
        lineStr = fr.readline()
        #每一行的前32個元素依次添加到returnVect中
        for j in range(32):
            returnVect[0, 32*i+j] = int(lineStr[j])
    #返回轉換後的1x1024向量
    return returnVect

def handwritingClassTest():
    """
    手寫數字分類測試
    Parameters:
        無
    Returns:
        無
    """
    #測試集的Labels
    hwLabels = []
    #返回trainingDigits目錄下的文件名
    trainingFileList = listdir('trainingDigits')
    #返回文件夾下文件的個數
    m = len(trainingFileList)
    #初始化訓練的Mat矩陣,測試集
    trainingMat = np.zeros((m, 1024))
    #從文件名中解析出訓練集的類別
    for i in range(m):
        #得到文件的名字
        fileNameStr = trainingFileList[i]
        #得到分類的數字
        classNumber = int(fileNameStr.split('_')[0])
        #將得到的類別添加到hwLabels中
        hwLabels.append(classNumber)
        #將每個文件的1x1024數據存儲到trainingMat矩陣中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % (fileNameStr))
    clf = SVC(C=200,kernel='rbf')
    clf.fit(trainingMat,hwLabels)
    #返回testDigits目錄下的文件列表
    testFileList = listdir('testDigits')
    #錯誤檢測計數
    errorCount = 0.0
    #測試數據的數量
    mTest = len(testFileList)
    #從文件中解析出測試集的類別並進行分類測試
    for i in range(mTest):
        #得到文件的名字
        fileNameStr = testFileList[i]
        #得到分類的數字
        classNumber = int(fileNameStr.split('_')[0])
        #得到測試集的1x1024向量,用於訓練
        vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))
        #得到預測結果
        # classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        classifierResult = clf.predict(vectorUnderTest)
        print("分類返回結果爲%d\t真實結果爲%d" % (classifierResult, classNumber))
        if(classifierResult != classNumber):
            errorCount += 1.0
    print("總共錯了%d個數據\n錯誤率爲%f%%" % (errorCount, errorCount/mTest * 100))

if __name__ == '__main__':
    handwritingClassTest()
View Code

3、SVM的優缺點

3.1 優勢
- 可用於線性/非線性分類,也能夠用於迴歸,泛化錯誤率低,也就是說具備良好的學習能力,且學到的結果具備很好的推廣性。
- 能夠解決小樣本狀況下的機器學習問題,能夠解決高維問題,能夠避免神經網絡結構選擇和局部極小點問題。
- SVM是最好的現成的分類器,現成是指不加修改可直接使用。而且可以獲得較低的錯誤率,SVM能夠對訓練集以外的數據點作很好的分類決策。
 
3.2 缺點
- 對參數調節和和函數的選擇敏感。
 
參考:
相關文章
相關標籤/搜索