一般情況下,我們做數據挖掘任務都是按照“數據預處理 - 特征工程 - 構建模型(使用默認參數或經驗參數) - 模型評估 - 參數優化 - 模型固定”這樣一個流程來處理問題。這一小節,我們要討論的主題就是參數優化,前面我們討論過GridSearchCV(網格搜索)這個工具,它是對我們的參數進行組合,選取效果最好的那組參數。
這一節,我們探索下參數優化當中的另一個工具RandomizedSearchCV(隨機搜索),這名字咋一聽感覺有點不太靠譜,對,它是有點不太靠譜,但為什么我們還要用它呢?因為它的效率高,它可以快速地幫助我們確定一個參數的大概范圍,然后我們再使用網格搜索確定參數的精確值。就像警察抓犯人一樣,先得快速地確認罪犯的活動區域,然后在該區域內展開地毯式搜索,這樣效率更高。
這一小節,我們以隨機森林模型作為例子,通過演示一個完整的建模過程,來說明RandomizedSearchCV的用法。當然這個工具不是隨機森林特有的,它可以應用于任何模型的參數優化當中。
從上圖可以看出隨機森林模型有很多參數,如:n_estimators, max_depth, min_samples_split, min_samples_leaf,max_features,bootstrap等。每一個參數都會對最終結果產生影響,同時每一個參數又有著眾多的取值,我們的目標是找到最優的參數組合,使得我們的模型效果最好。
RandomizedSearchCV工具:
官方文檔:
https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html?highlight=randomized#sklearn.model_selection.RandomizedSearchCV
RandomizedSearchCV參數說明:
- estimator:我們要傳入的模型,如KNN,LogisticRegression,RandomForestRegression等。
- params_distributions:參數分布,字典格式。將我們所傳入模型當中的參數組合為一個字典。
- n_iter:隨機尋找參數組合的數量,默認值為10。
- scoring:模型的評估方法。在分類模型中有accuracy,precision,recall_score,roc_auc_score等,在回歸模型中有MSE,RMSE等。
- n_jobs:并行計算時使用的計算機核心數量,默認值為1。當n_jobs的值設為-1時,則使用所有的處理器。
- iid:bool變量,默認為deprecated,返回值為每折交叉驗證的值。當iid = True時,返回的是交叉驗證的均值。
- cv:交叉驗證的折數,最新的sklearn庫默認為5。
接下來,我們采用溫度數據集作為例子,來演示RandomizedSearchCV的用法。我們將進行一個完整的數據建模過程:數據預處理 - 模型搭建 - RandomizedSearchCV參數優化 - GridSearchCV參數優化 - 確定最優參數,確定模型。
溫度數據集:鏈接:https://pan.baidu.com/s/1q10_Vz7ujuu8oCOqysNU7A
提取碼:bxcr
任務目標:基于昨天和前天的一些歷史天氣數據,建立模型,預測當天的最高的真實溫度。
數據集中主要特征說明:
- ws_1:昨天的風速。
- prcp_1:昨天的降水量。
- snwd_1:昨天的降雪厚度。
- temp_1:昨天的最高溫度。
- temp_2:前天的最高溫度。
- average:歷史中這一天的平均最高溫度。
- actual:當天的真實最高溫度。
建模完整過程演示:
#導入數據分析的兩大工具包
import numpy as np
import pandas as pd
#讀取數據
df = pd.read_csv('D:\\Py_dataset\\temps_extended.csv')
df.head()
#查看數據的規模
df.shape
(2191, 12)#該數據集有2191個樣本,每個樣本有12個特征。
1.數據預處理
該數據集整體上是比較干凈的,沒有缺失值和異常值。這一步我們熟悉下數據預處理的基本過程。
# 1.查看數據集的基本信息
df.info()
從上述結果可以看出這份數據集的整體情況。一共2191個樣本,索引從0開始,截止于2190。一共12個特征,每個特征的數量為2191,缺失值情況(non-null),類型(int64 or object or float64),內存使用205.5KB。
由于數據沒有缺失值,所以我們不需要做缺失值處理。接下來我們看數據類型,由于計算機只能識別數值型數據,所以我們必須將數據集中的非數值型數據轉化為數值型數據。該數據集中只有"weekday"是object類型,由于我們要預測的是今天的溫度值,所以日期數據(如昨天是幾號,星期幾)對我們的結果沒有什么影響,將這些日期數據刪掉。數據集中有一個"friend"特征,該值的意思可能是朋友的猜測結果,在建模過程中,我們暫不關注這個特征,所以將"friend"特征也刪掉。
df = df.drop(['year','month','day','weekday','friend'],axis = 1)
df.head()
2.數據切分
當我們完成了數據集清洗之后,接下來就是將原始數據集切分為特征(features)和標簽(labels)。接著將特征和標簽再次切分為訓練特征,測試特征,訓練標簽和測試標簽。
#導入數據切分模塊
from sklearn.model_selection import train_test_split
#提取數據標簽
labels = df['actual']
#提取數據特征
features = df.drop('actual',axis = 1)
#將數據切分為訓練集和測試集
train_features,test_features,train_labels,test_labels = train_test_split(features,labels,
test_size = 0.3,random_state = 0)
print('訓練特征的規模:',train_features.shape)
print('訓練標簽的規模:',train_labels.shape)
print('測試特征的規模:',test_features.shape)
print('測試標簽的規模:',test_labels.shape)
#切分之后的結果
訓練特征的規模: (1533, 6)
訓練標簽的規模: (1533,)
測試特征的規模: (658, 6)
測試標簽的規模: (658,)
3.建立初始隨機森林模型
建立初始模型,基本上都使用模型的默認參數,建立RF(RandomForestRegressor)模型,我們唯一指定了一個n_estimators參數。
from sklearn.ensemble import RandomForestRegressor
#建立初始模型
RF = RandomForestRegressor(n_estimators = 100,random_state = 0)
#訓練數據
RF.fit(train_features,train_labels)
#預測數據
predictions = RF.predict(test_features)
4.模型評估
該例子我們使用的是回歸模型,預測結果是一個準確的數值。我們的目標是希望我們的預測結果與真實數據的誤差越好。所以我們在此選用的模型評估方法為均方誤差(mean_squared_error)和均方根誤差(root_mean_squared_error)。下式分別是MSE和RMSE的計算公式,其中Yi為真實值,Yi^為預測值。
from sklearn.metrics import mean_squared_error
#傳入真實值,預測值
MSE = mean_squared_error(test_labels,predictions)
RMSE = np.sqrt(MSE)
print('模型預測誤差:',RMSE)
模型預測誤差: 5.068073484568353
5.RandomizdSearchCV參數優化
from sklearn.model_selection import RandomizedSearchCV
RF = RandomForestRegressor()
#設置初始的參數空間
n_estimators = [int(x) for x in np.linspace(start = 200,stop = 2000,num = 10)]
min_samples_split = [2,5,10]
min_samples_leaf = [1,2,4]
max_depth = [5,8,10]
max_features = ['auto','sqrt']
bootstrap = [True,False]
#將參數整理為字典格式
random_params_group = {'n_estimators':n_estimators,
'min_samples_split':min_samples_split,
'min_samples_leaf':min_samples_leaf,
'max_depth':max_depth,
'max_features':max_features,
'bootstrap':bootstrap}
#建立RandomizedSearchCV模型
random_model =RandomizedSearchCV(RF,param_distributions = random_params_group,n_iter = 100,
scoring = 'neg_mean_squared_error',verbose = 2,n_jobs = -1,cv = 3,random_state = 0)
#使用該模型訓練數據
random_model.fit(train_features,train_labels)
我們觀察下模型的訓練過程,我們設置了n_iter=100,由于交叉驗證的折數=3,所以該模型要迭代300次。第二層顯示的是訓練過程的用時,訓練完成總共用了6.2min。第三層顯示的是參與訓練的參數。
使用集成算法的屬性,獲得Random_model最好的參數
random_model.best_params_
{'n_estimators': 1200,
'min_samples_split': 5,
'min_samples_leaf': 4,
'max_features': 'auto',
'max_depth': 5,
'bootstrap': True}
將得出的最優參數,傳給RF模型,再次訓練參數,并進行結果預測??梢钥吹浇涍^參數優化后,模型的效果提升了2%。
RF = RandomForestRegressor(n_estimators = 1200,min_samples_split = 5,
min_samples_leaf = 4,max_features = 'auto',max_depth = 5,bootstrap = True)
RF.fit(train_features,train_labels)
predictions = RF.predict(test_features)
RMSE = np.sqrt(mean_squared_error(test_labels,predictions))
print('模型預測誤差:',RMSE)
print('模型的提升效果:{}'.format(round(100*(5.06-4.96)/5.06),2),'%')
模型預測誤差: 4.966401154246091
模型的提升效果:2 %
6.使用GridSearhCV對參數進行進一步優化
上一步基本上確定了參數的大概范圍,這一步我們在該范圍,進行更加細致的搜索。網格搜索的效率比較低,這里我只選擇了少數的幾個參數,但是用時也達到了9分鐘。如果參數增加,模型訓練的時間將會大幅增加。
from sklearn.model_selection import GridSearchCV
import time
param_grid = {'n_estimators':[1100,1200,1300],
'min_samples_split':[4,5,6,7],
'min_samples_leaf':[3,4,5],
'max_depth':[4,5,6,7]}
RF = RandomForestRegressor()
grid = GridSearchCV(RF,param_grid = param_grid,scoring = 'neg_mean_squared_error',cv = 3,n_jobs = -1)
start_time = time.time()
grid.fit(train_features,train_labels)
end_time = time.time()
print('模型訓練用時:{}'.format(end_time - start_time))
模型訓練用時:534.4072196483612
獲得grid模型最好的參數
grid.best_params_
{'max_depth': 5,
'min_samples_leaf': 5,
'min_samples_split': 6,
'n_estimators': 1100}
將最好的模型參數傳給RF模型,再次對數據進行訓練并作出預測。
RF = RandomForestRegressor(n_estimators = 1100,min_samples_split = 6,
min_samples_leaf = 5,max_features = 'auto',max_depth = 5,bootstrap = True)
RF.fit(train_features,train_labels)
predictions = RF.predict(test_features)
RMSE = np.sqrt(mean_squared_error(test_labels,predictions))
print('模型預測誤差:',RMSE)
模型預測誤差: 4.969890784882202
從結果來看,模型效果并沒有什么提升,說明在隨機搜索的過程中,已經找到了最優參數。最終結果模型預測的溫度與實際溫度相差4.96華氏度(2.75℃)。我們以該數據集作為一個示例,總結數據挖掘的全過程以及RandomizedSearchCV工具,在具體的調參工作中也是通過一步一步去優化參數,不斷縮小預測值與真實值之間的誤差。
7.總結
- 1.隨機參數選擇模型(RandomizedSearchCV)可以幫助我們快速的確定參數的范圍。
- 2.對于隨機參數選擇模型而言,初始的特征空間選擇特別重要。如果出事的特征空間選擇不對,則后面的調參工作都可能是徒勞。我們可參考一些經驗值或者做一些對比試驗,來確定模型的參數空間。
- 3.RandomizedSearchCV和GridSearchCV搭配使用,先找大致范圍,再精確搜索。
- 4.通過優化模型參數,雖然每次的提升幅度不是很大,但是通過多次的優化,這些小的提升累加在一起就是很大的提升。
- 5.遇到不懂的問題,多查看sklearn官方文檔,這是一個逐漸積累和提升的過程。