06機器學習實戰之SVM

對偶的概念

https://blog.csdn.net/qq_34531825/article/details/52872819?locationNum=7&fps=1javascript

拉格朗日乘子法、KKT條件

https://blog.csdn.net/mr_kktian/article/details/53750424css

1、什麼是SVM?

SVM的英文全稱是Support Vector Machines,咱們叫它支持向量機。支持向量機是咱們用於分類的一種算法。讓咱們以一個小故事的形式,開啓咱們的SVM之旅吧。html

在好久之前的情人節,一位大俠要去救他的愛人,但天空中的魔鬼和他玩了一個遊戲。html5

魔鬼在桌子上彷佛有規律放了兩種顏色的球,說:」你用一根棍分開它們?要求:儘可能在放更多球以後,仍然適用。」java

而後魔鬼,又在桌上放了更多的球,彷佛有一個球站錯了陣營。顯然,大俠須要對棍作出調整。node

 

SVM就是試圖把棍放在最佳位置,好讓在棍的兩邊有儘量大的間隙。這個間隙就是球到棍的距離。python

 

如今好了,即便魔鬼放了更多的球,棍仍然是一個好的分界線。jquery

 

魔鬼看到大俠已經學會了一個trick(方法、招式),因而魔鬼給了大俠一個新的挑戰。linux

 

如今,大俠沒有棍能夠很好幫他分開兩種球了,如今怎麼辦呢?固然像全部武俠片中同樣大俠桌子一拍,球飛到空中。而後,憑藉大俠的輕功,大俠抓起一張紙,插到了兩種球的中間。android

如今,從空中的魔鬼的角度看這些球,這些球看起來像是被一條曲線分開了。

 

 
再以後,無聊的大人們,把這些球叫作 data,把棍子叫作 classifier, 找到最大間隙的trick叫作 optimization,拍桌子叫作 kernelling, 那張紙叫作 hyperplane
 

概述一下:

當一個分類問題,數據是線性可分的,也就是用一根棍就能夠將兩種小球分開的時候,咱們只要將棍的位置放在讓小球距離棍的距離最大化的位置便可,尋找這個最大間隔的過程,就叫作最優化。可是,現實每每是很殘酷的,通常的數據是線性不可分的,也就是找不到一個棍將兩種小球很好的分類。這個時候,咱們就須要像大俠同樣,將小球拍起,用一張紙代替小棍將小球進行分類。想要讓數據飛起,咱們須要的東西就是核函數(kernel),用於切分小球的紙,就是超平面。

也許這個時候,你仍是似懂非懂,不要緊。根據剛纔的描述,能夠看出,問題是從線性可分延伸到線性不可分的。那麼,咱們就按照這個思路,進行原理性的剖析。

2、線性SVM

先看下線性可分的二分類問題。

 

上圖中的(a)是已有的數據,紅色和藍色分別表明兩個不一樣的類別。數據顯然是線性可分的,可是將兩類數據點分開的直線顯然不止一條。上圖的(b)和(c)分別給出了B、C兩種不一樣的分類方案,其中黑色實線爲分界線,術語稱爲「決策面」。每一個決策面對應了一個線性分類器。雖然從分類結果上看,分類器A和分類器B的效果是相同的。可是他們的性能是有差距的,看下圖:

 

在」決策面」不變的狀況下,我又添加了一個紅點。能夠看到,分類器B依然能很好的分類結果,而分類器C則出現了分類錯誤。顯然分類器B的」決策面」放置的位置優於分類器C的」決策面」放置的位置,SVM算法也是這麼認爲的,它的依據就是分類器B的分類間隔比分類器C的分類間隔大。這裏涉及到第一個SVM獨有的概念」分類間隔」。在保證決策面方向不變且不會出現錯分樣本的狀況下移動決策面,會在原來的決策面兩側找到兩個極限位置(越過該位置就會產生錯分現象),如虛線所示。虛線的位置由決策面的方向和距離原決策面最近的幾個樣本的位置決定。而這兩條平行虛線正中間的分界線就是在保持當前決策面方向不變的前提下的最優決策面。兩條虛線之間的垂直距離就是這個最優決策面對應的分類間隔。顯然每個可能把數據集正確分開的方向都有一個最優決策面(有些方向不管如何移動決策面的位置也不可能將兩類樣本徹底分開),而不一樣方向的最優決策面的分類間隔一般是不一樣的,那個具備「最大間隔」的決策面就是SVM要尋找的最優解。而這個真正的最優解對應的兩側虛線所穿過的樣本點,就是SVM中的支持樣本點,稱爲」支持向量」。

1 數學建模

求解這個」決策面」的過程,就是最優化。一個最優化問題一般有兩個基本的因素:1)目標函數,也就是你但願什麼東西的什麼指標達到最好;2)優化對象,你指望經過改變哪些因素來使你的目標函數達到最優。在線性SVM算法中,目標函數顯然就是那個」分類間隔」,而優化對象則是決策面。因此要對SVM問題進行數學建模,首先要對上述兩個對象(」分類間隔」和」決策面」)進行數學描述。按照通常的思惟習慣,咱們先描述決策面。

數學建模的時候,先在二維空間建模,而後再推廣到多維。

(1)」決策面」方程

咱們都知道二維空間下一條直線的方式以下所示:

如今咱們作個小小的改變,讓原來的x軸變成x1,y軸變成x2。

移項得:

將公式向量化得:

進一步向量化,用w列向量和x列向量和標量γ進一步向量化:

其中,向量w和x分別爲:

這裏w1=a,w2=-1。咱們都知道,最初的那個直線方程a和b的幾何意義,a表示直線的斜率,b表示截距,a決定了直線與x軸正方向的夾角,b決定了直線與y軸交點位置。那麼向量化後的直線的w和r的幾何意義是什麼呢?

如今假設:

可得:

在座標軸上畫出直線和向量w:

藍色的線表明向量w,紅色的先表明直線y。咱們能夠看到向量w和直線的關係爲垂直關係。這說明了向量w也控制這直線的方向,只不過是與這個直線的方向是垂直的。標量γ的做用也沒有變,依然決定了直線的截距。此時,咱們稱w爲直線的法向量。

二維空間的直線方程已經推導完成,將其推廣到n爲空間,就變成了超平面方程。(一個超平面,在二維空間的例子就是一個直線)可是它的公式沒變,依然是:

 

不一樣之處在於:

咱們已經順利推導出了」決策面」方程,它就是咱們的超平面方程,以後,咱們統稱其爲超平面方程。

(2)」分類間隔」方程

如今,咱們依然對於一個二維平面的簡單例子進行推導。

咱們已經知道間隔的大小實際上就是支持向量對應的樣本點到決策面的距離的二倍。那麼圖中的距離d咱們怎麼求?咱們高中都學過,點到直線的距離距離公式以下:

公式中的直線方程爲Ax0+By0+C=0,點P的座標爲(x0,y0)。

如今,將直線方程擴展到多維,求得咱們如今的超平面方程,對公式進行以下變形:

這個d就是」分類間隔」。其中||w||表示w的二範數,求全部元素的平方和,而後再開方。好比對於二維平面:

那麼,

咱們目的是爲了找出一個分類效果好的超平面做爲分類器。分類器的好壞的評定依據是分類間隔W=2d的大小,即分類間隔W越大,咱們認爲這個超平面的分類效果越好。此時,求解超平面的問題就變成了求解分類間隔W最大化的爲題。W的最大化也就是d最大化的。

(3)約束條件

看起來,咱們已經順利得到了目標函數的數學形式。可是爲了求解w的最大值。咱們不得不面對以下問題:

  • 咱們如何判斷超平面是否將樣本點正確分類?
  • 咱們知要求距離d的最大值,咱們首先須要找到支持向量上的點,怎麼在衆多的點中選出支持向量上的點呢?

上述咱們須要面對的問題就是約束條件,也就是說咱們優化的變量d的取值範圍受到了限制和約束。事實上約束條件一直是最優化問題裏最讓人頭疼的東西。但既然咱們已經知道了這些約束條件確實存在,就不得不用數學語言對他們進行描述。但SVM算法經過一些巧妙的小技巧,將這些約束條件融合到一個不等式裏面。

這個二維平面上有兩種點,咱們分別對它們進行標記:

  • 紅顏色的圓點標記爲1,咱們人爲規定其爲正樣本;
  • 藍顏色的五角星標記爲-1,咱們人爲規定其爲負樣本。

對每一個樣本點xi加上一個類別標籤yi:

若是咱們的超平面方程可以徹底正確地對上圖的樣本點進行分類,就會知足下面的方程:

若是咱們要求再高一點,假設決策面正好處於間隔區域的中軸線上,而且相應的支持向量對應的樣本點到決策面的距離爲d,那麼公式進一步寫成:

上述公式的解釋就是,對於全部分類標籤爲1的樣本點,它們到直線的距離都大於等於d(支持向量上的樣本點到超平面的距離)。對於全部分類標籤爲-1的樣本點,它們到直線的距離都小於等於d。公式兩邊都除以d,就能夠獲得:

其中,

由於||w||和d都是標量。所上述公式的兩個矢量,依然描述一條直線的法向量和截距。

上述兩個公式,都是描述一條直線,數學模型表明的意義是同樣的。如今,讓咱們對wd和γd從新起個名字,就叫它們w和γ。所以,咱們就能夠說:」對於存在分類間隔的兩類樣本點,咱們必定能夠找到一些超平面面,使其對於全部的樣本點均知足下面的條件:」

上述方程即給出了SVM最優化問題的約束條件。這時候,可能有人會問了,爲何標記爲1和-1呢?由於這樣標記方便咱們將上述方程變成以下形式:

正是由於標籤爲1和-1,才方便咱們將約束條件變成一個約束方程,從而方便咱們的計算。

 

(4)線性SVM優化問題基本描述

如今整合一下思路,咱們已經獲得咱們的目標函數:

咱們的優化目標是是d最大化。咱們已經說過,咱們是用支持向量上的樣本點求解d的最大化的問題的。那麼支持向量上的樣本點有什麼特色呢?

咱們的優化目標是是d最大化。咱們已經說過,咱們是用支持向量上的樣本點求解d的最大化的問題的。那麼支持向量上的樣本點有什麼特色呢?

你贊同這個觀點嗎?全部支持向量上的樣本點,都知足如上公式。若是不贊同,請重看」分類間隔」方程推導過程。

如今咱們就能夠將咱們的目標函數進一步化簡:

由於,咱們只關心支持向量上的點。隨後咱們求解d的最大化問題變成了||w||的最小化問題。進而||w||的最小化問題等效於

爲何要作這樣的等效呢?這是爲了在進行最優化的過程當中對目標函數求導時比較方便,但這絕對不影響最優化問題最後的求解。咱們將最終的目標函數和約束條件放在一塊兒進行描述:

這裏n是樣本點的總個數,縮寫s.t.表示」Subject to」,是」服從某某條件」的意思。上述公式描述的是一個典型的不等式約束條件下的二次型函數優化問題,同時也是支持向量機的基本數學模型。

(5)求解準備

咱們已經獲得支持向量機的基本數學模型,接下來的問題就是如何根據數學模型,求得咱們想要的最優解。在學習求解方法以前,咱們得知道一點,想用我下面講述的求解方法有一個前提,就是咱們的目標函數必須是凸函數。理解凸函數,咱們還要先明確另外一個概念,凸集。在凸幾何中,凸集(convex set)是在)凸組合下閉合的放射空間的子集。看一幅圖可能更容易理解:

左右量圖都是一個集合。若是集合中任意2個元素連線上的點也在集合中,那麼這個集合就是凸集。顯然,上圖中的左圖是一個凸集,上圖中的右圖是一個非凸集。

凸函數的定義也是如此,其幾何意義表示爲函數任意兩點連線上的值大於對應自變量處的函數值。若這裏凸集C即某個區間L,那麼,設函數f爲定義在區間L上的函數,若對L上的任意兩點x1,x2和任意的實數λ,λ屬於(0,1),總有:

則函數f稱爲L上的凸函數,當且僅當其上鏡圖(在函數圖像上方的點集)爲一個凸集。再看一幅圖,也許更容易理解:

像上圖這樣的函數,它總體就是一個非凸函數,咱們沒法得到全局最優解的,只能得到局部最優解。好比紅框內的部分,若是單獨拿出來,它就是一個凸函數。對於咱們的目標函數:

很顯然,它是一個凸函數。因此,可使用我接下來說述的方法求取最優解。

一般咱們須要求解的最優化問題有以下幾類:

  • 無約束優化問題,能夠寫爲:
  • 有等式約束的優化問題,能夠寫爲:
  • 有不等式約束的優化問題,能夠寫爲:

對於第(a)類的優化問題,嚐嚐使用的方法就是費馬大定理(Fermat),即便用求取函數f(x)的導數,而後令其爲零,能夠求得候選最優值,再在這些候選值中驗證;若是是凸函數,能夠保證是最優解。這也就是咱們高中常用的求函數的極值的方法。

對於第(b)類的優化問題,經常使用的方法就是拉格朗日乘子法(Lagrange Multiplier) ,即把等式約束h_i(x)用一個係數與f(x)寫爲一個式子,稱爲拉格朗日函數,而係數稱爲拉格朗日乘子。經過拉格朗日函數對各個變量求導,令其爲零,能夠求得候選值集合,而後驗證求得最優值。

對於第(c)類的優化問題,經常使用的方法就是KKT條件。一樣地,咱們把全部的等式、不等式約束與f(x)寫爲一個式子,也叫拉格朗日函數,係數也稱拉格朗日乘子,經過一些條件,能夠求出最優值的必要條件,這個條件稱爲KKT條件。

必要條件和充要條件若是不理解,能夠看下面這句話:

  • A的必要條件就是A能夠推出的結論
  • A的充分條件就是能夠推出A的前提

瞭解到這些,如今讓咱們再看一下咱們的最優化問題:

如今,咱們的這個對優化問題屬於哪一類?很顯然,它屬於第(c)類問題。由於,在學習求解最優化問題以前,咱們還要學習兩個東西:拉格朗日函數和KKT條件。

(6)拉格朗日函數

首先,咱們先要從宏觀的視野上了解一下拉格朗日對偶問題出現的緣由和背景。

咱們知道咱們要求解的是最小化問題,因此一個直觀的想法是若是我可以構造一個函數,使得該函數在可行解區域內與原目標函數徹底一致,而在可行解區域外的數值很是大,甚至是無窮大,那麼這個沒有約束條件的新目標函數的優化問題就與原來有約束條件的原始目標函數的優化問題是等價的問題。這就是使用拉格朗日方程的目的,它將約束條件放到目標函數中,從而將有約束優化問題轉換爲無約束優化問題。

隨後,人們又發現,使用拉格朗日得到的函數,使用求導的方法求解依然困難。進而,須要對問題再進行一次轉換,即便用一個數學技巧:拉格朗日對偶

因此,顯而易見的是,咱們在拉格朗日優化咱們的問題這個道路上,須要進行下面二個步驟

  • 將有約束的原始目標函數轉換爲無約束的新構造的拉格朗日目標函數
  • 使用拉格朗日對偶性,將不易求解的優化問題轉化爲易求解的優化

下面,進行第一步:將有約束的原始目標函數轉換爲無約束的新構造的拉格朗日目標函數

公式變形以下:

其中αi是拉格朗日乘子,αi大於等於0,是咱們構造新目標函數時引入的係數變量(咱們本身設置)。如今咱們令:

當樣本點不知足約束條件時,即在可行解區域外:

 

 

此時,咱們將αi設置爲正無窮,此時θ(w)顯然也是正無窮。

當樣本點知足約束條件時,即在可行解區域內:

 

此時,顯然θ(w)爲原目標函數自己。咱們將上述兩種狀況結合一下,就獲得了新的目標函數:

當樣本點知足約束條件時,即在可行解區域內:

 

 

 

 

此時,顯然θ(w)爲原目標函數自己。咱們將上述兩種狀況結合一下,就獲得了新的目標函數:

 

時,再看咱們的初衷,就是爲了創建一個在可行解區域內與原目標函數相同,在可行解區域外函數值趨近於無窮大的新函數,如今咱們作到了。

 

如今,咱們的問題變成了求新目標函數的最小值,即:

這裏用p*表示這個問題的最優值,且和最初的問題是等價的。

 

接下來,咱們進行第二步:將不易求解的優化問題轉化爲易求解的優化

咱們看一下咱們的新目標函數,先求最大值,再求最小值。這樣的話,咱們首先就要面對帶有須要求解的參數w和b的方程,而αi又是不等式約束,這個求解過程很差作。因此,咱們須要使用拉格朗日函數對偶性,將最小和最大的位置交換一下,這樣就變成了:

 

交換之後的新問題是原始問題的對偶問題,這個新問題的最優值用d*來表示。並且d*<=p*。咱們關心的是d=p的時候,這纔是咱們要的解。須要什麼條件才能讓d=p呢?

  • 首先必須知足這個優化問題是凸優化問題。
  • 其次,須要知足KKT條件。

凸優化問題的定義是:求取最小值的目標函數爲凸函數的一類優化問題。目標函數是凸函數咱們已經知道,這個優化問題又是求最小值。因此咱們的最優化問題就是凸優化問題。

接下里,就是探討是否知足KKT條件了。

(7)KKT條件

咱們已經使用拉格朗日函數對咱們的目標函數進行了處理,生成了一個新的目標函數。經過一些條件,能夠求出最優值的必要條件,這個條件就是接下來要說的KKT條件。一個最優化模型可以表示成下列標準形式:

KKT條件的全稱是Karush-Kuhn-Tucker條件,KKT條件是說最優值條件必須知足如下條件:

  • 條件一:通過拉格朗日函數處理以後的新目標函數L(w,b,α)對α求導爲零:
  • 條件二:h(x) = 0;
  • 條件三:α*g(x) = 0;

對於咱們的優化問題:

顯然,條件二已經知足了。另外兩個條件爲啥也知足呢?

這裏原諒我省略一系列證實步驟,感興趣的能夠移步這裏:http://blog.csdn.net/xianlingmao/article/details/7919597

這裏已經給出了很好的解釋。如今,凸優化問題和KKT都知足了,問題轉換成了對偶問題。而求解這個對偶學習問題,能夠分爲三個步驟:首先要讓L(w,b,α)關於w和b最小化,而後求對α的極大,最後利用SMO算法求解對偶問題中的拉格朗日乘子。

(8)對偶問題求解

第一步:

根據上述推導已知:

首先固定α,要讓L(w,b,α)關於w和b最小化,咱們分別對w和b偏導數,令其等於0,即:

將上述結果帶回L(w,b,α)獲得:

從上面的最後一個式子,咱們能夠看出,此時的L(w,b,α)函數只含有一個變量,即αi。

第二步:

如今內側的最小值求解完成,咱們求解外側的最大值,從上面的式子獲得

 

 

如今咱們的優化問題變成了如上的形式。對於這個問題,咱們有更高效的優化算法,即序列最小優化(SMO)算法。咱們經過這個優化算法能獲得α,再根據α,咱們就能夠求解出w和b,進而求得咱們最初的目的:找到超平面,即」決策平面」。

總結一句話:咱們爲啥使出吃奶的勁兒進行推導?由於咱們要將最初的原始問題,轉換到可使用SMO算法求解的問題,這是一種最流行的求解方法。爲啥用這種求解方法?由於它牛逼啊!

 

2 SMO算法

如今,咱們已經獲得了能夠用SMO算法求解的目標函數,可是對於怎麼編程實現SMO算法仍是感受無從下手。那麼如今就聊聊如何使用SMO算法進行求解。

 

(1)Platt的SMO算法

1996年,John Platt發佈了一個稱爲SMO的強大算法,用於訓練SVM。SM表示序列最小化(Sequential Minimal Optimizaion)。Platt的SMO算法是將大優化問題分解爲多個小優化問題來求解的。這些小優化問題每每很容易求解,而且對它們進行順序求解的結果與將它們做爲總體來求解的結果徹底一致的。在結果徹底相同的同時,SMO算法的求解時間短不少。

 

SMO算法的目標是求出一系列alpha和b,一旦求出了這些alpha,就很容易計算出權重向量w並獲得分隔超平面。

SMO算法的工做原理是:每次循環中選擇兩個alpha進行優化處理。一旦找到了一對合適的alpha,那麼就增大其中一個同時減少另外一個。這裏所謂的」合適」就是指兩個alpha必須符合如下兩個條件,條件之一就是兩個alpha必需要在間隔邊界以外,並且第二個條件則是這兩個alpha尚未進進行過區間化處理或者不在邊界上。

(2)SMO算法的解法

先來定義特徵到結果的輸出函數爲:

 

接着,咱們回憶一下原始優化問題,以下:

求導得:

將上述公式帶入輸出函數中:

與此同時,拉格朗日對偶後獲得最終的目標化函數:

 

將目標函數變形,在前面增長一個符號,將最大值問題轉換成最小值問題:

 實際上,對於上述目標函數,是存在一個假設的,即數據100%線性可分。可是,目前爲止,咱們知道幾乎全部數據都不那麼」乾淨」。這時咱們就能夠經過引入所謂的鬆弛變量(slack variable),來容許有些數據點能夠處於超平面的錯誤的一側。這樣咱們的優化目標就能保持仍然不變,可是此時咱們的約束條件有所改變:

 

根據KKT條件能夠得出其中αi取值的意義爲:

  • 對於第1種狀況,代表αi是正常分類,在邊界內部;
  • 對於第2種狀況,代表αi是支持向量,在邊界上;
  • 對於第3種狀況,代表αi是在兩條邊界之間。

而最優解須要知足KKT條件,即上述3個條件都得知足,如下幾種狀況出現將會不知足:

也就是說,若是存在不能知足KKT條件的αi,那麼須要更新這些αi,這是第一個約束條件。此外,更新的同時還要受到第二個約束條件的限制,即:

由於這個條件,咱們同時更新兩個α值,由於只有成對更新,才能保證更新以後的值仍然知足和爲0的約束,假設咱們選擇的兩個乘子爲α1和α2:

其中, ksi爲常數。由於兩個因子很差同時求解,因此能夠先求第二個乘子α2的解(α2 new),獲得α2的解(α2 new)以後,再用α2的解(α2 new)表示α1的解(α1 new )。爲了求解α2 new ,得先肯定α2 new的取值範圍。假設它的上下邊界分別爲H和L,那麼有:

接下來,綜合下面兩個條件:

當y1不等於y2時,即一個爲正1,一個爲負1的時候,能夠獲得:

因此有:

此時,取值範圍以下圖所示:

當y1等於y2時,即兩個都爲正1或者都爲負1,能夠獲得:

因此有:

此時,取值範圍以下圖所示:

如此,根據y1和y2異號或同號,能夠得出α2 new的上下界分別爲:

這個界限就是編程的時候須要用到的。已經肯定了邊界,接下來,就是推導迭代式,用於更新 α值。

咱們已經知道,更新α的邊界,接下來就是討論如何更新α值。咱們依然假設選擇的兩個乘子爲α1和α2。固定這兩個乘子,進行推導。因而目標函數變成了:

爲了描述方便,咱們定義以下符號:

最終目標函數變爲:

咱們不關心constant的部分,由於對於α1和α2來講,它們都是常數項,在求導的時候,直接變爲0。對於這個目標函數,若是對其求導,還有個未知數α1,因此要推導出α1和α2的關係,而後用α2代替α1,這樣目標函數就剩一個未知數了,咱們就能夠求導了,推導出迭代公式。因此如今繼續推導α1和α2的關係。注意第一個約束條件:

咱們在求α1和α2的時候,能夠將α3,α4,…,αn和y3,y4,…,yn看做常數項。所以有:

咱們沒必要關心常數B的大小,如今將上述等式兩邊同時乘以y1,獲得(y1y1=1):

其中γ爲常數By1,咱們不關心這個值,s=y1y2。接下來,咱們將獲得的α1帶入W(α2)公式得:

這樣目標函數中就只剩下α2了,咱們對其求偏導(注意:s=y1y2,因此s的平方爲1,y1的平方和y2的平方均爲1):

繼續化簡,將s=y1y2帶入方程。

 

咱們令:

Ei爲偏差項,η爲學習速率。

再根據咱們已知的公式:

將α2 new繼續化簡得:

這樣,咱們就獲得了最終須要的迭代公式。這個是沒有通過剪輯是的解,須要考慮約束:

 

根據以前推導的α取值範圍,咱們獲得最終的解析解爲:

又由於:

消去γ得:

 

 

 

 

這樣,咱們就知道了怎樣計算α1和α2了,也就是如何對選擇的α進行更新。

當咱們更新了α1和α2以後,須要從新計算閾值b,由於b關係到了咱們f(x)的計算,也就關係到了偏差Ei的計算。

咱們要根據α的取值範圍,去更正b的值,使間隔最大化。當α1 new在0和C之間的時候,根據KKT條件可知,這個點是支持向量上的點。所以,知足下列公式:

公式兩邊同時乘以y1得(y1y1=1):

由於咱們是根據α1和α2的值去更新b,因此單獨提出i=1和i=2的時候,整理可得:

其中前兩項爲:

將上述兩個公式,整理得:

同理可得b2 new爲:

當b1和b2都有效的時候,它們是相等的,即:

當兩個乘子都在邊界上,則b閾值和KKT條件一致。當不知足的時候,SMO算法選擇他們的中點做爲新的閾值:

最後,更新全部的α和b,這樣模型就出來了,從而便可求出咱們的分類函數。

如今,讓咱們梳理下SMO算法的步驟:

  • 步驟1:計算偏差: 
  • 步驟2:計算上下界L和H: 
  • 步驟3:計算η: 
  • 步驟4:更新αj: 
  • 步驟5:根據取值範圍修剪αj: 
  • 步驟6:更新αi: 
  • 步驟7:更新b1和b2: 
    • 步驟8:根據b1和b2更新b:

http://www.javashuo.com/article/p-kzozlmtg-r.html

 https://blog.csdn.net/weixin_33897722/article/details/87428844

 

 

 

 

 

 

 

 

 

In [1]:
from sklearn import svm
In [2]:
X = [[2, 0], [1, 1], [2, 3]]
y = [0, 0, 1]
clf = svm.SVC(kernel="linear")
clf.fit(X, y)
print(clf)
 
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
  kernel='linear', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)
In [3]:
print(clf.support_vectors_)  # 支持向量
 
[[1. 1.]
 [2. 3.]]
In [4]:
print(clf.support_)  # 支持向量所在的下標
 
[1 2]
In [5]:
print(clf.n_support_)  # 左右支持向量分別有幾個
 
[1 1]
In [6]:
print(clf.predict([[2, 0]]))  # 須要傳入一個二維數組
 
[0]
In [7]:
print(clf.predict([[2, 0.1],
                   [3, 0]]))
 
[0 0]
In [9]:
import numpy as np
import pylab as pl
from sklearn import svm
In [10]:
np.random.seed(0)
# we create 40 separable points
X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]]
In [11]:
X
Out[11]:
array([[-0.23594765, -1.59984279],
       [-1.02126202,  0.2408932 ],
       [-0.13244201, -2.97727788],
       [-1.04991158, -2.15135721],
       [-2.10321885, -1.5894015 ],
       [-1.85595643, -0.54572649],
       [-1.23896227, -1.87832498],
       [-1.55613677, -1.66632567],
       [-0.50592093, -2.20515826],
       [-1.6869323 , -2.85409574],
       [-4.55298982, -1.3463814 ],
       [-1.1355638 , -2.74216502],
       [ 0.26975462, -3.45436567],
       [-1.95424148, -2.18718385],
       [-0.46722079, -0.53064123],
       [-1.84505257, -1.62183748],
       [-2.88778575, -3.98079647],
       [-2.34791215, -1.84365103],
       [-0.76970932, -0.79762015],
       [-2.38732682, -2.30230275],
       [ 0.95144703,  0.57998206],
       [ 0.29372981,  3.9507754 ],
       [ 1.49034782,  1.5619257 ],
       [ 0.74720464,  2.77749036],
       [ 0.38610215,  1.78725972],
       [ 1.10453344,  2.3869025 ],
       [ 1.48919486,  0.81936782],
       [ 1.97181777,  2.42833187],
       [ 2.06651722,  2.3024719 ],
       [ 1.36567791,  1.63725883],
       [ 1.32753955,  1.64044684],
       [ 1.18685372,  0.2737174 ],
       [ 2.17742614,  1.59821906],
       [ 0.36980165,  2.46278226],
       [ 1.09270164,  2.0519454 ],
       [ 2.72909056,  2.12898291],
       [ 3.13940068,  0.76517418],
       [ 2.40234164,  1.31518991],
       [ 1.12920285,  1.42115034],
       [ 1.68844747,  2.05616534]])
In [11]:
y = [0] * 20 + [1] * 20  # 標記
In [13]:
y
Out[13]:
[0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 0,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1,
 1]
In [14]:
# fit the model
clf = svm.SVC(kernel='linear')
clf.fit(X, y)
Out[14]:
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
  kernel='linear', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)
In [15]:
# get the separating hyperplane
w = clf.coef_[0]
w
Out[15]:
array([0.90230696, 0.64821811])
In [15]:
a = -w[0] / w[1]  # 斜率
xx = np.linspace(-5, 5, 100)
yy = a * xx - (clf.intercept_[0]) / w[1]  # clf.intercept_[0]是在0位置的截距,就是w【3
In [17]:
# plot the parallels to the separating hyperplane that pass through the support vectors
b = clf.support_vectors_[0]  # 第一個支持向量
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]  # 取最後一個向量
yy_up = a * xx + (b[1] - a * b[0])
In [18]:
print("support_vectors_: ", clf.support_vectors_)
print("clf.coef_: ", clf.coef_)
 
support_vectors_:  [[-1.02126202  0.2408932 ]
 [-0.46722079 -0.53064123]
 [ 0.95144703  0.57998206]]
clf.coef_:  [[0.90230696 0.64821811]]
In [19]:
pl.plot(xx, yy, 'k-')
pl.plot(xx, yy_down, 'k--')
pl.plot(xx, yy_up, 'k--')
pl.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
           s=100, facecolors='red')  # 畫出支持向量
pl.scatter(X[:, 0], X[:, 1], c=y, cmap=pl.cm.get_cmap('RdYlBu'))
pl.axis('tight')
pl.show()
 
相關文章
相關標籤/搜索