顧老師新書《全棧軟體測試工程師寶典》
https://item.m.jd.com/product/10023427978355.html
以前兩本書的網上購買地址:
《軟體測試技術實戰設計,工具及管理》
https://item.jd.com/34295655089.html
《基於Django的電子商務網站》
https://item.jd.com/12082665.html
1. 線性可分與線性不可分
上圖左邊為線性可分的,通過一條直線就可以把兩類分開;而右邊是線性不可分的,如何用一條線都不能把紅黑兩個分離開。對於線性不可分的我們可以採取升維的方式來解決,比如有如下十個樣本。
紅色的是一類,綠色的是另一類,它在二維平面上是線性不可分的;我們現在加上一維,如果它是紅色的,第三維設為1,否則設為0。這樣我們通過升維把線性不可分的變為線性可分的,如下圖所示。
從正方向看下來,三維還原成二維,就變為:
2 支持向量機原理支持向量機(Support Vector Machine,以下簡稱SVM),作為傳統機器學習的一個非常重要的分類算法,它是一種通用的前饋網絡類型,最早是由Vladimir N.Vapnik 和 Alexey Ya.Chervonenkis在1963年提出,目前的版本(softmargin)是CorinnaCortes 和 Vapnik在1993年提出,1995年發表。深度學習(2012)出現之前,如果不考慮集成學習的算法,不考慮特定的訓練數據集,在分類算法中的表現SVM說是排第一估計是沒有什麼異議的。
SVM本來是一種線性分類和非線性分類都支持的二元分類算法,但經過演變,現在也支持多分類問題,也能應用到了回歸問題。
一些線性不可分的問題可能是非線性可分的,即特徵空間存在超曲面(hypersurface)將正類和負類分開。使用非線性函數可以將非線性可分問題從原始的特徵空間映射至更高維的希爾伯特空間(Hilbert space),從而轉化為線性可分問題。
支持向量機通過某非線性變換 φ( x) ,將輸入空間映射到高維特徵空間。特徵空間的維數可能非常高。如果支持向量機的求解只用到內積運算,而在低維輸入空間又存在某個函數 K(x, x') ,它恰好等於在高維空間中這個內積,即K( x, x') =<φ( x) ⋅φ( x') > 。那麼支持向量機就不用計算複雜的非線性變換,而由這個函數 K(x, x')直接得到非線性變換的內積,使大大簡化了計算。這樣的函數 K(x, x') 稱為核函數。
核函數一般包括以下幾個:
我們下面來看代碼
# 導入NumPy庫import numpy as np# 導入畫圖工具import matplotlib.pyplot as pltfrom sklearn import svmfrom sklearn.datasets import make_blobsdef SVM_linear():#創建50個數據點,分成2類 X , y = make_blobs(n_samples=50,random_state=6,centers=2)#創建一個線性內核的支持向量 clf = svm.SVC(kernel='linear',C=1000)# C-SVC的懲罰參數C,默認值是1.0 clf.fit(X,y)# 畫出數據點 plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.Paired,s=30)# 建立圖像坐標 ax = plt.gca() #當前的圖表和子圖可以使用plt.gcf()和plt.gca()獲得xlim = ax.get_xlim() #返回當前Axes視圖的x的上下限 ylim = ax.get_ylim() #返回當前Axes視圖的y的上下限# 生成等差數列 xx = np.linspace(xlim[0],xlim[1],30) yy = np.linspace(ylim[0],ylim[1],30) YY , XX = np.meshgrid(yy,xx) # meshgrid函數用兩個坐標軸上的點在平面上畫網格。 xy = np.vstack([XX.ravel(),YY.ravel()]).T# np.hstack():橫向拼接,增加特徵量;np.vstack():縱向拼接,增加樣本個數 Z = clf.decision_function(xy). reshape(XX.shape)#decision_function:計算樣本點到分割超平面的函數距離#shape是查看數據有多少行多少列#reshape()是數組array中的方法,作用是將數據重新組織# 把分類決定邊界畫出來 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()以上展示的是SVC線性核的模型。中間這條「線」叫做最大邊界超平面(Maximum Margin Separating Hyperplane)(二維時為線,三維時為面,多維時為超平面)。這條線到和所有支持向量的距離都是最大的。離這個超平面最近的點就是「支持向量」,點到超平面的距離叫做間隔,支持向量機的意思就是使超平面和支持向量之間的間隔儘可能的大。
f(x) = wTx+b
w = (w1,w2,w3,…,wn)為法向量
f(x) = 0:超平面上
> 0 :超平面一邊的一個點
< 0 :超平面另一邊的一個點
註:
SVM=Support Vector Machine 是支持向量機;
SVC=Support VectorClassification就是支持向量機用於分類;
SVR=Support Vector Regression.就是支持向量機用於回歸分析。
SVM適合於有監督學習的分類與回歸算法,如下圖。
wTxi+b>=1=>yi=1
wTxi+b<=-1=>yi=-1
下面我們通過代碼來看一下:SVC with Linear Kernel、SVC with RBF Kernel、SVC with sigmoid Kernel和SVC with poly Kernel的曲線。
import matplotlib.pyplot as pltfrom sklearn import svmfrom sklearn.datasets import make_blobsdef SVM_base(mykernel,title):#創建50個數據點,分成2類 X , y = make_blobs(n_samples=50,random_state=6,centers=2)#創建一個線性內核的支持向量if mykernel == 'LinearSVC': clf = svm.LinearSVC()else: clf = svm.SVC(kernel=mykernel,C=1000)# C-SVC的懲罰參數C,默認值是1.0 clf.fit(X,y)# 畫出數據點 plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.Paired,s=30)# 建立圖像坐標 ax = plt.gca() #當前的圖表和子圖可以使用plt.gcf()和plt.gca()獲得 xlim = ax.get_xlim() #返回當前Axes視圖的x的上下限 ylim = ax.get_ylim() #返回當前Axes視圖的y的上下限# 生成等差數列 xx = np.linspace(xlim[0],xlim[1],30) yy = np.linspace(ylim[0],ylim[1],30) YY , XX = np.meshgrid(yy,xx) # meshgrid函數用兩個坐標軸上的點在平面上畫網格。 xy = np.vstack([XX.ravel(),YY.ravel()]).T# np.hstack():橫向拼接,增加特徵量;np.vstack():縱向拼接,增加樣本個數 Z = clf.decision_function(xy). reshape(XX.shape)#decision_function:計算樣本點到分割超平面的函數距離#shape是查看數據有多少行多少列#reshape()是數組array中的方法,作用是將數據重新組織# 把分類決定邊界畫出來 ax.set_title(title) ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])#繪製等高線if mykernel != 'LinearSVC': ax.scatter(clf.support_vectors_[:,0],clf.support_vectors_[:,1],s=100,linewidth=1,facecolors='none')
def SVM_for_all_model(): models = ['linear','rbf','sigmoid','poly','LinearSVC'] titles = ['SVC with Linear Kernel','SVC with RBF Kernel','SVC with sigmoid Kernel','SVC with poly Kernel','LinearSVC'] figure, axs = plt.subplots(2,3,figsize =(10,3)) figure.suptitle('All Model of SVM') i = 0for model in models: plt.subplot(2,3,i+1) SVM_base(model,titles[i]) i = i+1 plt.show()我們再通過程序繪製Linear Kernel、RBF Kernel和poly Kernel 和LinearSVC的對紅酒數據畫出邊界曲線。
from sklearn import datasets#定義一個函數來畫圖def make_meshgrid(x, y, h=.02): x_min,x_max = x.min()-1,x.max()+1 y_min,y_max = y.min()-1,y.max()+1 xx, yy = np.meshgrid(np.arange(x_min, x_max, h),np.arange(y_min, y_max, h))return xx,yy#定義一個繪製等高線的函數def plot_contour(ax, clf, xx,yy,**params) : Z = clf.predict(np.c_[xx.ravel(),yy.ravel()]) Z = Z.reshape(xx.shape) out = ax.contourf(xx,yy,Z,**params)return out#不同核函數的SVM對比def compare_with_different_SVM(): wine = datasets.load_wine()#選取數據集前兩個特徵 X = wine.data[:,:2] y = wine.target C = 2.5 #SVM參數正則化 models = (svm.SVC(kernel='linear',C=C), svm.LinearSVC(C=C), svm.SVC(kernel='rbf',gamma=0.7,C=C), svm.SVC(kernel='sigmoid',C=C), svm.SVC(kernel='poly',degree=3,C=C)) models = (clf.fit(X,y) for clf in models)#設定圖標 titles = ('SVC with Linear Kernel','LinearSVC(Linear Kernel)','SVC with RBF Kernel','SVC with sigmoid Kernel','SVC with polynomial(degree 3) Kernel'#設置子圖形的個數和排列方式fig, sub = plt.subplots(2,3,figsize =(10,3))plt.subplots_adjust(wspace=0.4,hspace=0.4)#使用前面定義的函數畫圖X0, X1 = X[:,0],X[:,1] xx, yy = make_meshgrid(X0, X1)for clf, title, ax in zip(models, titles,sub.flatten()): plot_contour(ax,clf,xx,yy,cmap=plt.cm.plasma,alpha=0.8) ax.scatter(X0,X1,c=y,cmap=plt.cm.plasma,s=20,edgecolors='k') ax.set_xlim(xx.min(),xx.max()) ax.set_ylim(yy.min(),yy.max()) ax.set_xlabel('Feature 0') ax.set_ylabel('Feature 1') ax.set_xticks(()) ax.set_yticks(()) ax.set_title(title) plt.show()由此可以看出:
接下來我們看一下gamma參數。
def gamma_for_RBF(): wine = datasets.load_wine() X = wine.data[:,:2] y = wine.target C = 1.0 models =(svm.SVC(kernel='rbf',gamma=0.1,C=C), svm.SVC(kernel='rbf',gamma=1,C=C), svm.SVC(kernel='rbf',gamma=10,C=C)) models = (clf.fit(X,y) for clf in models)
titles = ('gamma = 0.1','gamma = 1','gamma = 10') fig, sub = plt.subplots(1,3,figsize =(10,3)) X0, X1 = X[:,0],X[:,1] xx, yy = make_meshgrid(X0, X1)for clf, title, ax in zip(models,titles,sub.flatten()): plot_contour(ax,clf,xx,yy,cmap=plt.cm.plasma,alpha=0.8) ax.scatter(X0,X1,c=y,cmap=plt.cm.plasma,s=20,edgecolors='k') ax.set_xlim(xx.min(),xx.max()) ax.set_ylim(yy.min(),yy.max()) ax.set_xlabel('Feature 0') ax.set_ylabel('Feature 1') ax.set_xticks(()) ax.set_yticks(()) ax.set_title(title) plt.show()由此可以看出:
SVM的優勢和劣勢如下:
SVM需要考慮:
我們下面通過波士頓房價數據例子來討論一下如何調優的過程。
from sklearn.pipeline import Pipelinefrom sklearn.preprocessing import StandardScalerfrom sklearn.model_selection import train_test_splitdef SVM_for_boston(): boston = datasets.load_boston() X,y = boston.data,boston.target X_train,X_test,y_train,y_test = train_test_split(X, y, random_state =8)for kernel in ['linear','rbf','sigmoid','poly']: svr = svm.SVR(kernel=kernel) svr.fit(X_train,y_train) print(kernel,'核函數的模型訓練集得分: {:.3f}'.format(svr.score(X_train,y_train))) print(kernel,'核函數的模型測試集得分: {:.3f}'.format(svr.score(X_test,y_test)))輸出
linear 核函數的模型訓練集得分: 0.709linear 核函數的模型測試集得分: 0.696rbf 核函數的模型訓練集得分: 0.192rbf 核函數的模型測試集得分: 0.222sigmoid 核函數的模型訓練集得分: 0.059sigmoid 核函數的模型測試集得分: 0.075poly 核函數的模型訓練集得分: 0.195poly 核函數的模型測試集得分: 0.207這個結果是非常糟糕的。通過下面程序來看一下數據分布圖。
ax = plt.gca()#將特徵數字中的最大和最小值一散點圖形式畫出來 plt.plot(X.min(axis=0),'v',label='min') plt.plot(X.max(axis=0),'^',label='max') plt.yscale('log') #縱坐標為對數形式 plt.legend(loc='best') #設置圖注位置最佳 ax.set_xlabel('feature') ax.set_ylabel('featuremagnitude') plt.show()圖標橫坐標是第幾個樣本,對應縱坐標為數據的最大最小值數據,由此可見數據在10-2到103之間,差距更大。下面我們通過StandardScaler()函數來對訓練集和測試集數據進行預處理。
#對訓練集和測試集數據進行預處理scaler = StandardScaler() scaler.fit(X_train) X_train_scaler =scaler.transform(X_train) X_test_scaler = scaler.transform(X_test) plt.plot(X_train_scaler.min(axis=0),'v',label='trainset min') plt.plot(X_train_scaler.max(axis=0),'^',label='trainset max') plt.plot(X_test_scaler.min(axis=0),'v',label='testset min') plt.plot(X_test_scaler.max(axis=0),'^',label='testset max') plt.legend(loc='best') ax.set_xlabel('scaledfeature') ax.set_ylabel('scaledfeature magnitude') plt.show()這樣數據集中在-4到10之間。我們通過預處理後的數據進行訓練模型。
for kernel in ['linear','rbf','sigmoid','poly']:
svr =svm.SVR(kernel=kernel)
svr.fit(X_train_scaler,y_train)
print(kernel,'預處理後訓練集得分:{:.3f}'.format(svr.score(X_train_scaler,y_train)))
print(kernel,'預處理後測試集得分:{:.3f}'.format(svr.score(X_test_scaler,y_test)))
輸出:
linear 預處理後訓練集得分: 0.706linear 預處理後測試集得分: 0.698rbf 預處理後訓練集得分: 0.665rbf 預處理後測試集得分: 0.695sigmoid 預處理後訓練集得分: 0.564sigmoid 預處理後測試集得分: 0.634poly 預處理後訓練集得分: 0.686poly 預處理後測試集得分: 0.623由此可見,Linear變化不大,其他都變化很大。下面我們調節下C與gamma參數,首先設置C=100,gamma=0.1。
# 調節參數for kernel in ['linear','rbf','sigmoid','poly']:svr = svm.SVR(kernel=kernel,C=100,gamma=0.1)svr.fit(X_train_scaler,y_train)print(kernel,'調節參數後訓練集得分: {:.3f}'.format(svr.score(X_train_scaler,y_train)))print(kernel,'調節參數後測試集得分:{:.3f}'.format(svr.score(X_test_scaler,y_test)))輸出
linear 調節參數後訓練集得分: 0.706linear 調節參數後測試集得分: 0.699rbf 調節參數後訓練集得分: 0.966rbf 調節參數後測試集得分: 0.894sigmoid 調節參數後訓練集得分: -3768.620sigmoid 調節參數後測試集得分: -5454.605poly 調節參數後訓練集得分: 0.950poly 調節參數後測試集得分: 0.318然後我們看一下C=100,gamma=0.005
# 調節參數for kernel in ['linear','rbf','sigmoid','poly』]: svr =svm.SVR(kernel=kernel,C=100,gamma=0.005) svr.fit(X_train_scaler,y_train) print(kernel,'調節參數(C=100,gamma=0.005)後訓練集得分:{:.3f}'.format(svr.score(X_train_scaler,y_train))) print(kernel,'調節參數(C=100,gamma=0.005)後測試集得分: {:.3f}'.format(svr.score(X_test_scaler,y_test)))輸出
linear 調節參數後訓練集得分: 0.706linear 調節參數後測試集得分: 0.699rbf 調節參數後訓練集得分: 0.841rbf 調節參數後測試集得分: 0.829sigmoid 調節參數後訓練集得分: 0.698sigmoid 調節參數後測試集得分: 0.695poly 調節參數後訓練集得分: 0.240poly 調節參數後測試集得分: 0.232最後繪製表格,分析一下輸出結果。
模型
預處理前
預處理後
調節參數後(gamma=0.1)
調節參數(gamma=0.005)
默認gamma與C
C=100
linear
0.709
0.706
0.706
0.706
0.696
0.698
0.699(不變)
0.699(不變)
rbf
0.192
0.665
0.966
0.841
0.222
0.695
0.894(提高)
0.829(略降)
sigmoid
0.059
0.564
-3768.620
0.698(提高)
0.075
0.634
-5454.605(失控)
0.695
poly
0.195
0.686
0.950
0.240(降低,但是不存在過擬合)
0.207
0.623
0.318(過擬合)
0.232
通過調節可以看出:
linear基本不受影響;
C=100,gamma=0.1:sigmoid失控,poly出現過擬合,rbf表現很好。
C=100,gamma=0.005:sigmoid恢復,poly出現降低,但是沒有過擬合現象,rbf略有下降。
由此可見,選擇模型類型和調節參數是非常重要的。
—————————————————————————————————
顧老師課程歡迎報名
軟體安全測試
https://study.163.com/course/courseMain.htm?courseId=1209779852&share=2&shareId=480000002205486
接口自動化測試
https://study.163.com/course/courseMain.htm?courseId=1209794815&share=2&shareId=480000002205486
DevOps 和Jenkins之DevOps
https://study.163.com/course/courseMain.htm?courseId=1209817844&share=2&shareId=480000002205486
DevOps與Jenkins 2.0之Jenkins
https://study.163.com/course/courseMain.htm?courseId=1209819843&share=2&shareId=480000002205486
Selenium自動化測試
https://study.163.com/course/courseMain.htm?courseId=1209835807&share=2&shareId=480000002205486
性能測試第1季:性能測試基礎知識
https://study.163.com/course/courseMain.htm?courseId=1209852815&share=2&shareId=480000002205486
性能測試第2季:LoadRunner12使用
https://study.163.com/course/courseMain.htm?courseId=1209980013&share=2&shareId=480000002205486
性能測試第3季:JMeter工具使用
https://study.163.com/course/courseMain.htm?courseId=1209903814&share=2&shareId=480000002205486
性能測試第4季:監控與調優
https://study.163.com/course/courseMain.htm?courseId=1209959801&share=2&shareId=480000002205486
Django入門
https://study.163.com/course/courseMain.htm?courseId=1210020806&share=2&shareId=480000002205486
啄木鳥顧老師漫談軟體測試
https://study.163.com/course/courseMain.htm?courseId=1209958326&share=2&shareId=480000002205486