隨機(jī)森林是非常具有代表性的Bagging集成算法,它的所有基評(píng)估器都是決策樹(shù) ,分類(lèi)樹(shù)組成的森林就叫做隨機(jī)森林分類(lèi)器,回歸樹(shù)所集成的森林就叫做隨機(jī)森林回歸器。
隨機(jī)森林采用決策樹(shù)作為弱分類(lèi)器,在bagging
的樣本隨機(jī)采樣 基礎(chǔ)上,?加上了特征的隨機(jī)選擇。
當(dāng)前結(jié)點(diǎn)特征集合 ( 個(gè)特征),隨機(jī)選擇 個(gè)特征子集,再選擇最優(yōu)特征進(jìn)行劃分。 控制了隨機(jī)性的引入程度,推薦值:
算法步驟
從樣本集N中有放回隨機(jī)采樣選出個(gè)樣本。 從所有特征中隨機(jī)選擇k個(gè)特征,對(duì)選出的樣本利用這些特征建立決策樹(shù)(一般是CART方法)。 重復(fù)以上兩步次,生成棵決策樹(shù),形成隨機(jī)森林,其中生成的決策樹(shù)不剪枝。
sklearn中的RandomForestClassifier
from sklearn.ensemble import RandomForestClassifierRandomForestClassifier(n_estimators=100 , *, criterion='gini' , max_depth=None , min_samples_split=2 , min_samples_leaf=1 , min_weight_fraction_leaf=0.0 , max_features='auto' , max_leaf_nodes=None , min_impurity_decrease=0.0 , min_impurity_split=None , bootstrap=True , oob_score=False , n_jobs=None , random_state=None , verbose=0 , warm_start=False , class_weight=None , ccp_alpha=0.0 , max_samples=None )
criterion: 不純度的衡量指標(biāo),有基尼系數(shù)和信息熵兩種選擇
max_depth: 樹(shù)的最大深度,超過(guò)最大深度的樹(shù)枝都會(huì)被剪掉
min_samples_leaf: 一個(gè)節(jié)點(diǎn)在分枝后的每個(gè)子節(jié)點(diǎn)都必須包含至少個(gè)訓(xùn)練樣 本,否則分枝就不會(huì)發(fā)生
min_samples_leaf: 一個(gè)節(jié)點(diǎn)必須要包含至少min_samples_split個(gè)訓(xùn)練樣本,這個(gè)節(jié)點(diǎn)才允許被分 枝,否則分枝就不會(huì)發(fā)生
max_features: 限制分枝時(shí)考慮的特征個(gè)數(shù),超過(guò)限制個(gè)數(shù)的特征都會(huì)被舍棄, 默認(rèn)值為總特征個(gè)數(shù)開(kāi)平方取整
min_impurity_decrease: 限制信息增益的大小,信息增益小于設(shè)定數(shù)值的分枝不會(huì)發(fā)生
以上參數(shù)可以參見(jiàn)機(jī)器學(xué)習(xí) | 決策樹(shù)模型 ,單個(gè)決策樹(shù)的準(zhǔn)確率越?,隨機(jī)森林的準(zhǔn)確率也會(huì)越?,因?yàn)檠b袋法是依賴(lài)于平均值或者少數(shù)服從多數(shù)原則來(lái)決定集成的結(jié)果的。
重要參數(shù)
1、n_estimators
基評(píng)估器的數(shù)量。此參數(shù)對(duì)隨機(jī)森林模型的精確性影響是單調(diào)的,n_estimators
越大,模型的效果往往越好。但任何模型都有決策邊界,n_estimators
達(dá)到一定的程度之后,隨機(jī)森林的精確性往往不在上升或開(kāi)始波動(dòng),并且n_estimators
越大,需要的計(jì)算量和內(nèi)存也越大,訓(xùn)練的時(shí)間也會(huì)越來(lái)越長(zhǎng)。因此渴望在訓(xùn)練難度和模型效果之間取得平衡。
導(dǎo)包
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.tree import DecisionTreeClassifierfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.datasets import load_winefrom sklearn.model_selection import train_test_splitfrom sklearn.model_selection import cross_val_score
數(shù)據(jù)集準(zhǔn)備
wine = load_wine()X = wine.datay= wine.targetX_train, X_test, y_train, y_test = train_test_split (X,y,test_size =0.3 ,random_state = 666 )
模型建立
>>> clf = DecisionTreeClassifier()>>> clf.fit(X_train,y_train)DecisionTreeClassifier(ccp_alpha=0.0 , class_weight=None , criterion='gini' , max_depth=None , max_features=None , max_leaf_nodes=None , min_impurity_decrease=0.0 , min_impurity_split=None , min_samples_leaf=1 , min_samples_split=2 , min_weight_fraction_leaf=0.0 , presort='deprecated' , random_state=None , splitter='best' )>>> clf.score(X_test,y_test)0.9259259259259259
隨機(jī)森林和決策樹(shù)在交叉驗(yàn)證下的效果對(duì)比
DF_cv = []RF_cv = []for i in range (10 ): clf=DecisionTreeClassifier() rfc = RandomForestClassifier(n_estimators=20 ) DF_cv.append (cross_val_score(clf,X,y,cv=10 ).mean()) RF_cv.append (cross_val_score(rfc,X,y,cv=10 ).mean())plt.plot(range (1 ,11 ),DF_cv,label='DecisionTreeClassifier' )plt.plot(range (1 ,11 ),RF_cv,label='RandomForestClassifier' )plt.legend(loc=7 )plt.show();
n_estimators學(xué)習(xí)曲線(xiàn)
#【TIME WARNING: 2 mins 30 seconds】score= []for i in range (150 ): rfc = RandomForestClassifier (n_estimators= i+1 ) cv_score = cross_val_score (rfc,X,y,cv=10 ).mean () score.append (cv_score)plt.figure (figsize=(15 ,7 ),dpi=80 )plt.plot (score);
2、random_state
隨機(jī)森林的本質(zhì)是一種裝袋集成算法(bagging),裝袋集成算法是對(duì)基評(píng)估器的預(yù)測(cè)結(jié)果進(jìn)行平均或用多數(shù)表決原則來(lái)決定集成評(píng)估器的結(jié)果。在剛才的紅酒例子中,我們建立了25棵樹(shù),對(duì)任何一個(gè)樣本而言,平均或多數(shù)表決原則下,當(dāng)且僅當(dāng)有13棵以上的樹(shù)判斷錯(cuò)誤的時(shí)候,隨機(jī)森林才會(huì)判斷錯(cuò)誤。單獨(dú)一棵決策樹(shù)對(duì)紅酒數(shù)據(jù)集的分類(lèi) 準(zhǔn)確率在0.85上下浮動(dòng),假設(shè)一棵樹(shù)判斷錯(cuò)誤的可能性為0.2(ε),那20棵樹(shù)以上都判斷錯(cuò)誤的可能性是:
import numpy as npfrom scipy.special import combnp.array([comb(20 ,i)*(0.2 **i)*((1 -0.2 )**(20 -i)) for i in range (11 ,21 )]).sum ()
sklearn中的分類(lèi)樹(shù)DecisionTreeClassifier自帶隨機(jī)性,決策樹(shù)從最重要的特征中隨機(jī)選擇出一個(gè)特征來(lái)進(jìn)行分枝,因此每次生成的決策樹(shù)都不一樣,這個(gè)功能由參數(shù)random_state
控制。
隨機(jī)森林中random_state
控制生成森林的模式,而非讓一個(gè)森林中只有一棵樹(shù)。
>>> rfc = RandomForestClassifier(n_estimators=20 ,random_state=2 )>>> rfc = rfc.fit(X_train, y_train)# 隨機(jī)森林的重要屬性之一:estimators,# 查看森林中樹(shù)的狀況 rfc.estimators_[0 ].random_state>>> for i in range (len (rfc.estimators_)):... print (rfc.estimators_[i].random_state)18725838487949214871113523011853453896213298710192298833118696954422081981515180546596013766935111418777250663257521878959199854108747512264917515183663128700703920838146871146014426570104212
觀(guān)察到,當(dāng)random_state
固定時(shí),隨機(jī)森林中生成是一組固定的樹(shù),但每棵樹(shù)依然是不一致的,這是 用”隨機(jī)挑選特征進(jìn)行分枝“的方法得到的隨機(jī)性。
3、bootstrap & oob_score
bootstrap參數(shù)默認(rèn)True,代表采用這種有放回的隨機(jī)抽樣技術(shù)。
要讓基分類(lèi)器盡量都不一樣,一種方法是使用不同的訓(xùn)練集來(lái)進(jìn)行訓(xùn)練,而袋裝法正是通過(guò)有放回的隨機(jī)抽樣技術(shù)來(lái)形成不同的訓(xùn)練數(shù)據(jù),bootstrap就是用來(lái)控制抽樣技術(shù)的參數(shù)。
在一個(gè)含有個(gè)樣本的原始訓(xùn)練集中進(jìn)行隨機(jī)采樣,每次采樣一個(gè)樣本,并在抽取下一個(gè)樣本之前將該樣本放回原始訓(xùn)練集,也就是說(shuō)下次采樣時(shí)這個(gè)樣本依然可能被采集到,這樣采集次,最終得到一個(gè)和原始訓(xùn)練集一樣大的,個(gè)樣本組成的自助集。由于是隨機(jī)采樣,這樣每次的自助集和原始數(shù)據(jù)集不同,和其他的采樣集也是不同的。這樣就可以自由創(chuàng)造取之不盡用之不竭且互不相同的自助集,用這些自助集來(lái)訓(xùn)練基分類(lèi)器自然也就各不相同了。
基于自助采樣法,有放回隨機(jī)采樣,一些樣本可能在同一個(gè)自助集中出現(xiàn)多次,而其他一些卻可能被忽略,一般來(lái)說(shuō),自助集大約平均會(huì)包含的原始數(shù)據(jù)。一個(gè)樣本未被采用的概率:
這些數(shù)據(jù)被稱(chēng)為袋外數(shù)據(jù) (out of bag data,簡(jiǎn)寫(xiě)為oob)。除了我們最開(kāi)始就劃分好的測(cè)試集之外,這些數(shù)據(jù)也可以被用來(lái)作為集成算法的測(cè)試集。在使用隨機(jī)森林時(shí),我們可以不劃分測(cè)試集和訓(xùn)練集,只需要用袋外數(shù)據(jù)來(lái)測(cè)試我們的模型即可。
在實(shí)例化時(shí)設(shè)置參數(shù)oob_score=True
,即可使用袋外數(shù)據(jù)來(lái)測(cè)試。訓(xùn)練完畢之后,用隨機(jī)森林屬性oob_score_
來(lái)查看在袋外數(shù)據(jù)上測(cè)試的結(jié)果。
隨機(jī)森林分類(lèi)模型一些總結(jié)
采用有交疊的采樣子集的目的
為集成中的個(gè)體學(xué)習(xí)器應(yīng)盡可能相互獨(dú)立,盡可能具有較大差異,以得到泛化能力強(qiáng)的集成。對(duì)訓(xùn)練樣本進(jìn)行采樣,得到不同的數(shù)據(jù)集。 如果采樣出的每個(gè)子集都完全不同,每個(gè)學(xué)習(xí)器只用到一小部分訓(xùn)練數(shù)據(jù),甚至不足以進(jìn)行有效學(xué)習(xí)。
feature_importance_計(jì)算方法
1、袋外數(shù)據(jù)錯(cuò)誤率評(píng)估
RF的數(shù)據(jù)是boostrap的有放回采樣,形成了袋外數(shù)據(jù)。因此可以采用袋外數(shù)據(jù)(OOB)錯(cuò)誤率進(jìn)行特征重要性的評(píng)估。
袋外數(shù)據(jù)錯(cuò)誤率定義為: 袋外數(shù)據(jù)自變量值發(fā)生輕微擾動(dòng)后的分類(lèi)正確率與擾動(dòng)前分類(lèi)正確率的平均減少量。
2、利用Gini系數(shù)計(jì)算特征的重要性
單棵樹(shù)上特征的重要性定義為:特征在所有非葉節(jié)在分裂時(shí)加權(quán)不純度的減少,減少的越多說(shuō)明特征越重要。
隨機(jī)森林得到的feature_importance的原理
在隨機(jī)森林中某個(gè)特征X的重要性的計(jì)算方法如下:
對(duì)于隨機(jī)森林中的每一顆決策樹(shù), 使用相應(yīng)的OOB(袋外數(shù)據(jù))數(shù)據(jù)來(lái)計(jì)算它的袋外數(shù)據(jù)誤差 ,記為.
隨機(jī)地對(duì)袋外數(shù)據(jù)OOB所有樣本的特征X加入噪聲干擾 (就可以隨機(jī)的改變樣本在特征X處的值), 再次計(jì)算它的袋外數(shù)據(jù)誤差 ,記為.
假設(shè)隨機(jī)森林中有 棵樹(shù),那么對(duì)于特征X的重要性,之所以可以用這個(gè)表達(dá)式來(lái)作為相應(yīng)特征的重要性的度量值是因?yàn)椋?nbsp;若給某個(gè)特征隨機(jī)加入噪聲之后,袋外的準(zhǔn)確率大幅度降低,則說(shuō)明這個(gè)特征對(duì)于樣本的分類(lèi)結(jié)果影響很大,也就是說(shuō)它的重要程度比較高。
隨機(jī)森林的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
決策樹(shù)選擇部分樣本及部分特征,一定程度上避免過(guò)擬合。 決策樹(shù)隨機(jī)選擇樣本并隨機(jī)選擇特征,模型具有很好的抗噪能力,性能穩(wěn)定。 能夠處理高維度數(shù)據(jù),并且不用做特征選擇,能夠展現(xiàn)出哪些變量比較重要。 對(duì)缺失值不敏感,如果有很大一部分的特征遺失,仍可以維持準(zhǔn)確度。 訓(xùn)練時(shí)樹(shù)與樹(shù)之間是相互獨(dú)立的,訓(xùn)練速度快,容易做成并行化方法。 隨機(jī)森林有袋外數(shù)據(jù)obb,不需要單獨(dú)劃分交叉驗(yàn)證集。
缺點(diǎn)
可能有很多相似決策樹(shù),掩蓋真實(shí)結(jié)果。 對(duì)小數(shù)據(jù)或低維數(shù)據(jù)可能不能產(chǎn)生很好分類(lèi)。 產(chǎn)生眾多決策樹(shù),算法較慢。
例子
>>> from sklearn.model_selection import cross_val_score>>> from sklearn.datasets import make_blobs>>> from sklearn.ensemble import RandomForestClassifier>>> from sklearn.ensemble import ExtraTreesClassifier>>> from sklearn.tree import DecisionTreeClassifier>>> X, y = make_blobs(n_samples=10000 , n_features=10 , centers=100 ,... random_state=0 )>>> clf = DecisionTreeClassifier(max_depth=None , min_samples_split=2 ,... random_state=0 )>>> scores = cross_val_score(clf, X, y, cv=5 )>>> scores.mean()0.98 ...>>> clf = RandomForestClassifier(n_estimators=10 , max_depth=None ,... min_samples_split=2 , random_state=0 )>>> scores = cross_val_score(clf, X, y, cv=5 )>>> scores.mean()0.999 ...>>> clf = ExtraTreesClassifier(n_estimators=10 , max_depth=None ,... min_samples_split=2 , random_state=0 )>>> scores = cross_val_score(clf, X, y, cv=5 )>>> scores.mean() > 0.999 True