涉及:
- 使用交叉驗證對模型進行評估
- 使用網格搜索尋找模型的最優參數
- 對分類模型的可信度進行評估
使用交叉驗證進行模型評估
以前的內容,經常涉及使用sklear中的train_test_split 將數據集拆分成訓練集和測試集,然后用訓練集訓練模型,再用模型去擬合測試集並對模型進行評分,來評估模型的准確度
1.sklearn中的交叉驗證法
統計學中,交叉驗證是一種常用於對於模型泛化性能進行評估的方法
和train_test_split方法不同的是,交叉驗證會反復地拆分數據集,並用來訓練多個模型
sklearn中默認使用的是 K折疊交叉驗證法:
還有“隨機拆分交叉驗證法”,“挨個兒試法”
交叉驗證的使用方法:
#導入紅酒數據集 from sklearn.datasets import load_wine #導入交叉驗證工具 from sklearn.model_selection import cross_val_score #導入用於分類的支持向量機模型 from sklearn.svm import SVC #載入紅酒數據集 wine = load_wine() #設置SVC的核函數為linear svc = SVC(kernel='linear') #使用交叉驗證法對SVC進行評分 scores = cross_val_score(svc,wine.data,wine.target) #得分 print(scores)
[0.83333333 0.95 1. ]
【結果分析】
先導入了scikit_learn的交叉驗證評分類,然后使用SVC對酒的數據集進行分類,默認情況下,cross_val_score會使用3個折疊,因此,會得到3個分數
模型的得分:
#使用.mean() 獲得分數的平均值 print(scores.mean())
0.9277777777777777
【結果分析】
交叉驗證法平均分為0.928分
將數據集拆成6個部分來評分——cross_val_score:
#設置cv參數為6 scores = cross_val_score(svc,wine.data,wine.target,cv=6) print(scores)
[0.86666667 0.9 0.93333333 0.96666667 1. 1. ]
print(scores.mean())
0.9444444444444445
【結果分析】
在sklearn中,cross_val_score對於分類模型默認使用的是K折疊交叉驗證,而對於分類模型則默認使用分層K交叉驗證法
要解釋啥是分層K交叉驗證法,先分析下酒的數據集:
#打印紅酒數據集的分類標簽 print(wine.target)
2.隨機拆分和“挨個兒試”
隨機拆分原理——先從數據集中隨機抽一部分數據作為訓練集,再從其余的部分隨機抽一部分作為測試集,進行評分后再迭代,重復上一步操作,直到把我們希望的迭代次數全跑完
#導入隨機拆分工具 from sklearn.model_selection import ShuffleSplit #設置拆分的數為10個 shuffle_split = ShuffleSplit(test_size=.2,train_size=.7,n_splits=10) #對拆分好的數據進行交叉驗證 scores = cross_val_score(svc,wine.data,wine.target,cv=shuffle_split) print(scores)
把每次迭代的測試集設為數據集的20%,而訓練集為70%,並且把整個數據集拆分成10個子集
【結果分析】
ShuffleSplit一共為SVC模型進行了10次評分,最終得分即10個評分的平均值
挨個兒試試:
把每個數據點都當成一個數據集,所以數據集里有多少樣本,它就迭代多少次
數據集較大——很耗時
數據集較小——評分准確度最高
#導入LeaveOneOut from sklearn.model_selection import LeaveOneOut #設置cv參數為leaveoneout cv = LeaveOneOut() #重新進行交叉驗證 scores = cross_val_score(svc,wine.data,wine.target,cv=cv) print('迭代次數:',len(scores)) print('平均分:',scores.mean())
迭代次數: 178 平均分: 0.9550561797752809
【結果分析】
由於酒的數據集中有178個樣本,所以迭代了178次
為啥要用交叉驗證法?
使用網格搜索優化模型參數
1.簡單網格搜索
用lasso算法為例:
在Lasso算法中,有兩個參數比較重要——正則化參數alpha,最大迭代次數max_iter
默認情況下alpha=1.0,max_iter=1000
假設,想試試當alpha分別取10.0 1.0 0.1 0.01這4個數值,而max_iter 分別取 100 1000 5000 10000時,模型表現有什么差別
如果按照手動調整的話,試16次。。。
#導入套索回歸模型 from sklearn.linear_model import Lasso #導入數據集拆分工具 from sklearn.model_selection import train_test_split X_train,X_test,y_train,y_test = train_test_split(wine.data,wine.target,random_state = 38) #設置初始分數為0 best_score = 0 #設置alpha的參數遍歷0.01,0.1,1,10 for alpha in [0.01,0.1,1,10]: #最大迭代數遍歷100,1000,5000,10000 for max_iter in [100,1000,5000,10000]: lasso = Lasso(alpha=alpha,max_iter=max_iter) #訓練套索回歸模型 lasso.fit(X_train,y_train) score = lasso.score(X_test,y_test) #令最佳分數為所有分數中的最高值 if score >best_score: best_score = score #定義字典,返回最佳參數和最佳迭代數 best_parameters={'alpha':alpha,'最大迭代數':max_iter} print('最高分:',best_score) print('最佳參數設置',best_parameters)
最高分: 0.8885499702025688 最佳參數設置 {'alpha': 0.01, '最大迭代數': 100}
【結果分析】
快速找到了~~
局限性:
所進行的16次評分都是基於同一個訓練集和測試集,這只能代表模型在該訓練集和測試集的得分情況,不能反映出新的數據集的情況
舉例:
修改train_test_split的random_state參數:【38--> 0】
#導入套索回歸模型 from sklearn.linear_model import Lasso #導入數據集拆分工具 from sklearn.model_selection import train_test_split X_train,X_test,y_train,y_test = train_test_split(wine.data,wine.target,random_state = 0) #設置初始分數為0 best_score = 0 #設置alpha的參數遍歷0.01,0.1,1,10 for alpha in [0.01,0.1,1,10]: #最大迭代數遍歷100,1000,5000,10000 for max_iter in [100,1000,5000,10000]: lasso = Lasso(alpha=alpha,max_iter=max_iter) #訓練套索回歸模型 lasso.fit(X_train,y_train) score = lasso.score(X_test,y_test) #令最佳分數為所有分數中的最高值 if score >best_score: best_score = score #定義字典,返回最佳參數和最佳迭代數 best_parameters={'alpha':alpha,'最大迭代數':max_iter} print('最高分:',best_score) print('最佳參數設置',best_parameters)
最高分: 0.8298747376836272 最佳參數設置 {'alpha': 0.1, '最大迭代數': 100}
【結果分析】
稍微對train_test_split拆分數據集的方式做一點變更,最高分酒降到了0.83
最佳alpha參數為0.1
為了解決這個問題——與交叉驗證結合的網格搜索
2.與交叉驗證結合的網格搜索
#導入numpy import numpy as np #設置alpha的參數遍歷0.01,0.1,1,10 for alpha in [0.01,0.1,1.0,10.0]: #最大迭代數遍歷100,1000,5000,10000 for max_iter in [100,1000,5000,10000]: lasso = Lasso(alpha=alpha,max_iter=max_iter) scores = cross_val_score(lasso,X_train,y_train,cv=6) score = np.mean(scores) #令最佳分數為所有分數中的最高值 if score >best_score: best_score = score #定義字典,返回最佳參數和最佳迭代數 best_parameters={'alpha':alpha,'最大迭代數':max_iter} print('最高分:',best_score) print('最佳參數設置',best_parameters)
最高分: 0.8652073211223437 最佳參數設置 {'alpha': 0.01, '最大迭代數': 100}
【結果分析】
這里我們做了一點手腳,就是只用先前拆分好的X_train來進行交叉驗證,以便於我們找到最佳參數后,再用來擬合X_test 來看一下模型的得分
#用最佳參數模型擬合數據 lasso = Lasso(alpha=0.01,max_iter=100).fit(X_train,y_train) print('數據集得分:',lasso.score(X_test,y_test))
數據集得分: 0.819334891919453
【結果分析】
此處,並不是參數的問題,而是lasso算法會對樣本的特征進行正則化,導致一些特征的系數變為0,也就是說會拋棄一些特征值
對於酒集來說,本身特征就不多,因此使用lasso進行分類,得分會相對低些
在sklearn中,內置了一個類,GridSearchCV,進行參數調優的過程簡單:
#導入網格搜索工具 from sklearn.model_selection import GridSearchCV #將需要遍歷的參數定義為字典 params = {'alpha':[0.01,0.1,1.0,10.0],'max_iter':[100,1000,5000,10000]} #定義網格搜索中使用的模型和參數 grid_search = GridSearchCV(lasso,params,cv=6) #使用網格搜索模型擬合數據 grid_search.fit(X_train,y_train) print('模型最高分:',grid_search.score(X_test,y_test)) print('最優參數:',grid_search.best_params_)
模型最高分: 0.819334891919453 最優參數: {'alpha': 0.01, 'max_iter': 100}
【結果分析】
GridSearchCV中的best_scores_ 屬性,會存儲模型在交叉驗證中所得的最高分,而不是測試集上的得分
#打印網格搜索中的best_score_屬性 print('交叉驗證最高分:',grid_search.best_score_)
交叉驗證最高分: 0.8653192931146032
【結果分析】
這里的得分和cross_val_score得分是完全一致的,說明GridSearchCV 本身就是將交叉驗證和網格搜索封裝一起的方法
GridSearchCV雖然強悍,但需要反復建模——> 所需要的計算時間往往更長
分類模型的可信度評估
實際上算法在分類過程中,會認為某個數據點80%可能性屬於分類1,20%可能性屬於分類0,模型會依據“可能性較大”的方式分配分類標簽
算法是如何對這種分類的可能性進行計算的?
1.分類模型中的預測准確率
在sklearn中,很多用於分類的模型都有一個 predict_proba功能——用於計算模型在對數據集進行分類時,每個樣本屬於不同分類的可能性是多少
#導入數據集生成工具 from sklearn.datasets import make_blobs #導入畫圖工具 import matplotlib.pyplot as plt #生成樣本數為200,分類為2,標准差為5的數據集 X,y = make_blobs(n_samples=200,random_state=1,centers=2,cluster_std =5) #繪制散點圖 plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.cool,edgecolor='k') plt.show()
使用make_blobs 制作數據集,為了給算法點難度,故意把數據集的方差設高點cluster_std=5
【結果分析】
像評價女朋友衣服——紅色--好看,青藍色—不好看,中間的點—還可以
使用高斯朴素貝葉斯分類:
#導入高斯貝葉斯模型 from sklearn.naive_bayes import GaussianNB X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=68) #訓練高斯貝葉斯模型 gnb = GaussianNB() gnb.fit(X_train,y_train) #獲得高斯貝葉斯的分類准確概率 predict_proba = gnb.predict_proba(X_test) print('預測准確率形態:',predict_proba.shape)
預測准確率形態: (50, 2)
【結果分析】
在predict_proba 屬性中存儲了50個數組【即測試集大小】,每個數組有2個元素
打印一下前5個:
#打印准確概率的前5個 print(predict_proba[:5])
[[0.98849996 0.01150004] [0.0495985 0.9504015 ] [0.01648034 0.98351966] [0.8168274 0.1831726 ] [0.00282471 0.99717529]]
【結果分析】
反應的是測試集前5個樣本的分類准確率
用圖像直觀看下predict_proba 在分類過程中的表現:
#設定橫縱軸范圍 x_min,x_max= X[:,0].min()-.5,X[:,0].max()+.5 y_min,y_max= X[:,1].min()-.5,X[:,1].max()+.5 xx,yy = np.meshgrid(np.arange(x_min,x_max,0.2),np.arange(y_min,y_max,0.2)) Z = gnb.predict_proba(np.c_[xx.ravel(),yy.ravel()])[:,1] Z = Z.reshape(xx.shape) #繪制等高線 plt.contourf(xx,yy,Z,cmap=plt.cm.summer,alpha=.8) #繪制散點圖 plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolor='k') plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,edgecolor='k',alpha=0.6) #設置橫縱軸范圍 plt.xlim(xx.min(),xx.max()) plt.ylim(yy.min(),yy.max()) #設置橫縱軸的單位 plt.xticks(()) plt.yticks(()) plt.show()
【結果分析】
圓點代表樣本數據
棕色為第一個分類,藍色為第二個分類,漸變色區域,就是模型覺得“還可以”的部分
2.分類模型中的決定系數
同預測准確率類似,決定系數decision_function 也會給我們返回一些數值——告訴我們模型認為某個數據點處於某個分類的“把握”有多大
不同的是,在二元分類任務中,只返回一個值——正數,屬於分類1;負數,屬於分類2
高斯朴素貝葉斯沒有decision_function屬性——> 使用支持向量機SVM算法建模:
#導入SVC模型 from sklearn.svm import SVC #使用訓練集訓練模型 svc = SVC().fit(X_train,y_train) #獲得SVC的決定系數 dec_func = svc.decision_function(X_test) #打印決定系數中的前5個 print(dec_func[:5])
[ 0.02082432 0.87852242 1.01696254 -0.30356558 0.95924836]
圖形化展示desicion_function原理:
#使用決定系數繪圖 Z = svc.decision_function(np.c_[xx.ravel(),yy.ravel()]) Z = Z.reshape(xx.shape) #繪制等高線 plt.contourf(xx,yy,Z,cmap=plt.cm.summer,alpha=.8) plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=plt.cm.cool,edgecolor='k') #繪制散點圖 plt.scatter(X_test[:,0],X_test[:,1],c=y_test,cmap=plt.cm.cool,edgecolor='k',alpha=0.6) plt.title('SVC decision_function') #設置橫縱軸范圍 plt.xlim(xx.min(),xx.max()) plt.ylim(yy.min(),yy.max()) #設置橫縱軸的單位 plt.xticks(()) plt.yticks(()) plt.show()
.score給模型評分的方法
- 對於分類模型來說,默認情況下,.score給出的是模型分類的准確率
- 對於回歸模型來說,默認情況下, .score給出的是回歸分析中的R2分數【即,可決系數或擬合優度】
其他評分的方法:
GridSearchCV改變評分的方式:
#修改scoring參數為roc_auc grid = GridSearchCV(RandomForestClassifier*(,param_grid = param_grid,scoring = 'roc_auc')
這樣,模型的參數就是 roc_auc 方式了