(給機器學習算法與Python學習加星標,提升AI技能)
Datawhale乾貨
作者:小一,Datawhale優秀學習者
寄語:本文介紹了SVM的理論,細緻說明了“間隔”和“超平面”兩個概念;隨後,闡述了如何最大化間隔並區分了軟硬間隔SVM;同時,介紹了SVC問題的應用。最後,用SVM乳腺癌診斷經典數據集,對SVM進行了深入的理解。
支持向量機(support vector machines, SVM)是一種二分類模型,它的基本模型是定義在特徵空間上的間隔最大的線性分類器,間隔最大使它有別於感知機。
SVM的的學習策略就是間隔最大化,可形式化爲一個求解凸二次規劃的問題,也等價於正則化的合頁損失函數的最小化問題。SVM的的學習算法就是求解凸二次規劃的最優化算法。
下圖爲SVM的分類效果顯示,可以發現,不管是線性還是非線性,SVM均表現良好。
學習框架
後臺回覆 SVM 可下載SVM學習框架高清導圖
SVM理論
支持向量機(Support Vector Machine:SVM)的目的是用訓練數據集的間隔最大化找到一個最優分離超平面。
下邊用一個例子來理解下間隔和分離超平面兩個概念。現在有一些人的身高和體重數據,將它們繪製成散點圖,是這樣的:
如果現在給你一個未知男女的身高和體重,你能分辨出性別嗎?直接將已知的點劃分爲兩部分,這個點落在哪一部分就對應相應的性別。那就可以畫一條直線,直線以上是男生,直線以下是女生。
問題來了,現在這個是一個二維平面,可以畫直線,如果是三維的呢?該怎麼畫?我們知道一維平面是點,二維平面是線,三維平面是面。
對的,那麼注意,今天的第一個概念:超平面是平面的一般化:
在一維的平面中,它是點
在二維的平面中,它是線
在三維的平面中,它是面
在更高的維度中,我們稱之爲超平面
注意:後面的直線、平面都直接叫超平面了。
繼續剛纔的問題,我們剛纔是通過一個分離超平面分出了男和女,這個超平面唯一嗎?很明顯,並不唯一,這樣的超平面有若干個。
那麼問題來了,既然有若干個,那肯定要最好的,這裏最好的叫最優分離超平面。如何在衆多分離超平面中選擇一個最優分離超平面?下面這兩個分離超平面,你選哪個?綠色的還是黑色的?
對,當然是黑色的,可是原理是什麼?很簡單,原理有兩個,分別是:
正確的對訓練數據進行分類
對未知數據也能很好的分類
黑色的分離超平面能夠對訓練數據很好的分類,當新增未知數據時,黑色的分離超平面泛化能力也強於綠色。深究一下,爲什麼黑色的要強於綠色?原理又是什麼?
其實很簡單:最優分離超平面其實是和兩側樣本點有關,而且只和這些點有關。怎麼理解這句話呢,我們看張圖:
其中當間隔達到最大,兩側樣本點的距離相等的超平面爲最優分離超平面。注意,今天的第二個概念:對應上圖,Margin對應的就是最優分離超平面的間隔,此時的間隔達到最大。
一般來說,間隔中間是無點區域,裏面不會有任何點(理想狀態下)。給定一個超平面,我們可以就算出這個超平面與和它最接近的數據點之間的距離。那麼間隔(Margin)就是二倍的這個距離。
如果還是不理解爲什麼這個分離超平面就是最優分離超平面,那你在看這張圖。
在這張圖裏面間隔MarginB小於上張圖的MarginA。當出現新的未知點,MarginB分離超平面的泛化能力不如MarginA,用MarginB的分離超平面去分類,錯誤率大於MarginA
總結一下
支持向量機是爲了通過間隔最大化找到一個最優分離超平面。在決定分離超平面的時候,只有極限位置的那兩個點有用,其他點根本沒有大作用,因爲只要極限位置離得超平面的距離最大,就是最優的分離超平面了。
如何確定最大化間隔
如果我們能夠確定兩個平行超平面,那麼兩個超平面之間的最大距離就是最大化間隔。看個圖你就都明白了:
左右兩個平行超平面將數據完美的分開,我們只需要計算上述兩個平行超平面的距離即可。所以,我們找到最大化間隔:
找到兩個平行超平面,可以劃分數據集並且兩平面之間沒有數據點
最大化上述兩個超平面
1. 確定兩個平行超平面
怎麼確定兩個平行超平面?我們知道一條直線的數學方程是:y-ax+b=0,而超平面會被定義成類似的形式:
推廣到n維空間,則超平面方程中的w、x分別爲:
如何確保兩超平面之間沒有數據點?我們的目的是通過兩個平行超平面對數據進行分類,那我們可以這樣定義兩個超平面。
對於每一個向量xi:滿足:
或者
也就是這張圖:所有的紅點都是1類,所有的藍點都是−1類。
整理一下上面的兩個超平面:
不等式兩邊同時乘以 yi,-1類的超平面yi=-1,要改變不等式符號,合併後得
ok,記住上面的約束條件。
2. 確定間隔
如何求兩個平行超平面的間隔呢?我們可以先做這樣一個假設:
是滿足約束 的超平面
是滿足約束的超平面
是上的一點
則到平面的垂直距離就是我們要的間隔。
這個間隔是可以通過計算出來的,推導還需要一些步驟,直接放結果了就:
其中||w||表示w的二範數,求所有元素的平方和,然後在開方。比如,二維平面下:
可以發現,w 的模越小,間隔m 越大
3. 確定目標
我們的間隔最大化,最後就成了這樣一個問題:
了其中w和b,我們的最優分離超平面就確定了,目的也就達到了。
上面的最優超平面問題是一個凸優化問題,可以轉換成了拉格朗日的對偶問題,判斷是否滿足KKT條件,然後求解。上一句話包含的知識是整個SVM的核心,涉及到大量的公式推導。
此處略過推導的步驟,若想了解推導過程可直接百度。你只需要知道它的目的就是爲了找出一個最優分離超平面。就假設我們已經解出了最大間隔,找到了最優分離超平面,它是這樣的:
除去上面我們對最大間隔的推導計算,剩下的部分其實是不難理解的。從上面過程,我們可以發現,其實最終分類超平面的確定依賴於部分極限位置的樣本點,這叫做支持向量。
由於支持向量在確定分離超平面中起着決定性作用,所有將這類模型叫做支持向量機。
我們在上面圖中的點都是線性可分的,也就是一條線(或一個超平面)可以很容易的分開的。但是實際情況不都是這樣,比如有的女生身高比男生高,有的男生體重比女生都輕,像這種存在噪聲點分類,應該怎麼處理?
針對樣本的SVM
1. 硬間隔線性SVM
上面例子中提到的樣本點都是線性可分的,我們就可以通過分類將樣本點完全分類準確,不存在分類錯誤的情況,這種叫硬間隔,這類模型叫做硬間隔線性SVM。
2. 軟間隔線性SVM
同樣的,可以通過分類將樣本點不完全分類準確,存在少部分分類錯誤的情況,這叫軟間隔,這類模型叫做軟間隔線性SVM。
不一樣的是,因爲有分類錯誤的樣本點,但我們仍需要將錯誤降至最低,所有需要添加一個懲罰項來進行浮動,所有此時求解的最大間隔就變成了這樣:
硬間隔和軟間隔都是對線性可分的樣本點進行分類,那如果樣本點本身就不線性可分?舉個例子:下面這幅圖
樣本點並不是線性可分的,這種問題應該怎麼處理呢?解決這個問題之前,先看一下這個小短視頻:
視頻中是將平面中的樣本點映射到三維空間中,使用一個平面將樣本線性可分。
所以我們需要一種方法,可以將樣本從原始空間映射到一個更高緯的空間中,使得樣本在新的空間中線性可分,即:核函數。在非線性SVM中,核函數的選擇關係到SVM的分類效果。
幸好的是,我們有多種核函數:線性核函數、多項式核函數、高斯核函數、sigmoid核函數等等,甚至你還可以將這些核函數進行組合,以達到最優線性可分的效果
核函數瞭解到應該就差不多了,具體的實現我們在下一節的實戰再說。
多分類SVM
前面提到的所有例子最終都指向了二分類,現實中可不止有二分類,更多的是多分類問題。那麼多分類應該怎麼分呢?有兩種方法:一對多和一對一。
1. 一對多法
一對多法講究的是將所有的分類分成兩類:一類只包含一個分類,另一類包含剩下的所有分類
舉個例子:現在有A、B、C、D四種分類,根據一對多法可以這樣分:
①:樣本A作爲正集,B、C、D爲負集
②:樣本B作爲正集,A、C、D爲負集
③:樣本C作爲正集,A、B、D爲負集
④:樣本D作爲正集,A、B、C爲負集
該方法分類速度較快,但訓練速度較慢,添加新的分類,需要重新構造分類器。
2. 一對一法
一對一法講究的是從所有分類中只取出兩類,一個爲正類一個爲父類
再舉個例子:現在有A、B、C三種分類,根據一對一法可以這樣分:
①分類器:樣本A、B
②分類器:樣本A、C
③分類器:樣本B、C
該方法的優點是:當新增一類時,只需要訓練與該類相關的分類器即可,訓練速度較快。缺點是:當類的種類K很多時,分類器個數K(K-1)/2會很多,訓練和測試時間較慢。
SVC,Support Vector Classification
我們知道針對樣本有線性SVM和非線性SVM。同樣的在sklearn中提供的這兩種的實現,分別是:LinearSVC和SVC。
SVC : Support Vector Classification 用支持向量機處理分類問題
SVR : Support Vector Regression 用支持向量機處理迴歸問題
1. SVC和LinearSVC
LinearSVC是線性分類器,用於處理線性分類的數據,且只能使用線性核函數。SVC是非線性分類器,即可以使用線性核函數進行線性劃分,也可以使用高維核函數進行非線性劃分。
2. SVM的使用
在sklearn 中,一句話調用SVM,
from sklearn import svm
主要說一下SVC的創建,因爲它的參數比較重要
model = svm.SVC(kernel= rbf , C=1.0, gamma=0.001)
分別解釋一下三個重要參數:
kernel代表核函數的選擇,有四種選擇,默認rbf(即高斯核函數)
參數C代表目標函數的懲罰係數,默認情況下爲 1.0
參數gamma代表核函數的係數,默認爲樣本特徵數的倒數
其中kernel代表的四種核函數分別是:
linear:線性核函數,在數據線性可分的情況下使用的
poly:多項式核函數,可以將數據從低維空間映射到高維空間
rbf:高斯核函數,同樣可以將樣本映射到高維空間,但所需的參數較少,通常性能不錯
sigmoid:sigmoid核函數,常用在神經網絡的映射中
SVM的使用就介紹這麼多,來實戰測試一下。
經典數據集實戰
1. 數據集
SVM的經典數據集:乳腺癌診斷。醫療人員採集了患者乳腺腫塊經過細針穿刺 (FNA) 後的數字化圖像,並且對這些數字圖像進行了特徵提取,這些特徵可以描述圖像中的細胞核呈現。通過這些特徵可以將腫瘤分成良性和惡性。
本次數據一共569條、32個字段,先來看一下具體數據字段吧:
其中mean結尾的代表平均值、se結尾的代表標準差、worst結尾代表最壞值(這裏具體指腫瘤的特徵最大值)。所有其實主要有10個特徵字段,一個id字段,一個預測類別字段。我們的目的是通過給出的特徵字段來預測腫瘤是良性還是惡性。
2. 數據EDA
EDA:Exploratory Data Analysis探索性數據分析,先來看數據的分佈情況:
df_data.info()
一共569條、32個字段。32個字段中1個object類型,一個int型id,剩下的都是float 類型。另外:數據中不存在缺失值。
大膽猜測一下,object類型可能是類別型數據,即最終的預測類型,需要進行處理,先記下。再來看連續型數據的統計數據:
df_data.describe()
好像也沒啥問題(其實因爲這個數據本身比較規整),可直接開始特徵工程吧。
3. 特徵工程
首先就是將類別數據連續化
"""2. 類別特徵向量化"""
le = preprocessing.LabelEncoder()
le.fit(df_data[ diagnosis ])
df_data[ diagnosis ] = le.transform(df_data[ diagnosis ])
再來觀察每一個特徵的三個指標:均值、標準差和最大值。優先選擇均值,最能體現該指特徵的整體情況。
"""3. 提取特徵"""
# 提取所有mean 字段和label字段
df_data_X = df_data.filter(regex= _mean )
df_data_y = df_data[ diagnosis ]
現在還有十個特徵,我們通過熱力圖來看一下特徵之間的關係。
#熱力圖查看特徵之間的關係
sns.heatmap(df_data[df_data_X.columns].corr(), linewidths=0.1, vmax=1.0, square=True,
cmap=sns.color_palette( RdBu , n_colors=256),
linecolor= white , annot=True)
plt.title( the feature of corr )
plt.show()
熱力圖是這樣的:
我們發現radius_mean、perimeter_mean和area_mean這三個特徵強相關,那我們只保留一個就行了。這裏保留熱力圖裏面得分最高的perimeter_mean。
最後一步,因爲是連續數值,最好對其進行標準化。標準化之後的數據是這樣的:
df_data_X = df_data_X.drop([ radius_mean , area_mean ], axis=1)
"""5. 進行特徵歸一化/縮放"""
scaler = preprocessing.StandardScaler()
df_data_X = scaler.fit_transform(df_data_X)
return df_data_X, df_data_y
4. 訓練模型
上面已經做好了特徵工程,直接塞進模型看看效果怎麼樣。因爲並不知道數據樣本到底是否線性可分,所有我們都來試一下兩種算法。先來看看LinearSVC 的效果
"""1.1. 第一種模型驗證方法"""
# 切分數據集
X_train, X_test, y_train, y_test = train_test_split(data_X, data_y, test_size=0.2)
# 創建SVM分類器
model = svm.LinearSVC()
# 用訓練集做訓練
model.fit(X_train, y_train)
# 用測試集做預測
pred_label = model.predict(X_test)
print( 準確率: , metrics.accuracy_score(pred_label, y_test))
效果很好,簡直好的不行,在此,並沒有考慮準確率。
ok,還有SVC的效果。因爲SVC需要設置參數,直接通過網格搜索讓機器自己找到最優參數,效果更好。
"""2. 通過網格搜索尋找最優參數"""
parameters = {
gamma : np.linspace(0.0001, 0.1),
kernel : [ linear , poly , rbf , sigmoid ],
}
model = svm.SVC()
grid_model = GridSearchCV(model, parameters, cv=10, return_train_score=True)
grid_model.fit(X_train, y_train)
# 用測試集做預測
pred_label = grid_model.predict(X_test)
print( 準確率: , metrics.accuracy_score(pred_label, y_test))
# 輸出模型的最優參數
print(grid_model.best_params_)
可以看出,最終模型還是選擇rbf高斯核函數,果然實至名歸。主要是通過數據EDA+特徵工程完成了數據方面的工作,然後通過交叉驗證+網格搜索確定了最優模型和最優參數。
推薦閱讀
【教程】還不會用Git的程序員,這個項目讓你邊玩邊學
下載 | 連『吳恩達』都點讚的深度學習筆記
完全圖解GPT-2:看完這篇就夠了(二)
完全圖解GPT-2:看完這篇就夠了(一)
【Github】100+ Chinese Word Vectors 預訓練中文詞向量