四種SVM主要核函數(shù)及相關(guān)參數(shù)的比較
本文將用數(shù)據(jù)可視化的方法解釋4種支持向量機(jī)核函數(shù)和參數(shù)的區(qū)別
簡(jiǎn)單地說(shuō),支持向量機(jī)(SVM)是一種用于分類(lèi)的監(jiān)督機(jī)器學(xué)習(xí)技術(shù)。它的工作原理是計(jì)算一個(gè)最好地分隔類(lèi)的最大邊距的超平面。
支持向量機(jī)除了提供簡(jiǎn)單的線(xiàn)性分離之外,還可以通過(guò)應(yīng)用不同的核方法進(jìn)行非線(xiàn)性分類(lèi)。參數(shù)設(shè)置也是SVM更好地工作的另一個(gè)重要因素。通過(guò)適當(dāng)?shù)倪x擇,我們可以使用支持向量機(jī)來(lái)處理高維數(shù)據(jù)。
本文旨將使用Scikit-learn庫(kù)來(lái)展示每個(gè)核函數(shù)以及如何使用不同的參數(shù)設(shè)置。并且通過(guò)數(shù)據(jù)可視化進(jìn)行解釋和比較。
如果你正在尋找常見(jiàn)數(shù)據(jù)集(如Iris Flowers或Titanic)之外的另一個(gè)數(shù)據(jù)集,那么poksammon數(shù)據(jù)集可以是另一個(gè)選擇。盡管你可能不是這些口袋怪物的粉絲,但它們的屬性很容易理解,并且有各種各樣的特征可供使用。
Pokemon的屬性,如hp,攻擊和速度,可以作為連續(xù)變量使用。對(duì)于分類(lèi)變量,有類(lèi)型(草、火、水等)、等級(jí)(普通、傳奇)等。此外,如果有新一代或Pokemon出現(xiàn),數(shù)據(jù)集將在未來(lái)進(jìn)行更新。
免責(zé)聲明:Pokemon和所有相關(guān)名稱(chēng)均為任天堂公司的版權(quán)和商標(biāo)。
導(dǎo)入數(shù)據(jù)和庫(kù)
為了直觀地展示每個(gè)SVM的內(nèi)核是如何分離分類(lèi)的的,我們將只選擇baby, legendary, mythical。我們先從導(dǎo)入數(shù)據(jù)和庫(kù)開(kāi)始。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv('pokemons.csv', index_col=0)
df.reset_index(drop=True, inplace=True)
df = df[df['rank'].isin(['baby', 'legendary'])]
df.reset_index(drop=True, inplace=True)
df.head()
EDA
Pokemon有7種基本的屬性- hp,攻擊,防御,特殊攻擊,特殊防御,速度和高度。下面的步驟是使用我們選擇的統(tǒng)計(jì)數(shù)據(jù)執(zhí)行一個(gè)快速EDA。
select_col = ['hp','atk', 'def', 'spatk', 'spdef', 'speed', 'height']
df_s = df[select_col]
df_s.info()
幸運(yùn)的是,沒(méi)有空值。接下來(lái),讓我們繪制Box和Whisker圖,以查看這些變量的分布。
sns.set_style('darkgrid')
df_s.iloc[:,].boxplot(figsize=(11,5))
plt.show()
height變量的分布與其他變量有很大的不同。在繼續(xù)之前應(yīng)該執(zhí)行標(biāo)準(zhǔn)化。我們將使用來(lái)自sklearn的StandardScaler來(lái)進(jìn)行處理
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
array_s = scaler.fit_transform(df_s)
df_scal = pd.DataFrame(array_s, columns=[i+'_std' for i in select_col])
df_scal.boxplot(figsize=(11,5))
plt.show()
標(biāo)準(zhǔn)化之后,分布看起來(lái)更好。
由于我們的數(shù)據(jù)集有多個(gè)特征,我們需要進(jìn)行降維繪圖。使用來(lái)自sklearn.decomposition的類(lèi)PCA將維數(shù)減少到兩個(gè)。結(jié)果將使用Plotly的散點(diǎn)圖顯示。
from sklearn.decomposition import PCA
import plotly.express as px
#encoding
dict_y = {'baby':1, 'legendary':2}
df['s_code'] = [dict_y.get(i) for i in df['rank']]
df.head()
pca = PCA(n_compnotallow=2)
pca_result = pca.fit_transform(array_s)
df_pca = pd.DataFrame(pca_result, columns=['PCA_1','PCA_2'])
df = pd.concat([df, df_pca], axis=1)
fig = px.scatter(df, x='PCA_1', y='PCA_2', hover_name='name',
color='rank', opacity=0.9,
color_discrete_sequence=['red', 'blue'])
fig.update_xaxes(showgrid=False)
fig.update_yaxes(showgrid=False)
fig.show()
我們把Pokemon圖片帶入散點(diǎn)圖。
再次免責(zé)聲明:Pokemon和所有相關(guān)名稱(chēng)均為任天堂公司的版權(quán)和商標(biāo)。
baby和legendary這兩個(gè)類(lèi)別之間的大多數(shù)數(shù)據(jù)點(diǎn)是分開(kāi)的。盡管這兩個(gè)類(lèi)并沒(méi)有完全分離,但在本文中對(duì)每個(gè)內(nèi)核函數(shù)進(jìn)行實(shí)驗(yàn)還是很有用的。
下一步是在三維空間中獲得更多細(xì)節(jié)。讓我們將PCA組件的數(shù)量更改為三個(gè)。這是3D散點(diǎn)圖可以顯示的最大數(shù)字。
pcaz = PCA(n_compnotallow=3)
pcaz_result = pcaz.fit_transform(array_s)
df_pcaz = pd.DataFrame(pcaz_result, columns=['PCAz_1', 'PCAz_2', 'PCAz_3'])
df = pd.concat([df, df_pcaz], axis=1)
fig = px.scatter_3d(df, x='PCAz_1', y='PCAz_2', z='PCAz_3', hover_name='name',
color='rank', opacity=0.9,
color_discrete_sequence=['red', 'blue'])
fig.update_traces(marker=dict(size=4))
fig.update_layout(margin=dict(l=0, r=0, t=0, b=0))
fig.show()
結(jié)果顯示了更多關(guān)于數(shù)據(jù)點(diǎn)如何在三維空間中定位的細(xì)節(jié)。在一些區(qū)域兩個(gè)類(lèi)仍然混合在一起。下面我們討論核方法。
核方法
支持向量機(jī)可以簡(jiǎn)單地使用Scikit-learn庫(kù)中的sklearn.svm.SVC類(lèi)執(zhí)行??梢酝ㄟ^(guò)修改核參數(shù)來(lái)選擇核函數(shù)??偣灿形宸N方法可用:
Linear
Poly
RBF (Radial Basis Function)
Sigmoid
Precomputed
本文將主要關(guān)注前四種核方法,因?yàn)樽詈笠环N方法是預(yù)計(jì)算的,它要求輸入矩陣是方陣,不適合我們的數(shù)據(jù)集
除了核函數(shù)之外,我們還將調(diào)整三個(gè)主要參數(shù),以便稍后比較結(jié)果。
C:正則化參數(shù)
Gamma(γ): rbf、poly和sigmoid函數(shù)的核系數(shù)
Coef0:核函數(shù)中的獨(dú)立項(xiàng),只在poly和s型函數(shù)中有意義
在下面的代碼中,predict_proba()將計(jì)算網(wǎng)格上可能結(jié)果的概率。最終結(jié)果將顯示為等高線(xiàn)圖。
from sklearn import svm
import plotly.graph_objects as go
y = df['s_code'] # y values
h = 0.2 # step in meshgrid
x_min, x_max = df_pca.iloc[:, 0].min(), df_pca.iloc[:, 0].max()
y_min, y_max = df_pca.iloc[:, 1].min(), df_pca.iloc[:, 1].max()
xx, yy = np.meshgrid(np.arange(x_min-0.5, x_max+0.5, h), #create meshgrid
np.arange(y_min-0.5, y_max+0.5, h))
def plot_svm(kernel, df_input, y, C, gamma, coef):
svc_model = svm.SVC(kernel=kernel, C=C, gamma=gamma, coef0=coef,
random_state=11, probability=True).fit(df_input, y)
Z = svc_model.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 0]
Z = Z.reshape(xx.shape)
fig = px.scatter_3d(df, x='PCAz_1', y='PCAz_2', z='PCAz_3', #3D Scatter plot
hover_name='name',
color='rank', opacity=0.9,
color_discrete_sequence=['red', 'blue'])
fig.update_traces(marker=dict(size=4))
fig.add_traces(go.Surface(x=xx, y=yy, # prediction probability contour plot
z=Z+round(df.PCAz_3.min(),3), # adjust the contour plot position
name='SVM Prediction',
colorscale='viridis', showscale=False,
contours = {"z": {"show": True, "start": x_min, "end": x_max,
"size": 0.1}}))
title = kernel.capitalize() + ' C=' + str(i) + ', γ=' + str(j) + ', coef0=' + str(coef)
fig.update_layout(margin=dict(l=0, r=0, t=0, b=0), showlegend=False,
title={'text': title,
'font':dict(size=39),
'y':0.95,'x':0.5,'xanchor': 'center','yanchor': 'top'})
return fig.show()
最后,創(chuàng)建三個(gè)參數(shù)的列表以進(jìn)行比較,這里將比較0.01和100之間的值。如果您想嘗試不同的值,可以調(diào)整該數(shù)字。
from itertools import product
C_list = [0.01, 100]
gamma_list = [0.01, 100]
coef_list = [0.01, 100]
param = [(r) for r in product(C_list, gamma_list, coef_list)]
print(param)
現(xiàn)在一切都準(zhǔn)備好了,讓我們用不同類(lèi)型的核函數(shù)繪制結(jié)果。
1、線(xiàn)性核
這是最常見(jiàn)、最簡(jiǎn)單的SVM的核函數(shù)。這個(gè)核函數(shù)返回一個(gè)線(xiàn)性超平面,它被用作分離類(lèi)的決策邊界。通過(guò)計(jì)算特征空間中兩個(gè)輸入向量的點(diǎn)積得到超平面。
for i,j,k in param:
plot_svm('linear', df_pca, y, i, j, k)
結(jié)果中的平面(等高線(xiàn)圖)不是超平面。它們是predict_proba()的預(yù)測(cè)概率的結(jié)果,其值在0到1之間。
概率平面表示數(shù)據(jù)點(diǎn)被分類(lèi)的概率。黃色區(qū)域意味著成為Baby可能性很大,而藍(lán)色區(qū)域則表示成為L(zhǎng)egend的可能性很大。
改變SVM結(jié)果的唯一參數(shù)是正則化參數(shù)(C)。理論上,當(dāng)C的數(shù)量增加時(shí),超平面的裕度會(huì)變小。當(dāng)來(lái)自不同類(lèi)別的數(shù)據(jù)點(diǎn)混合在一起時(shí),使用高C可能會(huì)很好。過(guò)高的正則化會(huì)導(dǎo)致過(guò)擬合。
2、徑向基函數(shù)(RBF)核
RBF(徑向基函數(shù))。該核函數(shù)計(jì)算歐幾里得距離的平方來(lái)度量?jī)蓚€(gè)特征向量之間的相似性。
只需更改內(nèi)核名稱(chēng),就可以使用相同的for循環(huán)進(jìn)程。
for i,j,k in param:
plot_svm('rbf', df_pca, y, i, j, k)
結(jié)果表明,除了正則化參數(shù)(C)外,γ (γ)也會(huì)影響RBF核的結(jié)果,coef0對(duì)RBF核函數(shù)沒(méi)有影響。
伽馬參數(shù)決定了數(shù)據(jù)點(diǎn)對(duì)超平面的影響。對(duì)于高伽馬值,靠近超平面的數(shù)據(jù)點(diǎn)將比更遠(yuǎn)的數(shù)據(jù)點(diǎn)有更大的影響。
低伽馬值的概率平面比高伽馬值的概率平面平滑。結(jié)果在高伽馬值的后4個(gè)散點(diǎn)圖中更為明顯;每個(gè)數(shù)據(jù)點(diǎn)對(duì)預(yù)測(cè)概率影響很大。
3、多項(xiàng)式核
多項(xiàng)式核通過(guò)將數(shù)據(jù)映射到高維空間來(lái)工作。取變換后的高維空間中數(shù)據(jù)點(diǎn)與原始空間的點(diǎn)積。由于它處理高維數(shù)據(jù)的能力,這個(gè)內(nèi)核被推薦用于執(zhí)行非線(xiàn)性分離。
多項(xiàng)式核與其他核相比,處理時(shí)間是最長(zhǎng)的。這可能是將數(shù)據(jù)映射到高維空間的結(jié)果。
for i,j,k in param:
plot_svm('poly', df_pca, y, i, j, k)
可以看出,這三個(gè)參數(shù)都會(huì)影響SVM的分類(lèi)效果。除正則化參數(shù)(C)和γ (γ)外,coef0參數(shù)控制高次多項(xiàng)式對(duì)模型的影響程度。coef0值越高,預(yù)測(cè)概率等高線(xiàn)越趨于彎曲。
4、Sigmoid核
理論上,sigmoid函數(shù)擅長(zhǎng)映射輸入值并返回0到1之間的值。該函數(shù)通常用于神經(jīng)網(wǎng)絡(luò)中,其中s形函數(shù)作為分類(lèi)的激活函數(shù)。
盡管它可以應(yīng)用于SVM任務(wù)并且看起來(lái)很有用,但一些文章說(shuō)結(jié)果可能太復(fù)雜而無(wú)法解釋。我們這里使用數(shù)據(jù)可視化來(lái)查看這個(gè)問(wèn)題。
for i,j,k in param:
plot_svm('sigmoid', df_pca, y, i, j, k)
可以看到從Sigmoid核得到的圖很復(fù)雜,也無(wú)法解釋。預(yù)測(cè)概率等值線(xiàn)圖與其他核的預(yù)測(cè)概率等值線(xiàn)圖完全不同。并且等高線(xiàn)圖的顏色不在它對(duì)應(yīng)的數(shù)據(jù)點(diǎn)下面。最主要的是當(dāng)改變參數(shù)值時(shí),結(jié)果沒(méi)有模式可循。
但是我個(gè)人認(rèn)為,這并不意味著這個(gè)內(nèi)核很糟糕或者應(yīng)該避免使用。也許他找到了我們未察覺(jué)的數(shù)據(jù)特征,所以可能會(huì)有一些分類(lèi)任務(wù),sigmoid將適合使用。
總結(jié)
支持向量機(jī)是一種有效的機(jī)器學(xué)習(xí)分類(lèi)技術(shù),因?yàn)樗軌蛱峁┖?jiǎn)單的線(xiàn)性和非線(xiàn)性分類(lèi)。
因?yàn)槊總€(gè)數(shù)據(jù)集都有不同的特征,所以不存在銀彈。為了使支持向量機(jī)有效,必須選擇好核和參數(shù),同時(shí)還要注意避免過(guò)擬合,我們以上的總結(jié)希望對(duì)你的選擇有所幫助。