動態

詳情 返回 返回

彩筆運維勇闖機器學習--隨機森林 - 動態 詳情

前言

隨機森林的出現,是為了解決決策樹對訓練數據過擬合的問題而出現的。決策樹在訓練的工程中,可以讓每一個葉子節點的不確定性降為0(即熵或者基尼指數為0),這樣做可能把訓練數據中的偶然性、異常值或噪聲也當成了“規 律”去學習了

對於複雜高維的數據,隨機森林的算法可以更好的泛化能力

開始探索

scikit-learn

老規矩,先上代碼,看看隨機森林的用法

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

clf = RandomForestClassifier(n_estimators=100, max_depth=3, random_state=0)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
print("隨機森林 分類報告:\n", classification_report(y_test, y_pred))

腳本!啓動:

watermarked-random_forest_1_1

鳶尾花數據集

決策樹那篇文章演示剪枝的時候,就使用了load_iris,它是 Scikit-learn 自帶的一個內置數據集加載器函數,用於獲取“鳶尾花數據集”,該數據集的信息:

  • 150條樣本
  • 4個特徵,sepal length, sepal width, petal length, petal width,分別代表萼片長度、萼片寬度、花瓣長度、花瓣寬度
  • 3個分類,Setosa、Versicolor、Virginica,標籤值分別為0 1 2

這是Scikit-learn提供的常用數據集,適用於學習、演示以及本人目前實在是找不到對應的數據來做練習 - -

深入理解隨機森林

隨機森林由許多決策樹組成,每棵樹都是在不同的樣本和特徵子集上訓練出來的。最終結果通過“投票”(分類)或“平均”(迴歸)方式整合

  • Bootstrap採樣:有N條樣本,每次隨機抽取N條樣本,並且是有放回抽樣,那就意味着有些樣本可能被抽取多次,有些一次也沒有被抽取
    • 假如原始集合\(D=\{x_1,x_2,x_3,x_4,x_5\}\),在一次有放回抽樣中,樣本為\(\{x_1,x_2,x_3,x_5,x_5\}\),那\(x_5\)被抽取了兩次,\(x_4\)一次都沒有被抽中,\(x_4\)被稱為OOB(out of bag)樣本
  • 將抽取的樣本訓練成決策樹,在訓練的過程中,特徵並不是全部考慮的,而是隨機選取一部分特徵進行劃分,每棵樹訓練的過程中都不剪枝
  • 訓練N棵樹之後之後
    • 分類任務採用多數多數投票法,即少數服從多數。比如森林中有5棵決策樹,對於樣本進行預測,3個預測為0,2個預測為1,那隨機森林對於該樣本的預測結果就是0
    • 迴歸任務採用平均值,顧名思義,求和取平均
  • 由於有一部分樣本(OOB樣本)一次也沒有被抽取,可以使用這些樣本進行評估,從而在不使用額外驗證集的情況下評估模型性能

理解了決策樹,就理解了隨機森林。決策樹,學習規則,直接預測結果;多棵決策樹組成的集成模型,通過投票(分類)或平均(迴歸)得出最終結果

方差

方差是衡量數據離散程度的數學特徵,方差越大,數據越分散,波動越大;方差越小,數據越集中,波動越小。在機器學習中,方差反應了模型對於訓練數據變化的敏感程度,方差越大,對於噪聲的變化越敏感,容易過擬合;方差越小,對於數據變化不敏感,泛化能力更強,但是有欠擬合的風險

決策樹就是方差較大的模型,因為決策樹會傾向於熵/基尼係數為0,它會一直分裂,導致樹非常的深,並且數據稍有變化,就產生了完全不同的樹結構。剪枝可以有效的避免高方差,預剪枝通過參數(最大深度,最小樣本分裂數等),控制數的深度,後剪枝可以參數(ccp_alpha)減掉樹枝,避免樹過深

隨機森林中是方差較小的模型,注意得益於它的抽樣方式,通過Bootstrap採樣,減少了特定訓練數據的依賴,再加上最後分類是通過所有樹投票,降低了單棵樹帶來的波動。其次不是所有特徵,而是隨機特徵,帶來樹分裂的次數 減少

常用參數

參數 含義 備註
n_estimators 森林中樹的數量 默認 100,建議:100~500,越多越穩但訓練慢
max_depth 每棵樹的最大深度 控制過擬合;常設為 5~30;默認 None
min_samples_split 節點最小分裂樣本數 控制過擬合,默認 2,設置大些可防止過擬合
min_samples_leaf 每個葉節點最少樣本數 默認 1,設置大些讓樹更“平滑”,防止過擬合
max_features 每次分裂考慮的特徵數 分類常用 'sqrt',迴歸常用 'auto' 或 'log2'
bootstrap 是否啓用 Bootstrap 採樣 默認 True;設為 False 表示使用全部數據(不推薦)

超參數調優

在之前的篇章中,曾經提到過超參數的概念,這裏再來詳細討論一下:超參數是模型訓練之前就要設置的,模型無法自己去學習超參數,超參數往往決定着模型的泛化能力。比如上述的n_estimators max_depth等,合理的設置這些參數能夠提高模型的泛化能力,減少過擬合

網格搜索

一種窮舉搜索的方法,用來尋找在給定超參數空間中,使模型性能最優的參數組合。它嘗試所有可能的參數組合,並對每一組組合進行模型訓練與評估

from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

rf = RandomForestClassifier(random_state=0)
param_grid = {
    'n_estimators': [50, 100, 150],
    'max_depth': [None, 5, 10],
    'min_samples_split': [2, 4]
}
grid_search = GridSearchCV(
    estimator=rf,
    param_grid=param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1
)
grid_search.fit(X_train, y_train)

print("最優參數組合:", grid_search.best_params_)

3個參數,n_estimators,max_depth,min_samples_split,分別將對應的取值進行窮舉搜索訓練,訓練的參考準確率(accuracy),誰的準確率高,就使用對應的參數組合。在訓練的過程中使用5折交叉驗證

腳本!啓動

watermarked-random_forest_1_2

隨機搜索

從給定的超參數空間中隨機採樣若干組參數組合進行訓練和評估

from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import RandomizedSearchCV, train_test_split
from sklearn.metrics import classification_report, accuracy_score
from scipy.stats import randint

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
rf = RandomForestClassifier(random_state=0)
param_dist = {
    'n_estimators': randint(50, 200),
    'max_depth': [None, 5, 10, 20],
    'min_samples_split': randint(2, 10),
    'max_features': ['sqrt', 'log2', None]
}
random_search = RandomizedSearchCV(
    estimator=rf,
    param_distributions=param_dist,
    n_iter=20,
    cv=5,
    scoring='accuracy',
    random_state=0,
    n_jobs=-1
)

random_search.fit(X_train, y_train)
print("最優參數組合:", random_search.best_params_)

n_iter是比較重要的參數,代碼中它限制了要嘗試20種不同的參數組合,在這其中選擇準確率最高的

watermarked-random_forest_1_3

貝葉斯優化

當面對海量的參數時,窮舉參數組合顯然不再適合,而貝葉斯優化的做法構造一個模型,該模型用來模擬:超參數與用這一組超參數訓練隨機森林之後的準確率之間的關係,從而智能地選擇下一組超參數進行評估。在每次嘗試的過程中,都會記錄超參數與隨機森林準確率,最終選擇準確率最高的那一組超參數

與隨機搜索的不同,就在於超參數的選擇,隨機搜索顧名思義,採取隨機的組合方式選擇參數,而貝葉斯則是選擇參數的過程是構建摸一個預測模型,對超參數和模型性能之間的關係進行建模,用模型來指導下一組參數應該選什麼,從而更快、更高效地找到最優組合

from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from skopt import BayesSearchCV
from skopt.space import Real, Integer, Categorical

X, y = load_iris(return_X_y=True)
model = RandomForestClassifier(random_state=0)
search_space = {
    'n_estimators': Integer(50, 200),
    'max_depth': Integer(2, 20),
    'min_samples_split': Integer(2, 10),
    'max_features': Categorical(['sqrt', 'log2', None])
}
opt = BayesSearchCV(
    estimator=model,
    search_spaces=search_space,
    n_iter=30,
    cv=5,
    scoring='accuracy',
    n_jobs=-1,
    random_state=0
)
opt.fit(X, y)

print("最優參數:", opt.best_params_)

watermarked-random_forest_1_4

小結

總結一下三種超參數調優的方法

方法 思想 優點 缺點 使用場景
網格搜索 窮舉所有可能的參數組合 簡單直觀,易於並行 參數過多導致計算代價高,無學習能力 參數較少,對性能要求不敏感
隨機搜索 隨機採樣參數組合 比網格搜索高效 不利用歷史信息採樣,隨機性大 參數空間大,資源有限
貝葉斯優化 構建一個代理模型來預測每組參數組合的性能,並基於此智能選擇下一個組合 樣本效率高,可快速收斂最優解,特別適合開銷大的模型 實現複雜,開銷大 超參數空間大且訓練開銷高,希望精細調優性能

聯繫我

  • 聯繫我,做深入的交流


至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...

Add a new 評論

Some HTML is okay.