随机森林的特征 是放回抽样么_机器学习超详细实践攻略(10):随机森林算法详解及小白都能看懂的调参指南...
一、什么是隨機森林
前面我們已經介紹了決策樹的基本原理和使用。但是決策樹有一個很大的缺陷:因為決策樹會非常細致地劃分樣本,如果決策樹分得太多細致,會導致其在訓練集上出現(xiàn)過擬合,而如果決策樹粗略地劃分樣本,又不能很好地擬合樣本。
為了解決這個兩難困境,聰明的專家們想出了這樣的思路:既然我增加單棵樹的深度會適得其反,那不如我不追求一個樹有多高的精確度,而是訓練多棵這樣的樹來一塊預測,一棵樹的力量再大,也是有限的,當他們聚成一個集體,它的力量可能是難以想象的,也就是我們常說的:“三個臭皮匠賽過諸葛亮”。這便是集成學習的思想。
這里多提一句,正是因為每棵樹都能夠用比較簡單的方法細致地擬合樣本,我們可以多用幾棵樹來搭建準確率更高的算法,后邊要說到的一些工業(yè)級的算法,比如GBDT、XGBOOST、LGBM都是以決策樹為積木搭建出來的。
所以在學習這些算法的過程中,我們也要把決策樹算法看成一塊塊積木,學完了基本的積木算法之后,對于現(xiàn)在常用的那幾個工業(yè)級的算法,只需要理清兩個問題:
1)這個算法利用了哪個集成學習思想
2)這個算法具體怎么把這個思想實現(xiàn)出來的。
隨機森林就是決策樹們基于bagging集成學習思想搭建起來的。
隨機森林的算法實現(xiàn)思路非常簡單,只需要記住一句口訣:抽等量樣本,選幾個特征,構建多棵樹。
下面,我們詳細解釋這個口訣的含義:
1)抽等量樣本
隨機森林訓練每棵樹之前,都會從訓練集中隨機抽出一部分樣本來訓練。所以說訓練每棵樹用到的樣本其實都是有差別的,這樣就保證了不同的樹可以重點學習不同的樣本。而為了達到抽等量樣本的目的,抽樣方式一般是有放回的抽樣,也就是說,在訓練某棵樹的時候,這一次被抽到的樣本會被放回數據集中,下一次還可能被抽到,因此,原訓練集中有的樣本會多次被抽出用來訓練,而有的樣本可能不會被使用到。
但是不用擔心有的樣本沒有用到,只要訓練的樹的棵數足夠多,大多數訓練樣本總會被取到的。有極少量的樣本成為漏網之魚也不用擔心,后邊我們會篩選他們出來用來測試模型。
2)選幾個特征
在訓練某棵樹的時候,也不是將樣本的所有特征都用來訓練,而是會隨機選擇一部分特征用來訓練。這樣做的目的就是讓不同的樹重點關注不同的特征。在scikit-learn中,用“max_features”這個參數來控制訓練每棵樹選取的樣本數。
3)構建多棵樹。
通過1)、2)兩個步驟,訓練多棵樹。魯迅曾經說過:世界上本沒有森林,長得樹多了,就成了森林。正是一棵棵決策樹構成了整個隨機森林。具體構建樹的數量,在scikit-learn中,用“n_estimators”這個參數來控制。
那最終的預測結果怎么得到呢?隨機森林是非常民主的算法,最終的結果由每棵決策樹綜合給出:如果是分類問題,那么對于每個測試集,樹都會預測出一個類別進行投票,最終統(tǒng)計票數多的那個類別為最終類別。看看,這算法儼然是一個遵循:“少數服從多數”的原則的小型民主社會;如果是回歸問題,那就更簡單了,各個樹得到的結果相加求得一個平均值為最終回歸結果。
從上邊的流程中可以看出,隨機森林的隨機性主要體現(xiàn)在兩個方面:數據集的隨機選取、每棵樹所使用特征的隨機選取。以上兩個隨機性使得隨機森林中的決策樹都能夠彼此不同,提升系統(tǒng)的多樣性,從而提升分類性能。
二、隨機森林的特點
以上就是隨機森林的構建原理,下面,我們說說隨機森林算法的優(yōu)缺點:
1、優(yōu)點:
1)實現(xiàn)簡單,泛化能力強,可以并行實現(xiàn),因為訓練時樹與樹之間是相互獨立的;
2)相比單一決策樹,能學習到特征之間的相互影響,且不容易過擬合;
3)能直接特征很多的高維數據,因為在訓練過程中依舊會從這些特征中隨機選取部分特征用來訓練;
4)相比SVM,不是很怕特征缺失,因為待選特征也是隨機選取;
5)訓練完成后可以給出特征重要性。當然,這個優(yōu)點主要來源于決策樹。因為決策樹在訓練過程中會計算熵或者是基尼系數,越往樹的根部,特征越重要。
2、缺點
1)在噪聲過大的分類和處理回歸問題時還是容易過擬合;
2)相比于單一決策樹,它的隨機性讓我們難以對模型進行解釋。
三、隨機森林的使用
和決策樹類似,隨機森林同樣可以分為分類森林(RandomForestClassifier )和回歸森林(RandomForestRegressor),在scikit-lean中調用方式和決策樹相同。
讓我們在手寫識別數據集上實現(xiàn)一個分類森林。
#導入必要的包 from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split,GridSearchCV,cross_val_score from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt import numpy as np#導入數據集 data = load_digits() x = data.data y = data.target用隨機森林訓練并進行交叉驗證:
RF = RandomForestClassifier(random_state = 66) score = cross_val_score(RF,x,y,cv=10).mean() print('交叉驗證得分: %.4f'%score)輸出:
交叉驗證得分: 0.9278四、隨機森林調參
一)隨機森林參數介紹
除了和決策樹有的參數之外,對于隨機森林,只需要掌握8個新增的參數即可,我將這8個參數分成三類:
1、用于調參的參數:
- max_features(最大特征數): 這個參數用來訓練每棵樹時需要考慮的最大特征個數,超過限制個數的特征都會被舍棄,默認為auto。可填入的值有:int值,float(特征總數目的百分比),“auto”/“sqrt”(總特征個數開平方取整),“l(fā)og2”(總特征個數取對數取整)。默認值為總特征個數開平方取整。值得一提的是,這個參數在決策樹中也有但是不重要,因為其默認為None,即有多少特征用多少特征。為什么要設置這樣一個參數呢?原因如下:考慮到訓練模型會產生多棵樹,如果在訓練每棵樹的時候都用到所有特征,以來導致運算量加大,二來每棵樹訓練出來也可能千篇一律,沒有太多側重,所以,設置這個參數,使訓練每棵樹的時候只隨機用到部分特征,在減少整體運算的同時還可以讓每棵樹更注重自己選到的特征。
- n_estimators:隨機森林生成樹的個數,默認為100。
2、控制樣本抽樣參數:
- bootstrap:每次構建樹是不是采用有放回樣本的方式(bootstrap samples)抽取數據集。可選參數:True和False,默認為True。
- oob_score:是否使用袋外數據來評估模型,默認為False。
boostrap和 oob_score兩個參數一般要配合使用。如果boostrap是False,那么每次訓練時都用整個數據集訓練,如果boostrap是True,那么就會產生袋外數據。
先解釋一下袋外數據的概念:
在一個含有n個樣本的原始訓練集中,我們每次隨機取出一個樣本并記錄,并在抽取下一個樣本之前將該樣本放回原始訓練集,即下次采樣時這個樣本依然可能被采集到,這樣采集n次,最終得到一個和原始訓練集一樣大的子數據集。
由于是隨機采樣,這樣每次的子數據集和原始數據集都不同,用這些子數據集來各自訓練一棵樹,這些樹的參數自然也就各不相同了。
然而有放回抽樣也會有自己的問題。由于是有放回,一些樣本可能在同一個自助集中出現(xiàn)多次,而其他一些卻可能被忽略,一般來說,每一次抽樣,某個樣本被抽到的概率是 1/n ,所以不被抽到的概率就是 1-1/n ,所以n個樣本都不被抽到的概率就是:
用洛必達法則化簡,可以得到這個概率收斂于(1/e),約等于0.37。
因此,如果數據量足夠大的時候,會有約37%的訓練數據被浪費掉,沒有參與建模,這些數據被稱為袋外數據(out of bag data,簡寫為oob)。
為了這些數據不被浪費,我們也可以把他們用來作為集成算法的測試集。也就是說,在使用隨機森林時,我們可以不劃分測試集和訓練集,只需要用袋外數據來測試我們的模型即可。
當然,這需要樣本數據n和分類器個數n_estimators都很大,如果數據集過少,很可能就沒有數據掉落在袋外,自然也就無法使用oob數據來測試模型了。
當bootstrap參數取默認值True時,表示抽取數據集時采用這種有放回的隨機抽樣技術。如果希望用袋外數據來測試,則需要在實例化時就將oob_score這個參數調整為True,訓練完畢之后,我們可以用隨機森林的另一個重要屬性:oob_score_來查看我們的在袋外數據上測試的結果,代碼如下:
#訓練一個模型,讓oob_score=True 輸出:0.9393433500278241這個就是沒有參與訓練的數據集在模型上的測試得分。
3、不重要參數
- max_samples:構建每棵樹需要抽取的最大樣本數據量,默認為None,即每次抽取樣本數量和原數據量相同。
- n_jobs::設定fit和predict階段并列執(zhí)行的CPU核數,如果設置為-1表示并行執(zhí)行的任務數等于計算機核數。默認為None,即采用單核計算。
- verbose:控制構建數過程的冗長度,默認為0。一般不需要管這個參數。
- warm_start:當設置為True,重新使用之前的結構去擬合樣例并且加入更多的估計器(estimators,在這里就是隨機樹)到組合器中。默認為 False
以上這幾個參數只需要簡單了解即可,大多數參數在使用過稱重不用調整,只是需要注意一點,n_jobs默認為None,為了加快速度,可以把n_jobs設置為-1。
二)隨機森林調參順序
介紹完了這些參數,接下來就要介紹隨機森林的調參順序了,隨機森林的調參順序一般遵循先重要后次要、先粗放后精細的原則,即先確定需要多少棵樹參與建模,再對每棵樹做細致的調參,精益求精。
相對于xgboost等算法,隨機森林的調參還是相對比較簡單,因為各個參數之間互相影響的程度很小,只需要按步驟調整即可。
結合我們決策樹文章中提到的參數以及今天所講的兩個參數,隨機森林中主要用來調參的參數有6個:
- n_estimators:
- criterion
- max_depth
- min_samples_split
- min_samples_leaf
- max_features
調參順序如下:
1)選擇criterion參數(決策樹劃分標準)
和決策樹一樣,這個參數只有兩個參數 'entropy'(熵) 和 'gini'(基尼系數)可選,默認為gini,這里簡單測試一下就好
RF = RandomForestClassifier(random_state = 66) score = cross_val_score(RF,x,y,cv=10).mean() print('基尼系數得分: %.4f'%score) RF = RandomForestClassifier(criterion = 'entropy',random_state = 66) score = cross_val_score(RF,x,y,cv=10).mean() print('熵得分: %.4f'%score)輸出:
基尼系數得分: 0.9278熵得分: 0.9249
這里看到,依舊是選用gini系數模型效果更好。
2)探索n_estimators的最佳值。
接下來才是進入真正的調參環(huán)節(jié)。根據上述調參原則,我們先看看用幾棵樹模型的表現(xiàn)最好。一般來說,樹的棵數越多,模型效果表現(xiàn)越好,但樹的棵數達到一定的數量之后,模型精確度不再上升,訓練這個模型的計算量卻逐漸變大。這個時候,再加樹的數量就沒必要了。就好比你餓的時候每吃一個饅頭就特別頂飽,但是吃到一定數量的饅頭之后,再吃就要撐著了。
只要找到這個臨界值,這個參數就調好了。為了觀察得分隨著樹增多的變化,我們依然繪制決策樹調參時的學習曲線。
###調n_estimators參數 ScoreAll = [] for i in range(10,200,10):DT = RandomForestClassifier(n_estimators = i,random_state = 66) #,criterion = 'entropy'score = cross_val_score(DT,data.data,data.target,cv=10).mean()ScoreAll.append([i,score]) ScoreAll = np.array(ScoreAll)max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的,其實就是找出最高得分對應的索引 print("最優(yōu)參數以及最高得分:",ScoreAll[max_score]) plt.figure(figsize=[20,5]) plt.plot(ScoreAll[:,0],ScoreAll[:,1]) plt.show()輸出:
最優(yōu)參數以及最高得分: [120. 0.95560035]調n_estimators參數根據曲線,我們進一步縮小范圍,搜索100~130之間的得分。(這里可以根據經驗自己指定)
###進一步縮小范圍,調n_estimators參數 ScoreAll = [] for i in range(100,130):DT = RandomForestClassifier(n_estimators = i,random_state = 66) #criterion = 'entropy',score = cross_val_score(DT,data.data,data.target,cv=10).mean()ScoreAll.append([i,score]) ScoreAll = np.array(ScoreAll)max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的,其實就是找出最高得分對應的索引 print("最優(yōu)參數以及最高得分:",ScoreAll[max_score]) plt.figure(figsize=[20,5]) plt.plot(ScoreAll[:,0],ScoreAll[:,1]) plt.show()輸出:
最優(yōu)參數以及最高得分: [117. 0.95727946]調n_estimators參數
可以看到,117為得分最高點,我們暫定n_estimators為117,接著調下邊的參數。
3)探索max_depth(樹的最大深度)最佳參數
###粗調max_depth參數 ScoreAll = [] for i in range(10,30,3):DT = RandomForestClassifier(n_estimators = 117,random_state = 66,max_depth =i ) #,criterion = 'entropy'score = cross_val_score(DT,data.data,data.target,cv=10).mean()ScoreAll.append([i,score]) ScoreAll = np.array(ScoreAll)max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的,其實就是找出最高得分對應的索引 print("最優(yōu)參數以及最高得分:",ScoreAll[max_score]) plt.figure(figsize=[20,5]) plt.plot(ScoreAll[:,0],ScoreAll[:,1]) plt.show()輸出:
最優(yōu)參數以及最高得分: [16. 0.95727946]max_depth參數轉折點在16,但是16之后一直沒有變化,可以說明就算不限制,所有樹的最大深度也就是16左右,因為我們以步長為3搜索的,所以還需要進一步搜索一下16附近的值。
精細搜索之后發(fā)現(xiàn),16這個值就是轉折點,所以暫定max_depth = 16。
4)探索min_samples_split(分割內部節(jié)點所需的最小樣本數)最佳參數
min_samples_split最小值就是2,我們就從2開始調起。
輸出:
最優(yōu)參數以及最高得分: [2. 0.95727946]min_samples_split參數
可以看到,隨著min_samples_split增大,模型得分下降,說明沒有出現(xiàn)過擬合現(xiàn)象,min_samples_split暫定2。
5)探索min_samples_leaf(分割內部節(jié)點所需的最小樣本數)最佳參數
###調min_samples_leaf參數 ScoreAll = [] for i in range(1,15,2):DT = RandomForestClassifier(n_estimators = 117,random_state = 66,max_depth =16,min_samples_leaf = i,min_samples_split = 2 ) score = cross_val_score(DT,data.data,data.target,cv=10).mean()ScoreAll.append([i,score]) ScoreAll = np.array(ScoreAll)max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的,其實就是找出最高得分對應的索引 print("最優(yōu)參數以及最高得分:",ScoreAll[max_score]) plt.figure(figsize=[20,5]) plt.plot(ScoreAll[:,0],ScoreAll[:,1]) plt.show()輸出:
最優(yōu)參數以及最高得分: [1. 0.95727946]min_samples_leaf參數5)對每棵樹用到的最大特征數max_features調參:
正常來說,只要這個值不要設置得太小,所有特征都會被整個森林抽取到用來訓練, 所以相對來說這個值對整個模型的影響不是太大。但這個值越大,單棵樹需要考慮的特征越多,雖然模型的表現(xiàn)可能會更好,但是增加這個值會導致算法運行速度變慢,所以需要我們考慮去找一個平衡值。
#調max_features參數 param_grid = {'max_features':np.arange(0.1, 1)}rfc = RandomForestClassifier(random_state=66,n_estimators = 117,max_depth = 16,min_samples_leaf =1 ,min_samples_split =4 ) GS = GridSearchCV(rfc,param_grid,cv=10) GS.fit(data.data,data.target) print(GS.best_params_) print(GS.best_score_)輸出:
{'max_features': 0.1}0.9560335195530726
如果時間充裕,接下來也可以將min_samples_leaf和min_samples_split作為網格參數聯(lián)調一下,因為這兩個參數會相互影響,這里暫時省略這一步。
此時,我們得到的參數如下:
參數值n_estimators117max_depth16min_samples_leaf1min_samples_split2max_features0.1
6)在得到的最優(yōu)參數附近進行小范圍網格搜索
因為手動調參時,這些參數可能會相互影響,導致我們得到的參數還不是最優(yōu)的。所以在最優(yōu)參數附近進行小范圍的網格搜索,排出相互影響的因素,尤其是在數據集量比較少時,小范圍搜索一下可能會有意外收獲。
import time start = time.time()param_grid = {'n_estimators':np.arange(140, 150),'max_depth':np.arange(15, 18),'min_samples_leaf':np.arange(1, 8),'min_samples_split':np.arange(2, 5),'max_features':np.arange(0.1, 1) }rfc = RandomForestClassifier(random_state=66) GS = GridSearchCV(rfc,param_grid,cv=10) GS.fit(data.data,data.target) end = time.time() print("循環(huán)運行時間:%.2f秒"%(end-start)) print(GS.best_params_) print(GS.best_score_)輸出如下:
循環(huán)運行時間:3052.67秒{'max_depth': 16, 'max_features': 0.1, 'min_samples_leaf': 1, 'min_samples_split': 3, 'n_estimators': 143}
0.9599332220367279
可以看到,精確度又上升了一點,此時,我們得到的新舊參數對比如下:
參數舊值新值n_estimators117143max_depth1616min_samples_leaf11min_samples_split23max_features0.10.1
對比一下新舊參數,可以看到參數變化還是比較大的,尤其是樹的棵數這個參數。當然,這里主要原因是我們用來做示例的這個預置的數據集只有1797條數據,導致參數的隨機性太大,在實際使用中數據集數量都是十萬百萬級的,不會出現(xiàn)我們手動調整的參數和小范圍網格搜索參數差別這么大的情況。
最后需要說明的一點是:隨機森林相對于決策樹來說運行較慢,在調參時可以將參數搜索范圍設置得小一些。
當然,這只是我個人的調參順序,僅用來參考,沒必要這么固化。實際調參時可以根據實際情況做一些調整。還是那句話:正是調參過程充滿的各種不確定性,才是調參的真正魅力所在。
五、本系列相關文章
- 機器學習超詳細實踐攻略(1):盤點scikit-learn里那些有趣又有用的彩蛋級入門數據集
- 機器學習超詳細實踐攻略(8):使用scikit-learn構建模型的通用模板【萬字長文】
- ?機器學習超詳細實踐攻略(9):決策樹算法詳解及小白都能看懂的調參指南
- 機器學習超詳細實踐攻略(21):三板斧干掉樣本不均衡問題之1——過(欠)采樣
- 機器學習超詳細實踐攻略(22):三板斧干掉樣本不均衡問題之2——對正負樣本設置不同權重
- 機器學習超詳細實踐攻略(23):三板斧干掉樣本不均衡問題之3——通過集成學習方法解決樣本不均衡
總結
以上是生活随笔為你收集整理的随机森林的特征 是放回抽样么_机器学习超详细实践攻略(10):随机森林算法详解及小白都能看懂的调参指南...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小爱音箱app如何多部手机登录(怎么扫不
- 下一篇: http端口_PhpStorm 修改默认