支持向量機
支持向量機就算法作爲機器學習的經典算法,從被提出後快速發展,在很多場景和領域都取得了非常好的效果,同時兼有速度塊、支持數據量大等特點使其在工程實踐中得到廣泛應用。
首先我們先來看一個3維的平面方程:Ax+By+Cz+D=0
這就是我們中學所學的,從這個方程我們可以推導出二維空間的一條直線:Ax+By+D=0
那麼,依次類推,更高維的空間叫做一個超平面。
二維空間的幾何表示:
SVM的目標是找到一個超平面,這個超平面能夠很好的解決二分類問題,所以先找到各個分類的樣本點離這個超平面最近的點,使得這個點到超平面的距離最大化,最近的點就是虛線所畫的。由以上超平面公式計算得出大於1的就屬於打叉分類,如果小於0的屬於圓圈分類。
如何找到超平面
在超平面wx+b=0確定的情況下,|wx+b|能夠表示點x到距離超平面的遠近,而通過觀察wx+b的符號與類標記y的符號是否一致可判斷分類是否正確,所以,可以用(y(w*x+b))的正負性來判定或表示分類的正確性。於此,我們便引出了函數間隔(functional margin)的概念。定義函數間隔(用γ表示)爲:
但是這個函數間隔有個問題,就是我成倍的增加w和b的值,則函數值也會跟着成倍增加,但這個超平面沒有改變。所以有函數間隔還不夠,需要一個幾何間隔。
幾何間隔
我們把w做一個約束條件,假定對於一個點 x ,令其垂直投影到超平面上的對應點爲 x0 ,w 是垂直於超平面的一個向量,爲樣本x到超平面的距離,如下圖所示:
最大間隔分類器
對一個數據點進行分類,當超平面離數據點的“間隔”越大,分類的確信度(confidence)也越大。所以,爲了使得分類的確信度儘量高,需要讓所選擇的超平面能夠最大化這個“間隔”值。這個間隔就是下圖中的Gap的一半。
代碼練習理解
代碼1
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X [y<2,:2] #只取y<2的類別,也就是0 1 並且只取前兩個特徵
y = y[y<2] # 只取y<2的類別
# 分別畫出類別0和1的點
plt.scatter(X[y==0,0],X[y==0,1],color='red')
plt.scatter(X[y==1,0],X[y==1,1],color='blue')
plt.show()
# 標準化
standardScaler = StandardScaler()
standardScaler.fit(X) #計算訓練數據的均值和方差
X_standard = standardScaler.transform(X) #再用scaler中的均值和方差來轉換X,使X標準化
svc = LinearSVC(C=1e9) #線性SVM分類器
svc.fit(X_standard,y) # 訓練svm
這是未經過標準化的原始數據點分佈
代碼2
繪製決策邊界
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)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
# 繪製決策邊界
plot_decision_boundary(svc,axis=[-3,3,-3,3]) # x,y軸都在-3到3之間
# 繪製原始數據
plt.scatter(X_standard[y==0,0],X_standard[y==0,1],color='red')
plt.scatter(X_standard[y==1,0],X_standard[y==1,1],color='blue')
plt.show()
上面說了CCC是控制正則項的重要程度,這裏我們再次實例化一個svc,並傳入一個較小的C。
代碼3
svc2 = LinearSVC(C=0.01)
svc2.fit(X_standard,y)
plot_decision_boundary(svc2,axis=[-3,3,-3,3]) # x,y軸都在-3到3之間
# 繪製原始數據
plt.scatter(X_standard[y==0,0],X_standard[y==0,1],color='red')
plt.scatter(X_standard[y==1,0],X_standard[y==1,1],color='blue')
plt.show()
可以很明顯的看到和第一個決策邊界的不同,在這個決策邊界彙總,有一個紅點是分類錯誤的。
C越小容錯空間越大。
代碼4
使用多項式特徵和核函數
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
X, y = datasets.make_moons() #使用生成的數據
print(X.shape) # (100,2)
print(y.shape) # (100,)
生成月亮數據集
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()
X, y = datasets.make_moons(noise=0.15,random_state=777) #隨機生成噪聲點,random_state是隨機種子,noise是方差
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()
多項式特徵的SVM來對它進行分類。
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
def PolynomialSVC(degree,C=1.0):
return Pipeline([
("poly",PolynomialFeatures(degree=degree)),#生成多項式
("std_scaler",StandardScaler()),#標準化
("linearSVC",LinearSVC(C=C))#最後生成svm
])
poly_svc = PolynomialSVC(degree=3)
poly_svc.fit(X,y)
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()
我們可以看到,生成的邊界不再是線性的直線了。
使用核技巧來對數據進行處理,使其維度提升,使原本線性不可分的數據,在高維空間變成線性可分的。再用線性SVM來進行處理。
from sklearn.svm import SVC
def PolynomialKernelSVC(degree,C=1.0):
return Pipeline([
("std_scaler",StandardScaler()),
("kernelSVC",SVC(kernel="poly")) # poly代表多項式特徵
])
poly_kernel_svc = PolynomialKernelSVC(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()
可以看到這種方式也生成了一個非線性的邊界。
這裏SVC(kernel=“poly”)有個參數是kernel,就是核函數.
害!就這樣吧…