1. 程式人生 > 其它 >機器學習中最流行的模型之一,用於分類的支援向量機的完整介紹

機器學習中最流行的模型之一,用於分類的支援向量機的完整介紹

支援向量機(SVM)是一個非常強大而多變的機器學習模型,能夠執行線性或非線性的分類,迴歸,甚至異常值檢測。它是機器學習中最流行的模型之一,任何對機器學習感興趣的人都應該學習和使用它。SVM特別適用於複雜的中小型資料集分類。在這篇文章中,我們將探討用於分類的SVM模型。

線性SVM

假設我們有兩類資料,我們要使用SVM進行分類,如圖所示:

這兩個類別可以用直線(線性可分)輕鬆分離。左圖顯示了2個可能的線性分類器的決策邊界。所有的SVM模型都是為了生成將資料進行很好分類的正確分割線(稱為在更高維度中稱為超平面)。在左圖中,儘管紅線也對資料進行了分類,但在新的資料例項中可能無法很好地執行。我們可以畫出許多對這些資料進行分類的線,但是在所有這些線中,藍線分隔資料最好。同樣的藍線顯示在右圖。這條線(超平面)不僅分離了兩個類,還儘可能遠離最接近的訓練例項。你可以將SVM分類器視為在類之間擬合儘可能寬的街道(由右側圖上的平行虛線表示)。這被稱最大間隔分類器。

這個最好的決策邊界是由位於街道邊緣的例項決定(或者稱為“支援”)。這些例項稱為支援向量。街道邊緣的間距稱為間隔(margin)。

軟間隔分類器

如果我們嚴格要求我們的例項不得在“街道”上,並且修正街道的邊緣,這就是所謂的硬間隔分類。而硬邊緣分類有2個問題:

1)只有資料線性分離才有效。

2)對異常值太敏感。

在上面的資料分類圖中,有一個藍色的異常值。如果我們對該資料集應用硬間隔分類,我們將得到左邊圖所示的小間距的決策邊界。為了避免這些問題,最好使用更彈性的模型。目的是在保持街道盡可能大和不允許例項過界之間找到一個良好的平衡(就是說會出現例項最終可能在街道中間甚至道路另一面的情況)。這稱為軟間隔分類。如果我們對該資料集應用軟間隔分類,則我們將得到比硬間隔分類更大決策邊界。如右圖中所示。

非線性SVM

雖然線性SVM分類器能力不錯,在許多情況下都工作的很好,但是許多資料集無法進行線性分離。處理非線性資料集的一個簡單方法是新增更多的特徵,比如多項式特徵,有時這可以獲得線性可分的資料集。通過生成多項式特徵,我們將得到新的特徵矩陣,它由具有小於或等於指定度的所有多項式組合的特徵。下圖是SVM使用多項式特徵的示例。

核技巧

核(Kernel)是在一些特徵空間中計算兩個向量x和y點積的一種方法(特徵空間可能有非常高的維度),所以核函式有時被稱為“廣義點積(generalized dot product)”。

假設我們有一個對映 φ:Rn→Rm向量Rn到特徵空間Rm的對映。x和y的內積空間是φ(x)Tφ(y)。核是一個對應於這個點積k的函式,也就是k(x,y)=φ(x)Tφ(y)。核提供了在一些特徵空間內計算點積的方法,你甚至可以不知道這個空間和φ是什麼。

多項式核函式

新增多項式特徵非常簡單。但是低度多項式無法處理複雜的資料集,並且具有較高的多項式度它會產生大量的特徵,讓模型變得特別慢。在這種情況下,我們可以使用多項式核函式解決這個問題。多項式核函式公式如下:

d是多項式的度。

高斯核函式

高斯RBF(徑向基函式)是SVM模型中使用的另一種流行的核函式。它的公式如下:

如果我們有如下的資料集,則高斯核函式非常有用。

超引數

在SVM模型中有2個重要的超引數。

C引數

C引數決定SVM分類器的邊距寬度。C的值越越大分類器越嚴格,因此邊距寬度小。對於較大的C值,如果該超平面更好地將所有訓練點歸類正確,則該模型將選擇較小邊距的超平面。相反,C的非常小的值將導致模型尋找更大的邊距分離超平面,即使這個超平面錯誤的分類了更多的點。如果C值非常小,你會得到錯誤分類的例項,即使你的訓練資料是線性可分的。

γ引數

該γ引數定義了每個訓練例項的影響能力。γ引數對scikit-learn中的線性核函式是無效的。

使用scikit-learn實現

在這部分中,我們將使用scikit-learn來實現SVM。

線性核函式

import numpy as np
import pandas as pd
from matplotlibimport style
from sklearn.svmimport SVC
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize']= (12,6)
style.use('ggplot')

# Import Dataset
data= pd.read_csv('data.csv', header=None)
X= data.values[:, :2]
y= data.values[:,2]

# A function to draw hyperplane and the margin of SVM classifier
def draw_svm(X, y, C=1.0):
    # Plotting the Points
    plt.scatter(X[:,0], X[:,1], c=y)

    # The SVM Model with given C parameter
    clf= SVC(kernel='linear', C=C)
    clf_fit= clf.fit(X, y)

    # Limit of the axes
    ax= plt.gca()
    xlim= ax.get_xlim()
    ylim= ax.get_ylim()

    # Creating the meshgrid
    xx= np.linspace(xlim[0], xlim[1],200)
    yy= np.linspace(ylim[0], ylim[1],200)
    YY, XX= np.meshgrid(yy, xx)
    xy= np.vstack([XX.ravel(), YY.ravel()]).T
    Z= clf.decision_function(xy).reshape(XX.shape)

    # Plotting the boundary
    ax.contour(XX, YY, Z, colors='k', levels=[-1,0,1],
                        alpha=0.5, linestyles=['--','-','--'])
    ax.scatter(clf.support_vectors_[:,0],
                clf.support_vectors_[:,1],
                s=100, linewidth=1, facecolors='none')
    plt.show()
    # Returns the classifier
    return clf_fit

clf_arr= []
clf_arr.append(draw_svm(X, y,0.0001))
clf_arr.append(draw_svm(X, y,0.001))
clf_arr.append(draw_svm(X, y,1))
clf_arr.append(draw_svm(X, y,10))

for i, clfin enumerate(clf_arr):
    # Accuracy Score
    print(clf.score(X, y))
    pred= clf.predict([(12,32), (-250,32), (120,43)])
    print(pred)
0.992907801418
[1 0 1]
0.992907801418
[1 0 1]
1.0
[1 0 1]
1.0
[1 0 1]

你能看到相同超平面具有不同邊距寬度。這取決於C超引數。

多項式核函式

import numpy as np
import pandas as pd
from matplotlibimport style
from sklearn.svmimport SVC
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize']= (12,6)
style.use('ggplot')

data= pd.read_csv('polydata2.csv', header=None)
X= data.values[:, :2]
y= data.values[:,2]

def draw_svm(X, y, C=1.0):
    plt.scatter(X[:,0], X[:,1], c=y)
    clf= SVC(kernel='poly', C=C)
    clf_fit= clf.fit(X, y)

    ax= plt.gca()
    xlim= ax.get_xlim()
    ylim= ax.get_ylim()

    xx= np.linspace(xlim[0], xlim[1],200)
    yy= np.linspace(ylim[0], ylim[1],200)
    YY, XX= np.meshgrid(yy, xx)
    xy= np.vstack([XX.ravel(), YY.ravel()]).T
    Z= clf.decision_function(xy).reshape(XX.shape)

    ax.contour(XX, YY, Z, colors='k', levels=[-1,0,1],
                        alpha=0.5, linestyles=['--','-','--'])
    ax.scatter(clf.support_vectors_[:,0],
                clf.support_vectors_[:,1],
                s=100, linewidth=1, facecolors='none')
    plt.show()
    return clf_fit

clf= draw_svm(X, y)
score= clf.score(X, y)
pred= clf.predict([(-130,110), (-170,-160), (80,90), (-280,20)])
print(score)
print(pred)
1.0
[0 1 0 1]

高斯核函式

import numpy as np
import pandas as pd
from matplotlibimport style
from sklearn.svmimport SVC
from sklearn.datasetsimport make_classification, make_blobs, make_moons
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize']= (12,6)
style.use('ggplot')

X, y= make_moons(n_samples=200)

# Auto gamma equals 1/n_features
def draw_svm(X, y, C=1.0, gamma='auto'):
    plt.scatter(X[:,0], X[:,1], c=y)
    clf= SVC(kernel='rbf', C=C, gamma=gamma)
    clf_fit= clf.fit(X, y)

    ax= plt.gca()
    xlim= ax.get_xlim()
    ylim= ax.get_ylim()

    xx= np.linspace(xlim[0], xlim[1],200)
    yy= np.linspace(ylim[0], ylim[1],200)
    YY, XX= np.meshgrid(yy, xx)
    xy= np.vstack([XX.ravel(), YY.ravel()]).T
    Z= clf.decision_function(xy).reshape(XX.shape)

    ax.contour(XX, YY, Z, colors='k', levels=[-1,0,1],
                        alpha=0.5, linestyles=['--','-','--'])
    ax.scatter(clf.support_vectors_[:,0],
                clf.support_vectors_[:,1],
                s=100, linewidth=1, facecolors='none')
    plt.show()
    return clf_fit

clf_arr= []
clf_arr.append(draw_svm(X, y,0.01))
clf_arr.append(draw_svm(X, y,0.1))
clf_arr.append(draw_svm(X, y,1))
clf_arr.append(draw_svm(X, y,10))

for i, clfin enumerate(clf_arr):
    print(clf.score(X, y))
0.83
0.9
1.0
1.0
import numpy as np
import pandas as pd
from matplotlibimport style
from sklearn.svmimport SVC
from sklearn.datasetsimport make_gaussian_quantiles
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize']= (12,6)
style.use('ggplot')

X, y= make_gaussian_quantiles(n_samples=200, n_features=2, n_classes=2, cov=3)

# Auto gamma equals 1/n_features
def draw_svm(X, y, C=1.0, gamma='auto'):
    plt.scatter(X[:,0], X[:,1], c=y)
    clf= SVC(kernel='rbf', C=C, gamma=gamma)
    clf_fit= clf.fit(X, y)

    ax= plt.gca()
    xlim= ax.get_xlim()
    ylim= ax.get_ylim()

    xx= np.linspace(xlim[0], xlim[1],200)
    yy= np.linspace(ylim[0], ylim[1],200)
    YY, XX= np.meshgrid(yy, xx)
    xy= np.vstack([XX.ravel(), YY.ravel()]).T
    Z= clf.decision_function(xy).reshape(XX.shape)

    ax.contour(XX, YY, Z, colors='k', levels=[-1,0,1],
                        alpha=0.5, linestyles=['--','-','--'])
    ax.scatter(clf.support_vectors_[:,0],
                clf.support_vectors_[:,1],
                s=100, linewidth=1, facecolors='none')
    plt.show()
    return clf_fit

clf_arr= []
clf_arr.append(draw_svm(X, y,0.1))
clf_arr.append(draw_svm(X, y,1))
clf_arr.append(draw_svm(X, y,10))
clf_arr.append(draw_svm(X, y,100))

for i, clfin enumerate(clf_arr):
    print(clf.score(X, y))
0.965
0.97
0.985
0.995

γ引數對RBF SVM模型非常重要。在第一個例子中,低的γ值導致了出現接近線性分類。

你可以在下面的連結中檢視程式碼示例和資料集。

https://github.com/mubaris/studious-eureka