本篇文章是隨機森林氣溫預測任務的最后一篇文章啦袋哼,本文我們的主要內容就是 調參。前面在介紹隨機森林算法的時候第焰,我們知道在建立樹模型的時候果录,我們通常會使用預剪枝策略上枕,邊建立決策樹邊限制樹的復雜度,以防止樹模型出現(xiàn)過擬合的現(xiàn)象弱恒。
接下來辨萍,我們調參的參數(shù)大部分都是和預剪枝策略相關的,比如樹的深度返弹、葉子節(jié)點的個數(shù)锈玉、切分的最小樣本數(shù)、葉子節(jié)點最小樣本個數(shù)等等义起。話不多說拉背,一起來開始今天的學習吧~
數(shù)據(jù)集讀取、預處理和切分
讀取數(shù)據(jù)集:
import pandas as pd
import os
df = pd.read_csv("data" + os.sep + "temps_extended.csv")
df.head()
數(shù)據(jù)特征這里就不介紹了默终,前面的文章我們已經(jīng)詳細地討論過特征啦~
進行度熱編碼椅棺、數(shù)據(jù)集切分:
import numpy as np
from sklearn.model_selection import train_test_split
def get_train_test(df):
data = pd.get_dummies(df)
y = data.actual
X = data.drop('actual',axis=1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
return X_train, X_test, y_train, y_test
X_train, X_test, y_train, y_test = get_train_test(df)
訓練集和測試集樣本情況:
>> X_train.shape, X_test.shape
((1643, 17), (548, 17))
在開始調參前,我們需要先看看隨機森林 RandomForestRegressor
有哪些參數(shù):
>> from sklearn.ensemble import RandomForestRegressor
>> rfr = RandomForestRegressor(random_state=0)
>> rfr.get_params()
{'bootstrap': True,
'ccp_alpha': 0.0,
'criterion': 'squared_error',
'max_depth': None,
'max_features': 'auto',
'max_leaf_nodes': None,
'max_samples': None,
'min_impurity_decrease': 0.0,
'min_samples_leaf': 1,
'min_samples_split': 2,
'min_weight_fraction_leaf': 0.0,
'n_estimators': 100,
'n_jobs': None,
'oob_score': False,
'random_state': 0,
'verbose': 0,
'warm_start': False}
我們接下來的調參主要選擇其中比較重要的幾個:
-
max_depth
:樹的深度 -
max_features
:選取的特征個數(shù) -
min_samples_leaf
:葉子節(jié)點包含的最少樣本數(shù) -
min_samples_split
:切分節(jié)點時的最少樣本數(shù) -
n_estimators
:隨機森林中樹的個數(shù)
下面的調參工作齐蔽,小魚也將圍繞這 5 個特征展開两疚。
RandomizedSearchCV 隨機搜索
在開始任務之前,首先選擇一個大致的合適區(qū)間作為參數(shù)空間:
n_estimators = [int(x) for x in np.linspace(50, 1000, 5)]
max_depth = [int(x) for x in np.linspace(10, 30, 5)]
max_features = [6, 8, 10, 12, 16]
min_samples_split = [2, 5, 9, 13, 17]
min_samples_leaf = [1, 4, 7, 10, 13]
random_grid = {
"n_estimators": n_estimators,
"max_depth": max_depth,
"min_samples_split": min_samples_split,
"min_samples_leaf": min_samples_leaf,
"max_features": max_features
}
輸出:
>> random_grid
{'n_estimators': [50, 287, 525, 762, 1000],
'max_depth': [10, 15, 20, 25, 30],
'min_samples_split': [2, 5, 9, 13, 17],
'min_samples_leaf': [1, 4, 7, 10, 13],
'max_features': [6, 8, 10, 12, 16]}
對于每個參數(shù)含滴,小魚都列出了 5 個取值诱渤,參數(shù)有 5 個,一共會產(chǎn)生 5**5 = 3125
種組合蛙吏,再加上個 3 折的交叉驗證源哩,那么一共就需要訓練 9375 個模型,這樣我們調參的效率也就太低了鸦做。
那有什么辦法可以解決效率問題呢励烦?
答案就是 RandomizedSearchCV
,這個函數(shù)可以幫助我們在候選集組合中泼诱,隨機地選擇幾組合適的參數(shù)來建模坛掠,并且求其交叉驗證后的評估結果。以此來大致地找到一個最合適的參數(shù)治筒。
這樣不我們就不需要訓練 9375 個模型屉栓,找到最優(yōu)的參數(shù)組合了。比如隨機選擇其中的 200 組參數(shù)耸袜,并進行 3 折交叉驗證友多,那么一共只需要訓練 600 個模型。
下面是代碼部分:
from sklearn.model_selection import RandomizedSearchCV
# 隨機選擇最合適的參數(shù)組合
rf = RandomForestRegressor(random_state=0)
rf_random = RandomizedSearchCV(
estimator=rf,
param_distributions=random_grid,
n_iter=100,
scoring="neg_mean_absolute_error",
cv=3,
verbose=2,
random_state=0,
n_jobs=-1
)
rf_random.fit(X_train, y_train)
RandomizedSearchCV
參數(shù)說明:
-
estimator
:RandomizedSearchCV
這個方法是一個通用的堤框,并不是專為隨機森林設計的域滥,所以我們需要指定選擇的算法模型是什么纵柿。 -
distributions
:參數(shù)的候選空間,就是我們用字典格式給出的參數(shù)候選值启绰。 -
n_iter
:隨機尋找參數(shù)組合的個數(shù)昂儒,比如在這里我們賦值了 100,代表接下來要隨機找 100 組參數(shù)的組合委可,然后在其中找到最好的一組渊跋。 -
scoring
:模型的評估方法,即按照該方法去找到最好的參數(shù)組合着倾。 -
cv
:幾折交叉驗證拾酝。 -
random_state
:隨機種子,為了使得咱們的結果能夠一致屈呕,排除掉隨機成分的干擾微宝,一般我們都會指定成一個值。 -
n_jobs
:多進程訓練虎眨,如果是 -1 就會用所有的 CPU蟋软。
輸出:
Fitting 3 folds for each of 100 candidates, totalling 300 fits
RandomizedSearchCV(cv=3, estimator=RandomForestRegressor(random_state=0),
n_iter=100, n_jobs=-1,
param_distributions={'max_depth': [10, 15, 20, 25, 30],
'max_features': [6, 8, 10, 12, 16],
'min_samples_leaf': [1, 4, 7, 10, 13],
'min_samples_split': [2, 5, 9, 13, 17],
'n_estimators': [50, 287, 525, 762,
1000]},
random_state=0, scoring='neg_mean_absolute_error',
verbose=2)
獲取最優(yōu)的參數(shù)組合:
>> rf_random.best_params_
{'n_estimators': 50,
'min_samples_split': 5,
'min_samples_leaf': 10,
'max_features': 16,
'max_depth': 25}
接下來,我們使用測試集來實際看看調參的結果如何嗽桩。定義相關函數(shù):
def predict_and_evaluate(model, x_test, y_test, print_mape=True):
predictions = model.predict(x_test)
# 計算誤差 MAPE (Mean Absolute Percentage Error)
errors = abs(predictions - y_test)
mape = errors / y_test
if print_mape:
print(f'MAPE:{mape.mean():.2%}')
return mape.mean()
使用默認參數(shù)建模:
>> base_model = RandomForestRegressor(random_state=0)
>> base_model.fit(X_train, y_train)
>> predict_and_evaluate(base_model, X_test, y_test)
MAPE:6.65%
使用 RandomizedSearchCV
為我們找到的最優(yōu)參數(shù)組合:
>> best_random = rf_random.best_estimator_
>> predict_and_evaluate(best_random, X_test, y_test)
MAPE:6.60%
可以看到模型的效果提升了一些岳守,但是這已經(jīng)是上限了嗎?
GridSearchCV 網(wǎng)格搜索
RandomizedSearchCV 在隨機搜索時碌冶,相當于為我們鎖定了大致的范圍湿痢。接下來就要靠 GridSearchCV 在縮小后的范圍內開展地毯式搜索了,這就是網(wǎng)絡搜索扑庞,說白了就是將所有的參數(shù)組合都進行一遍譬重。
在隨機搜索時,我們得到的最優(yōu)參數(shù)組合為:
{'n_estimators': 50,
'min_samples_split': 5,
'min_samples_leaf': 10,
'max_features': 16,
'max_depth': 25}
在參數(shù)的附近罐氨,定義網(wǎng)格搜索的參數(shù)空間:
# 網(wǎng)絡搜索
param_grid = {
'n_estimators': [50, 100, 200],
'min_samples_split': [4, 5, 6],
'min_samples_leaf': [9, 10, 11],
'max_features': [15, 16, 17],
'max_depth': [24, 25, 26]
}
進行網(wǎng)格搜索和交叉驗證:
from sklearn.model_selection import GridSearchCV
rf = RandomForestRegressor(random_state=0)
grid_search = GridSearchCV(
estimator=rf,
param_grid=param_grid,
scoring='neg_mean_absolute_error',
cv=3,
n_jobs=-1,
verbose=2
)
grid_search.fit(X_train, y_train)
輸出:
Fitting 3 folds for each of 243 candidates, totalling 729 fits
GridSearchCV(cv=3, estimator=RandomForestRegressor(random_state=0), n_jobs=-1,
param_grid={'max_depth': [24, 25, 26],
'max_features': [15, 16, 17],
'min_samples_leaf': [9, 10, 11],
'min_samples_split': [4, 5, 6],
'n_estimators': [50, 100, 200]},
scoring='neg_mean_absolute_error', verbose=2)
網(wǎng)格搜索最佳參數(shù)組合:
>> grid_search.best_params_
{'max_depth': 24,
'max_features': 15,
'min_samples_leaf': 10,
'min_samples_split': 4,
'n_estimators': 50}
評估:
>> predict_and_evaluate(grid_search.best_estimator_, X_test, y_test)
MAPE:6.59%
誤差下降了 0.01 個百分點臀规,改善效果不是很明顯≌ひ可以多來幾組地毯式搜索找到最優(yōu)的參數(shù)組合塔嬉。
總結
隨機搜索可以更節(jié)約時間,尤其是在任務開始階段租悄,我們并不知道哪一個參數(shù)在哪一個位置效果能更好谨究,這樣我們可以把參數(shù)間隔設置的更大一些,先用隨機搜索確定一些大致位置泣棋。
網(wǎng)絡搜索相當于地毯式搜索胶哲,當我們得到了大致位置之后,想在這里尋找到最優(yōu)參數(shù)的時候就派上用場了潭辈⊙煊欤可以把隨機和網(wǎng)絡搜索當做一套組合拳俩檬,搭配使用。
調參的方法其實還有很多碾盟,比如貝葉斯優(yōu)化。上述的調參方式技竟,每一個都是獨立的進行不會對之后的結果產(chǎn)生任何影響冰肴,貝葉斯優(yōu)化的基本思想在于每一個優(yōu)化都是在不斷積累經(jīng)驗,這樣我會慢慢得到最終的解應當在的位置榔组,相當于前一步結果會對后面產(chǎn)生影響了熙尉。