機器學習-分類算法支持向量機簡要概述
文章目錄
1. 監督學習與無監督學習
首先,簡要理解一下 監督學習 和 無監督學習 。
- 監督學習 :
- 含義:給定輸入和標籤,訓練得到一個模型,之後根據訓練好的模型對沒有標籤的數據進行預測,得到該數據的標籤。
- 特點:既有數據也有標籤,切數據和標籤之間存在聯繫
- 常見:分類(離散)、迴歸(連續)
- 無監督學習 :
- 含義:給定輸入和特徵,在不知道數據和特徵之間關係的情況下,據聚類或一定的模型得到數據之間的關係。
- 特點:數據和特徵之間沒有聯繫或着找不出聯繫
- 常見:聚類算法
2. 支持向量機 ——SVM
2.1 線性可分
圖片來源於百度百科
如上圖所示,有兩種類型的點,白點與黑點。SVM的目標,就是找出一個超平面(本圖中是一條線,在二維數據中,超平面是一條線;在三維數據中,超平面就是一個平面;在n維數據中,超平面就是一個n-1維的對象),這個超平面將數據集分成兩個部分,並且“間隔”最大。這個間隔如圖中所示,是兩條直線間的距離。
對於這條直線,是直線的向量方式,假設直線標準方程爲:
對其進行簡單變換,函數形式:
此時進行簡單替換,如下:
上述式子只是超平面的一個簡單示例,對於數據集中任何一個數據(x,y)代入式子計算,如果其值大於1,則是黑點,值小於-1,則是紅點。如果值剛好等於1或者-1,則稱這個點爲支持向量(可見上圖有3個支持向量)。如果值大於-1且小於1,則這個點處於間隔之內。
爲了找尋滿足”間隔“最大的超平面,看看間隔的計算公式:
公式中的w就是x與y係數a和b,要確定這個超平面,本質上就是確定參數w與b。
2.2 線性不可分
在線性不可分的情況下,支持向量機通過某種事先選擇的非線性映射將輸入變量映射到一個高維特徵空間,在這個空間中構造最優分類超平面。此處不詳談,用一張圖表示。其實本質還是找到一個超平面,由於低維空間找不到,所以就映射到高維空間,在高維空間尋找一個超平面,完成分類。
圖片來源於 支持向量機通俗導論(理解SVM的三層境界)
2.3 核函數
核函數的本質也是將輸入變量映射到高維空間,並尋找超平面。但它實際上是直接在原來的低維空間中進行計算,而不需要顯式地寫出映射後的結果。
下面列舉幾個常見的核:
- 線性核
- 多項式核
- 高斯核 :可映射到無窮維空間
3. python sklearn中的使用(二分類問題)
3.1 SVC
SVC是支持向量分類,基於libsvm實現,數據擬合的時間複雜度是數據樣本的二次方,可方便用於處理二分類問題。
def __init__(self, C=1.0, kernel='rbf', degree=3, gamma='auto_deprecated',
coef0=0.0, shrinking=True, probability=False,
tol=1e-3, cache_size=200, class_weight=None,
verbose=False, max_iter=-1, decision_function_shape='ovr',
random_state=None):
- 參數說明:
- C:懲罰項,float類型。可選參數,默認爲1.0,C越大,對分錯樣本的懲罰程度越大,因此在訓練樣本中準確率越高,但是泛化能力會降低,也就是對測試數據的分類準確率降低。相反,減小C的話,容許訓練樣本中有一些誤分類錯誤樣本,泛化能力強。對於訓練樣本帶有噪聲的情況,一般採用後者,把訓練樣本集中錯誤分類的樣本作爲噪聲。
- kernel:核函數類型,str類型,默認爲’rbf’。可選參數爲:
- ’linear’:線性核函數
- ‘poly’:多項式核函數
- ‘rbf’:徑像核函數/高斯核
- ‘sigmod’:sigmod核函數
- precomputed’:核矩陣。precomputed表示自己提前計算好核函數矩陣,這時候算法內部就不再用核函數去計算核矩陣,而是直接用你給的核矩陣,核矩陣需要爲n*n的
- degree:多項式核函數的階數,int類型,可選參數,默認爲3。這個參數只對多項式核函數有用,是指多項式核函數的階數n,如果給的核函數參數是其他核函數,則會自動忽略該參數
- gamma:核函數係數,float類型,可選參數,默認爲auto。只對’rbf’ ,’poly’ ,’sigmod’有效。如果gamma爲auto,代表其值爲樣本特徵數的倒數,即1/n_features
- coef0:核函數中的獨立項,float類型,可選參數,默認爲0.0。只有對’poly’ 和,’sigmod’核函數有用,是指其中的參數c
- probability:是否啓用概率估計,bool類型,可選參數,默認爲False,這必須在調用fit()之前啓用,並且會fit()方法速度變慢
- shrinking:是否採用啓發式收縮方式,bool類型,可選參數,默認爲True
- tol:svm停止訓練的誤差精度,float類型,可選參數,默認爲1e^-3
- cache_size:內存大小,float類型,可選參數,默認爲200。指定訓練所需要的內存,以MB爲單位,默認爲200MB
- class_weight:類別權重,dict類型或str類型,可選參數,默認爲None。給每個類別分別設置不同的懲罰參數C,如果沒有給,則會給所有類別都給C=1,即前面參數指出的參數C。如果給定參數’balance’,則使用y的值自動調整與輸入數據中的類頻率成反比的權重
- verbose:是否啓用詳細輸出,bool類型,默認爲False,此設置利用libsvm中的每個進程運行時設置,如果啓用,可能無法在多線程上下文中正常工作。一般情況都設爲False
- max_iter:最大迭代次數,int類型,默認爲-1,表示不限制
- decision_function_shape:決策函數類型,可選參數’ovo’和’ovr’,默認爲’ovr’。’ovo’表示one vs one,’ovr’表示one vs rest
- random_state:數據洗牌時的種子值,int類型,可選參數,默認爲None。僞隨機數發生器的種子,在混洗數據時用於概率估計
- 代碼實例
plt.scatter(data_set[:,0],data_set[:,1],c=data_set[:,2]) # 繪製可視化圖
plt.show()
對於上述書,我們用其對SVC進行訓練再用訓練好的SVC進行測試。
# 創建模型
clf = svm.SVC()
# 訓練模型,參數sample_weight爲每個樣本設置權重,應對非均衡問題
clf.fit(X=train_data, y=train_target, sample_weight=None)
# 使用模型預測值
result = clf.predict(test_data)
# 輸出預測值[-1. -1. 1. 1.]
print('預測結果:', result)
# 獲得支持向量的索引
print('支持向量索引:',clf.support_)
# 爲每一個類別獲得支持向量的數量
print('支持向量數量:',clf.n_support_)
預測結果: [-1. -1. 1. 1.]
支持向量索引: [ 1 8 12 14 17 19 28 29 41 42 43 52 59 70 74 76 4 5 18 31 33 36 39 54
55 57 75 79 90]
支持向量數量: [16 13]
可見其預測結果還是挺準確的。
3.2 NuSVC
NuSVC(Nu-Support Vector Classification.): 核支持向量分類,和SVC類似,也是基於libsvm實現的,但不同的是通過一個參數空值支持向量的個數。
def __init__(self, nu=0.5, kernel='rbf', degree=3, gamma='auto_deprecated',
coef0=0.0, shrinking=True, probability=False, tol=1e-3,
cache_size=200, class_weight=None, verbose=False, max_iter=-1,
decision_function_shape='ovr', random_state=None):
其中參數 nu :訓練誤差的一個上界和支持向量的分數的下界。取值在(0,1 ]之間。其餘參數與SVC一致。
clf = NuSVC() # 創建線性可分svm模型,參數均使用默認值
clf.fit(train_data, train_target) # 訓練模型
result = clf.predict(test_data) # 使用模型預測值
print('預測結果:',result) # 輸出預測值[-1. -1. 1. 1.]
# 獲得支持向量的索引
print('支持向量索引:',clf.support_)
# 爲每一個類別獲得支持向量的數量
print('支持向量數量:',clf.n_support_)
預測結果: [-1. -1. 1. 1.]
支持向量索引: [ 0 1 8 9 10 12 14 17 19 23 24 28 29 30 41 42 43 52 56 58 59 70 74 76
97 98 99 2 4 5 6 13 16 18 26 31 33 36 39 46 48 50 54 55 57 69 72 75
78 79 80 82 83 88 90]
支持向量數量: [27 28]
3.3 LinearSVC
LinearSVC(Linear Support Vector Classification):線性支持向量分類,類似於SVC,但是其使用的核函數是”linear“。基於徑向基函數計算的,其實現也不是基於LIBSVM,所以它具有更大的靈活性在選擇處罰和損失函數時,而且可以適應更大的數據集,他支持密集和稀疏的輸入是通過一對一的方式解決的。
def __init__(self, penalty='l2', loss='squared_hinge', dual=True, tol=1e-4,
C=1.0, multi_class='ovr', fit_intercept=True,
intercept_scaling=1, class_weight=None, verbose=0,
random_state=None, max_iter=1000):
-
參數說明:
-
C: 目標函數的懲罰係數C,用來平衡分類間隔margin和錯分樣本的,default C = 1.0
-
penalty : l1’ or ‘l2’ (default=’l2’) ,指定懲罰中使用的規範。 'l2’懲罰是SVC中使用的標準。 'l1’導致稀疏的coef_向量
-
loss: 指定損失函數
-
dual : 選擇算法來解決對偶或原始優化問題。當
時dual=false -
tol :(default = 1e - 3): svm結束標準的精度
-
multi_class: 如果y輸出類別包含多類,用來確定多類策略, ovr表示一對多,“crammer_singer”優化所有類別的一個共同的目標 。如果選擇“crammer_singer”,損失、懲罰和優化將會被被忽略
-
fit_intercept : 是否計算此模型的截距。 如果設置爲false,則不會在計算中使用截距(即,預期數據已經居中)
-
intercept_scaling : 當self.fit_intercept爲True時,實例向量x變爲[x,self.intercept_scaling],即具有等於intercept_scaling的常量值的“合成”特徵被附加到實例向量。 截距變爲intercept_scaling *合成特徵權重注意! 合成特徵權重與所有其他特徵一樣經受l1 / l2正則化。 爲了減小正則化對合成特徵權重(並因此對截距)的影響,必須增加intercept_scaling
-
class_weight: 對於每一個類別i設置懲罰係數
如果不給出,權重自動調整爲
-
verbose: 啓用詳細輸出, 此設置利用liblinear中的每進程運行時設置,如果啓用,可能無法在多線程上下文中正常工作
-
random_state : 在隨機數據混洗時使用的僞隨機數生成器的種子。 如果是int,則random_state是隨機數生成器使用的種子; 如果是RandomState實例,則random_state是隨機數生成器; 如果爲None,則隨機數生成器是np.random使用的RandomState實例
-
max_iter :要運行的最大迭代次數,默認爲1000
-
-
實例
clf = LinearSVC() # 創建線性可分svm模型,參數均使用默認值
clf.fit(train_data, train_target) # 訓練模型
result = clf.predict(test_data) # 使用模型預測值
print('預測結果:',result) # 輸出預測值[-1. -1. 1. 1.]
預測結果: [-1. -1. 1. 1.]
4. 多分類問題
對於多分類問題,可通過SVM實現
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
# 創建不均衡樣本
rng = np.random.RandomState(0)
n_samples_1 = 1000
n_samples_2 = 100
n_samples_3 = 100
X = np.r_[1.5 * rng.randn(n_samples_1, 2), 0.5 * rng.randn(n_samples_2, 2) + [2, 2],0.5 * rng.randn(n_samples_3, 2) + [-3, 3]]
# 三類樣本點中心爲(1.5,1.5)、(2,2)、(-3,3)
y = [0] * (n_samples_1) + [1] * (n_samples_2)+ [2] * (n_samples_3)
# 前面的1000個爲類別0,後面的100個爲類別1,最後100個類別爲2
# 創建模型獲取分離超平面
clf = svm.SVC(decision_function_shape='ovo',kernel='linear', C=1.0)
# decision_function_shape='ovo'爲使用1對1多分類處理。會創建n(n-1)/2個二分類。ovr爲一對所有的處理方式
clf.fit(X, y)
# 多分類的情況下,獲取其中二分類器的個數。
dec = clf.decision_function([[1.5,1.5]]) # decision_function()的功能:計算樣本點到分割超平面的函數距離。 包含幾個2分類器,就有幾個函數距離。
print('二分類器個數:',dec.shape[1])
# 繪製,第一個二分類器的分割超平面
w = clf.coef_[0]
a = -w[0] / w[1] # a可以理解爲斜率
xx = np.linspace(-5, 5)
yy = a * xx - clf.intercept_[0] / w[1] # 二維座標下的直線方程
# 使用類權重,獲取分割超平面
wclf = svm.SVC(kernel='linear', class_weight={1: 10})
wclf.fit(X, y)
# 繪製 分割分割超平面
ww = wclf.coef_[0]
wa = -ww[0] / ww[1]
wyy = wa * xx - wclf.intercept_[0] / ww[1] # 帶權重的直線
# 繪製第一個二分類器的分割超平面和樣本點
h0 = plt.plot(xx, yy, 'k-', label='no weights')
h1 = plt.plot(xx, wyy, 'k--', label='with weights')
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.legend()
plt.show()
二分類器個數: 3
5. 迴歸
支持向量分類的方法可以被擴展用作解決迴歸問題. 這個方法被稱作支持向量迴歸。
支持向量分類生成的模型(如前描述)只依賴於訓練集的子集,因爲構建模型的 cost function 不在乎邊緣之外的訓練點. 類似的,支持向量迴歸生成的模型只依賴於訓練集的子集, 因爲構建模型的 cost function 忽略任何接近於模型預測的訓練數據。
支持向量分類有三種不同的實現形式: SVR, NuSVR 和 LinearSVR. 在只考慮線性核的情況下, LinearSVR 比 SVR 提供一個更快的實現形式, 然而比起 SVR 和 LinearSVR, NuSVR 實現一個稍微不同的構思(formulation)。
與分類的類別一樣, fit方法會調用參數向量 X, y, 只在 y 是浮點數而不是整數型:
from sklearn import svm
X = [[0, 0], [2, 2]]
y = [0.5, 2.5]
clf = svm.SVR()
clf.fit(X, y)
print(clf.predict([[1, 1]]))
[1.5]