本文作者Key,博客園主頁:https://home.cnblogs.com/u/key1994/
本內容為個人原創作品,轉載請注明出處或聯系:zhengzha16@163.com
1.Introduction
接下來是關於支持向量機(SVM)算法的介紹。
我選擇SVM作為第一次博客的主要內容,並不是因為我覺得SVM算法優於其他算法,也不是因為我對該算法更了解,而是因為今天在參加Udacity的自動駕駛課程時剛好學習了SVM,所以及時記錄下來以便后用。
在學習一種新的算法的時候,我習慣於從了解該算法的提出時間、提出背景等問題來着手,因為這樣可以快速了解算法的優勢與劣勢、應用范圍,並方便與其他算法進行比較。這一過程往往需要花費時間來查閱大量的文獻,而且對算法的原理、推導等無過多幫助,因此往往被很多學者忽略。盡管如此,我依然會從眾多資料中想辦法找到我想要的答案。
一般認為,支持向量概念的提出是在20世紀60年代(准確的說是1963年),由Vladimir N. Vapnik and Alexey Ya. Chervonenkis ,而成熟的支持向量機理論則由Cortes和Vapnik在1995年正式發表的Machine Learning中提出的。也就是說,支持向量機雖然提出較早,但是真正實現流行應用是在1995年之后。
最早的支持向量機就是用於解決分類任務,而現在支持向量機也被用於回歸任務中。
2.原理推導
現在學習算法其實很簡單,只需要在Google或者百度中輸入“support vector machine”或者“SVM”或者“支持向量機”,至少可以找到成百上千條搜索結果。我們可以充分利用這些搜索結果來獲取我們想要的知識。而眾多結果里面,算法的原理推導往往市千篇一律的,所以我覺得在原理推導部分我不需要輸入這些重復的內容,只需要在理解的基礎上轉載別人的成果(或者更簡單一點,只需要留下網址)。但是,在這里我還是想要記錄一下自己的理解,也就是別人沒有提到的知識。

在這幅圖中,我們的任務是對x點和o點進行分類,這個問題看上去如此簡單——只需要在x點和o點確定一條直線(在空間中為超平面),即可完成分類。

但是可以實現該功能的直線(或者超平面)有很多個,而支持向量機的工作,就是確定最優的那一個。
具體如何實現的呢?
對於每一條直線(或超平面),總存在距離該直線(或超平面)距離(這里的距離如何理解?)最近的一個點,假設該距離分別為l1和l2,令
l = l1 + l2
在這里我們暫且討論二維世界的問題。根據支持向量機理論,使l值最大的一條直線即為最優的分類器。實際上,這里的l可以定義為margin,距離最優分類器最近的數據點被稱為“支持向量”。

到目前為止,我們就可以確定支持向量機的分類理論。
但是,在這里我有一個疑問,一旦直線的斜率確定好之后,我們可以在確定兩條直線a和b分別經過x點和o點,是否在a和b之間的任意一條直線都是最優分類器呢?因為這些直線的margin都是相同的。
查閱了一些資料,好像都沒有討論這個問題,不禁讓我懷疑自己是否沒有完全理解支持向量機的實質。但是,這個疑問依然深深印在我的腦海里。
對於我的疑問,我自己也嘗試着給出解答。首先,我認為即使在直線a和b之間任意確定一條直線,margin的大小都相同,但是真正的最優分類器只有一個。否則,你認為下圖中的c和d直線的分類效果相同嗎?

如果給定一個新的o樣本點,該樣本點有可能會落在直線b的右側,也有可能會落在左側。加入落在b的左側,由於直線d 距離直線b 更近,所以該點就會有更大的概率落在直線d的左側(注意,此時分類結果是錯誤的)。而c線距離直線b更遠,所以以c線為分類器時,新的樣本點被錯誤分類的概率更小。或者也可以以更專業的名詞來概括:c直線構成的分類器魯棒性更好。至於魯棒性的概念,這里無須多言。
那么,怎樣確定最優分類器的位置呢?以下是我個人的見解。
確定最優分類器的位置,需要充分考慮現有樣本點的分布規律。有時候一類樣本點可能分布較為緊湊,也可能較為分散。從統計學上來說,可以用方差或者標准差來描述這一特性。如果某類樣本點方差更大,則其數據越分散。由於我們假設所有的樣本是服從獨立同分布的(IID),那么就有理由相信,當給出一個新的數據點時,該數據點的位置不確定性越大。很明顯,分類器的位置要距離該類別數據更遠,從而保證分類器的魯棒性。因此,我的解決方法是:
對於已知的樣本,分別求出不同類別的樣本的方差,這里假設x點樣本的方差為V1,O點的方差為V2,支持向量機的margin為l,那么最優分類器距離a線的距離為:

即:某類型數據點的方差越大,分類器距離該樣本集越遠。
該方法還有一個優勢:在確定直線a和b 的斜率時,我們只用到了距離分類器最近的某些點,而距離分類器較遠的數據點沒有考慮,甚至在SVM的理論體系下這些點可能永遠都用不到。那么這些點是否包含有用的信息呢?我相信是包含的。通過求同類型所有數據點的方差,在一定程度上就可以提取到這些點的有用信息。
以上方法是我自己的一個簡單構想,至於方法的效果如何,我現在還來不及驗證,只能暫時擱置於此。如果有讀者對該方法有不同的看法,或者有意向去驗證,歡迎與我聯系。再次強調:我只是在做大膽的假設,然后小心的求證。結果可能不甚理想,望海涵。
3.核函數
如果支持向量機的介紹至此為止,那么算法也太過於簡單。事實是,以上部分僅僅是為了SVM的理論推導而進行的簡化,而現實中的問題復雜得多。例如,對於下圖所示的各個點,我們如何運用以上的知識進行分類呢?

顯然,我們很難找到一條直線將x點和O點完全分開。那此時應該怎么辦呢?
首先我們觀察一下這些數據點,不難發現x點距離坐標系原點都比較近,而O點則距離原點比較遠。如果構建以下函數:

那么就可以將各個數據點在新的x1-z坐標系中重新分布,如下圖所示:

看上去,我們就可以找到一條直線將x點和O點完美分類了。這里的z函數稱之為核函數(Kernel),至於為何如此命名,坦白講我也不知道。
如果你認為核函數的作用就是對數據點進行處理,使其可以線性可分,那么很遺憾的告訴你這種理解是錯誤的,因為以上例子只是核函數的一種特殊情況。核函數真正的作用是將高維問題中的復雜運算簡化為低維運算,從而避免了繁瑣的運算,加快分類器的訓練速度。想要深入了解核函數,只需要在你的瀏覽器中輸入“核函數”或者“Kernel Function”,即可獲得答案。還是之前說的,對於可以輕易找到答案的問題,這里不會花費時間來講解。
但現在的問題是,如何確定核函數呢?以上的示例是通過肉眼觀察出樣本點的分布規律,人為構造的的核函數。但是並不是所有的樣本點都可以通過肉眼觀察出其分布規律。因此,在支持向量機中,人們規定了幾種常用的核函數:

雖然這些函數公式看上去比較嚇人,但是如果你認真理解過核函數的定義,這些函數對你來說會非常簡單。而且,我們在使用SVM進行分類時,往往借助於python、Matlab等軟件來完成訓練與預測,在這些軟件中,我們只需要從相應的庫或者包中調用這些核函數即可,不需要手動輸入核函數的公式,應用起來非常方便。
值得一提的是,雖然SVM是目前非常常用且流行的一種算法,但是當我們使用SVM解決實際問題時,往往無法達到100%的准確率。一般來說我們需要規定目標准確率,然后通過不斷調整參數,朝着這個目標來努力。當然,我們也要想辦法避免出現過擬合(overfitting)。這里的參數主要有以下:
(1) C: float參數 默認值為1.0
錯誤項的懲罰系數。C越大,即對分錯樣本的懲罰程度越大,因此在訓練樣本中准確率越高,但是泛化能力降低,也就是對測試數據的分類准確率降低。相反,減小C的話,容許訓練樣本中有一些誤分類錯誤樣本,泛化能力強。對於訓練樣本帶有噪聲的情況,一般采用后者,把訓練樣本集中錯誤分類的樣本作為噪聲。
(2) gamma: float參數 默認為auto
核函數系數,只對‘rbf’,‘poly’,‘sigmod’有效。如果gamma為auto,代表其值為樣本特征數的倒數,即1/n_features。
gamma表征每一個訓練樣本對分類器的影響大小。gamma取值越大,則距離分類器較近的點的權重越大,即分類器主要考慮較近的點;gamma取值越小,則距離分類器較遠的點權重增大,分類器可以考慮更多樣本點的信息。
(3)其他參數
影響SVM分類精度、訓練效果、訓練時間的因素還有很多,這里不再贅述。可以參照以下網頁內容自行學習:
https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html
