機器學習【十】模型評估與優化


涉及:

  • 使用交叉驗證對模型進行評估
  • 使用網格搜索尋找模型的最優參數
  • 對分類模型的可信度進行評估

使用交叉驗證進行模型評估

以前的內容,經常涉及使用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 方式了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM