Python機(jī)器學(xué)習(xí)(五):SVM 支撐向量機(jī)

Jacob的 Python機(jī)器學(xué)習(xí)系列:
Python機(jī)器學(xué)習(xí)(一):kNN算法
Python機(jī)器學(xué)習(xí)(二):線性回歸算法
Python機(jī)器學(xué)習(xí)(三):梯度下降法
Python機(jī)器學(xué)習(xí)(四):PCA 主成分分析
Python機(jī)器學(xué)習(xí)(五):SVM 支撐向量機(jī)

這個(gè)系列拖了好久烫扼,當(dāng)然這段時(shí)間也不算荒廢吧塞关,主要是考試和各種課程設(shè)計(jì)的緣故茴扁,也接了一些小項(xiàng)目秒啦,所以機(jī)器學(xué)習(xí)這里就落下來了。現(xiàn)在基本所有事情都搞定了冈敛,所以一方面要趕緊把這個(gè)系列完結(jié)了贴唇,另一方面這個(gè)漫長假期(學(xué)校給我們放了兩個(gè)月的假丽柿。。蔗包。)也要給自己立一個(gè)大flag秉扑,趕緊把自己的能力提上去,畢竟下學(xué)期就要找實(shí)習(xí)了调限。OK舟陆,日常嘮叨完畢。

支撐向量機(jī)(Support Vector Machin耻矮,SVM)可以解決分類問題秦躯,也可以用于解決回歸問題。這里僅對分類問題進(jìn)行一些粗淺的討論淘钟。

感性理解

在分類問題中宦赠,分類算法會將數(shù)據(jù)空間劃分一個(gè)或多個(gè)決策邊界(高維時(shí)稱為超平面,為了簡化問題米母,這里僅對兩個(gè)特征的二分類問題進(jìn)行討論)勾扭,決策邊界的一邊是一類,另一邊是另一類铁瞒。了解邏輯回歸的應(yīng)該都能理解妙色。但是,不同的分類算法會對相同的數(shù)據(jù)生成不同的決策邊界慧耍。那么身辨,哪個(gè)決策邊界才是最好的呢丐谋?這個(gè)問題稱為不適定問題對于SVM來說,它的目的就是盡可能地找到一個(gè)合適的邊界煌珊,來提高算法的泛化能力号俐,即魯棒性。


不同的決策邊界

那么定庵,SVM的具體操作是:尋找一個(gè)最優(yōu)的決策邊界吏饿,距離兩個(gè)類別的最近的樣本最遠(yuǎn)。最近的樣本點(diǎn)稱為支撐向量蔬浙。當(dāng)然猪落,這里討論的是線性可分的問題。當(dāng)線性不可分的時(shí)候畴博,有改進(jìn)的方法笨忌,下文中會提到。


中間的直線就是SVM算法得到的決策邊界

Hard Margin SVM

上面的圖中俱病,樣本點(diǎn)是線性可分的官疲,即可以找到一條決策邊界使得分類不會出錯(cuò),這時(shí)候使用的SVM算法稱為Hard Magin SVM庶艾。此時(shí)的算法至少在訓(xùn)練集上是不會發(fā)生錯(cuò)誤的袁余。

感性理解之后就需要用數(shù)學(xué)語言來表達(dá)了≡圩幔回憶一下高中學(xué)的解析幾何颖榜,直線的一般式方程為

點(diǎn)到直線的距離為

那么拓展到n維空間中的話,可以寫成這種形式


同樣煤裙,距離公式為

我們定義類A的值為1掩完,類B的值為-1。在圖中可以看到硼砰,類A的支撐向量距離決策邊界的距離為d且蓬,類B上的支撐向量距離決策邊界的距離也為d。那么可以列寫這樣的方程


因?yàn)橄蛄?w 的模题翰,即方程左邊的分母為常數(shù)恶阴,距離 d 也為常數(shù),可以進(jìn)行這樣的簡化豹障,即 d 除過去并且換個(gè)符號冯事。下標(biāo)d說明截距和向量 w 已經(jīng)被 dw 的模相除。

因?yàn)槎x了類A的值為1血公,類B的值為-1昵仅,那么可以寫成一個(gè)式子

對于所有支撐向量,滿足這樣的方程

即求模的最小值。實(shí)際工程中為了求導(dǎo)得到最小值摔笤,使用的是第二個(gè)式子

所以總結(jié)下就是這個(gè)目標(biāo)够滑。下方的式子是求解條件


Soft Margin SVM

如果數(shù)據(jù)線性不可分,那么如果要使用SVM算法吕世,就需要允許分類算法犯一定的錯(cuò)誤彰触,具體方法是讓限定條件變得寬松一點(diǎn)



那么隨之,求解目標(biāo)也會有所改變命辖。C是一個(gè)超參數(shù)渴析。C趨向于0的時(shí)候,允許無限大的誤差吮龄,趨向于無窮大的時(shí)候,算法本質(zhì)就是Hard Margin SVM咆疗。


L1正則化

L2正則化

編程實(shí)現(xiàn)

要自己實(shí)現(xiàn)SVM比較麻煩漓帚,這里只用sciki-learn中提供的函數(shù)去實(shí)現(xiàn)。

"""
Created by 楊幫杰 on 12/24/2018
Right to use this code in any way you want without
warranty, support or any guarantee of it working
E-mail: yangbangjie1998@qq.com
Association: SCAU 華南農(nóng)業(yè)大學(xué)
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
from matplotlib.colors import ListedColormap

# 使用鳶尾花數(shù)據(jù)集
iris = datasets.load_iris()

X = iris.data
y = iris.target

# 只使用兩個(gè)特征和兩個(gè)種類
X = X[y < 2, :2]
y = y[y < 2]

# 歸一化尺度
standardScaler = StandardScaler()
standardScaler.fit(X)
X_standard = standardScaler.transform(X)

# hard margin SVM
svc = LinearSVC(C=1e9)
svc.fit(X_standard, y)


# 畫出決策邊界
def plot_decision_boundary(model, axis):

    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1] - axis[0])*100)).reshape(1, -1),
        np.linspace(axis[2], axis[3], int((axis[3] - axis[2])*100)).reshape(1, -1)
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]

    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)

    custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)


# 畫出svm決策邊界
def plot_svc_decision_boundary(model, axis):
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 100)).reshape(1, -1),
        np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 100)).reshape(1, -1)
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]

    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)

    custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)

    w = model.coef_[0]
    b = model.intercept_[0]

    # w0 * x0 + w1 * x1 + b = 0
    # => x1 = -w0/w1 * x0 - b/w1
    plot_x = np.linspace(axis[0], axis[1], 200)
    up_y = -w[0]/w[1] * plot_x - b/w[1] + 1/w[1]
    down_y = -w[0]/w[1] * plot_x - b/w[1] - 1/w[1]

    up_index = (up_y >= axis[2]) & (up_y <= axis[3])
    down_index = (down_y >= axis[2]) & (down_y <= axis[3])
    plt.plot(plot_x[up_index], up_y[up_index], color="black")
    plt.plot(plot_x[down_index], down_y[down_index], color="black")


# 顯示數(shù)據(jù)和分類情況
plot_decision_boundary(svc, axis=[-3, 3, -3, 3])
plt.scatter(X_standard[y == 0, 0], X_standard[y == 0, 1])
plt.scatter(X_standard[y == 1, 0], X_standard[y == 1, 1])
plt.show()

plot_svc_decision_boundary(svc, axis=[-3, 3, -3, 3])
plt.scatter(X_standard[y == 0, 0], X_standard[y == 0, 1])
plt.scatter(X_standard[y == 1, 0], X_standard[y == 1, 1])
plt.show()

# soft margin SVM
svc2 = LinearSVC(C=0.01)
svc2.fit(X_standard, y)

plot_svc_decision_boundary(svc2, axis=[-3, 3, -3, 3])
plt.scatter(X_standard[y == 0, 0], X_standard[y == 0, 1])
plt.scatter(X_standard[y == 1, 0], X_standard[y == 1, 1])
plt.show()

Hard Margin SVM的分類結(jié)果
兩條黑邊是經(jīng)過支撐向量上的直線

Soft Margin SVM

如果想使用多項(xiàng)式特征的SVM午磁,可以給數(shù)據(jù)添加多項(xiàng)式特征后使用LinearSVC

"""
Created by 楊幫杰 on 12/24/2018
Right to use this code in any way you want without
warranty, support or any guarantee of it working
E-mail: yangbangjie1998@qq.com
Association: SCAU 華南農(nóng)業(yè)大學(xué)
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from matplotlib.colors import ListedColormap

X, y = datasets.make_moons(noise=0.15, random_state=666)


def PolynomialSVC(degree, C=1.0):
    return Pipeline([
        ("poly", PolynomialFeatures(degree=degree)),
        ("std_scaler", StandardScaler()),
        ("linearSVC", LinearSVC(C=C))
    ])


poly_svc = PolynomialSVC(degree=3)
poly_svc.fit(X, y)


def plot_decision_boundary(model, axis):

    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1] - axis[0])*100)).reshape(1, -1),
        np.linspace(axis[2], axis[3], int((axis[3] - axis[2])*100)).reshape(1, -1)
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]

    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)

    custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)


plot_decision_boundary(poly_svc, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y == 0, 0], X[y == 0, 1])
plt.scatter(X[y == 1, 0], X[y == 1, 1])
plt.show()
帶多項(xiàng)式特征

在SVM實(shí)現(xiàn)中會使用核函數(shù)尝抖,它的目的是直接計(jì)算出兩者添加多項(xiàng)式特征之后的點(diǎn)乘,加快計(jì)算速度迅皇。并且昧辽,不同的核函數(shù),會對樣本點(diǎn)進(jìn)行不同的轉(zhuǎn)換登颓,得到不同的效果搅荞,比如高斯核函數(shù)(徑向基函數(shù))。這里不進(jìn)行討論框咙,讀者可以自行改變SVC函數(shù)中的kernel參數(shù)來進(jìn)行實(shí)驗(yàn)咕痛。

"""
Created by 楊幫杰 on 12/24/2018
Right to use this code in any way you want without
warranty, support or any guarantee of it working
E-mail: yangbangjie1998@qq.com
Association: SCAU 華南農(nóng)業(yè)大學(xué)
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from matplotlib.colors import ListedColormap
from sklearn.svm import SVC

X, y = datasets.make_moons(noise=0.15, random_state=666)

def plot_decision_boundary(model, axis):

    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1] - axis[0])*100)).reshape(1, -1),
        np.linspace(axis[2], axis[3], int((axis[3] - axis[2])*100)).reshape(1, -1)
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]

    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)

    custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D', '#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)


def PolynomialKernalSVC(degree, C=1.0):
    return Pipeline([
        ("std_scaler", StandardScaler()),
        ("kernelSVC", SVC(kernel="poly", degree=degree, C=C))
    ])


poly_kernel_svc = PolynomialKernalSVC(degree=3)
poly_kernel_svc.fit(X, y)

plot_decision_boundary(poly_kernel_svc, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y == 0, 0], X[y == 0, 1])
plt.scatter(X[y == 1, 0], X[y == 1, 1])
plt.show()

多項(xiàng)式核函數(shù)

References:
Python3 入門機(jī)器學(xué)習(xí) 經(jīng)典算法與應(yīng)用 —— liuyubobobo
機(jī)器學(xué)習(xí)實(shí)戰(zhàn) —— Peter Harrington

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市喇嘱,隨后出現(xiàn)的幾起案子茉贡,更是在濱河造成了極大的恐慌,老刑警劉巖者铜,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腔丧,死亡現(xiàn)場離奇詭異,居然都是意外死亡作烟,警方通過查閱死者的電腦和手機(jī)愉粤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俗壹,“玉大人科汗,你說我怎么就攤上這事”脸” “怎么了头滔?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵怖亭,是天一觀的道長。 經(jīng)常有香客問我坤检,道長兴猩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任早歇,我火速辦了婚禮倾芝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘箭跳。我一直安慰自己晨另,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布谱姓。 她就那樣靜靜地躺著借尿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屉来。 梳的紋絲不亂的頭發(fā)上路翻,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機(jī)與錄音茄靠,去河邊找鬼茂契。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慨绳,可吹牛的內(nèi)容都是我干的掉冶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼脐雪,長吁一口氣:“原來是場噩夢啊……” “哼郭蕉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喂江,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤召锈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后获询,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涨岁,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年吉嚣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梢薪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尝哆,死狀恐怖秉撇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤琐馆,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布规阀,位于F島的核電站,受9級特大地震影響瘦麸,放射性物質(zhì)發(fā)生泄漏谁撼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一滋饲、第九天 我趴在偏房一處隱蔽的房頂上張望厉碟。 院中可真熱鬧,春花似錦屠缭、人聲如沸箍鼓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袄秩。三九已至,卻和暖如春逢并,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背郭卫。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工砍聊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贰军。 一個(gè)月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓玻蝌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親词疼。 傳聞我的和親對象是個(gè)殘疾皇子俯树,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360