一文讀懂隨機森林的解釋和實現(附python代碼)

一文讀懂隨機森林的解釋和實現(附python代碼)

作者:William Koehrsen

翻譯:和中華

校對:李潤嘉

本文約6000字,建議閱讀15分鐘。

本文從單棵決策樹講起,然後逐步解釋了隨機森林的工作原理,並使用sklearn中的隨機森林對某個真實數據集進行預測。

如今由於像Scikit-Learn這樣的庫的出現,我們可以很容易地在Python中實現數百種機器學習算法。它們是如此易用,以至於我們通常都不需要任何關於模型底層工作機制的知識就可以使用它們。雖然沒必要了解所有細節,但瞭解某個機器學習模型大致是如何工作的仍然有幫助。這使得我們可以在模型表現不佳時進行診斷,或者解釋模型是如何做決策的,這一點至關重要,尤其當我們想要說服別人相信我們的模型時。

在本文中,我們將介紹如何在Python中構建和使用隨機森林(Random Forest)。除了查看代碼之外,我們還將嘗試瞭解此模型的工作原理。因為隨機森林由許多決策樹(decision tree)組成,所以我們先來了解一下單個決策樹如何在一個簡單的問題上進行分類。隨後,我們將使用隨機森林來解決一個現實世界中的數據科學問題。本文的完整代碼在GitHub上以Jupyter Notebook的形式提供。

注意:本文最初出現在enlight上,這是一個社區驅動的開源平臺,為那些希望學習機器學習的人提供教程。


理解決策樹


決策樹是隨機森林的基本構成要素,而且是一種直觀的模型。我們可以將決策樹視為一系列關於數據的是/否問題,從而最終得出一個預測類別(或迴歸情況下的連續值)。 這是一個可解釋的模型,因為它非常像我們人類進行分類的過程:在我們做出決定之前(在理想世界中),我們會對可用數據進行一系列的詢問。

決策樹的技術細節在於如何形成關於數據的問題。在CART算法中,通過確定問題(稱為節點的分裂)來構建決策樹,這些問題在得到應答時會導致基尼不純度(Gini Impurity)的最大減少。這意味著決策樹試圖形成包含來自單個類的高比例樣本(數據點)的節點,這個過程通過在能將數據乾淨地劃分為不同類的特徵中找到適當的值來實現。

我們稍後會談談基尼不純度的更底層細節,但首先,讓我們構建一個決策樹,以便我們能夠在高層次上理解它。


簡單問題上的決策樹


我們將從一個非常簡單的二元分類問題開始,如下所示:


一文讀懂隨機森林的解釋和實現(附python代碼)


目標是把數據點劃分到各自所屬的類

我們的數據只有兩個特徵(預測變量),x1和x2,共有6個數據點(樣本),被分為2個不同的標籤。雖然這個問題很簡單,但它不是線性可分的(linearly separable),這意味著我們不能繪製一條通過數據的直線來對點進行分類。

然而,我們可以繪製一系列直線,將數據點劃分入多個框,我們稱這些框為節點。 事實上,這就是決策樹在訓練期間所做的事情。實際上決策樹是通過構造許多線性邊界而構建的一個非線性模型。

我們使用Scikit-Learn來創建決策樹並在數據上訓練(擬合)。


一文讀懂隨機森林的解釋和實現(附python代碼)



在訓練過程中,我們為模型提供特徵和標籤,以幫助它學習如何根據特徵對點進行分類。(針對這個簡單問題我們沒有測試集,在測試時,我們只為模型提供特徵值並讓它對標籤進行預測。)

我們可以在訓練數據上測試模型的準確性:


一文讀懂隨機森林的解釋和實現(附python代碼)



可以看到它獲得了我們所期望的100%的準確性,這是因為我們給了它訓練的答案(y),並且沒有限制樹的深度。事實證明,在訓練數據中過強的學習能力可能是一個缺點,因為它可能導致過擬合(overfitting),我們將在稍後對此進行討論。


可視化決策樹


當我們訓練決策樹時到底發生了什麼?可視化可以幫助我們更好地理解決策樹,這可以通過Scikit-Learn的一個功能來實現(詳細信息,請查看notebook或這篇文章)。


一文讀懂隨機森林的解釋和實現(附python代碼)


簡單的決策樹

除葉子節點(彩色終端節點)外,所有節點都有5個部分:

  • 基於某個特徵的一個值對數據進行的提問,每個提問都有一個真或假的答案可以分裂節點。根據答案,數據點相應地向下移動。
  • gini:節點的Gini不純度。當我們沿著樹向下移動時,平均加權基尼不純度會減少。
  • samples:節點中的觀測數據數量。
  • value:每個類中的樣本數。例如,根節點中有2個樣本屬於類0,有4個樣本屬於類1。
  • class:該節點中大多數點的分類。在葉節點中,即是對節點中所有樣本的預測。

葉節點中不再提問,因為這裡已經產生了最終的預測。要對某個新數據點進行分類,只需沿著樹向下移動,使用新點的特徵來回答問題,直到到達某個葉節點,該葉節點對應的分類就是最終的預測。

為了以不同的方式查看樹,我們可以在原始數據上繪製由決策樹構建的分割。


一文讀懂隨機森林的解釋和實現(附python代碼)


決策樹構建的分割

每個分割都是一條線,它根據特徵值將數據點劃分到不同節點。對於這個簡單的問題並且對最大深度沒有做出限制,劃分最終把每個點放置在僅包含同類點的一個節點中。(再次提醒,稍後我們將看到訓練數據的這種完美劃分可能並非我們想要的,因為它可能導致過擬合)

基尼不純度(Gini Impurity)


是時候深入瞭解基尼不純度的概念了(數學並不嚇人!)節點的基尼不純度是指,根據節點中樣本的分佈對樣本分類時,從節點中隨機選擇的樣本被分錯的概率。例如,在根節點中,根據節點中的樣本標籤有44.4%的可能性錯誤地對某個隨機選擇的數據點進行分類。可以使用以下等式得出這個值:


一文讀懂隨機森林的解釋和實現(附python代碼)


節點n的基尼不純度

節點n的基尼不純度是1減去每個類(二元分類任務中是2)的樣本比例的平方和。有點拗口,所以我們來一起計算出根節點的基尼不純度。


一文讀懂隨機森林的解釋和實現(附python代碼)


根節點的基尼不純度

在每個節點,決策樹要在所有特徵中搜索用於拆分的值,從而可以最大限度地減少基尼不純度。(拆分節點的另一個替代方法是使用信息增益)。

然後,它以貪婪遞歸的過程重複這種拆分,直到達到最大深度,或者每個節點僅包含同類的樣本。樹每層的加權總基尼不純度一定是減少的。在樹的第二層,總加權基尼不純度值為0.333:


一文讀懂隨機森林的解釋和實現(附python代碼)



(每個節點的基尼不純度按照該節點中來自父節點的點的比例進行加權。)你可以繼續為每個節點計算基尼不純度(可視化圖中有答案)。 就這樣,從一些基本的數學中,誕生了一個強大的模型!

最終,最後一層的加權總基尼不純度變為0,也意味著每個節點都是完全純粹的,從節點中隨機選擇的點不會被錯誤分類。雖然這一切看起來挺好的,但這意味著模型可能過擬合,因為所有節點都是僅僅使用訓練數據構建的。

過擬合:為什麼森林比一棵樹更好


你可能會想問為什麼不能只用一個決策樹呢?它似乎很完美,因為它沒有犯任何錯誤!但別忘了這個關鍵點,即這棵樹是在訓練數據上沒有犯錯。我們早已預計會出現這種情況,因為我們給樹提供了答案,而且沒有限制最大深度(樹的層數)。然而,機器學習模型的目標是可以對從未見過的新數據很好地泛化。

過擬合發生在當我們有一個非常靈活的模型(模型具有高能力)時,其本質上是通過緊密擬合來記住訓練數據。這樣的問題是模型不僅學到了訓練數據中的實際關係,還學習了存在的噪聲。靈活的模型具有高方差(variance),因為學到的參數(例如決策樹的結構)將隨著訓練數據的不同而變化很大。

另一方面,因為對訓練數據做出了假設,所以一個不靈活的模型具有較高的偏差(bias),(它偏向於對數據預先構思的想法)例如,線性分類器假設數據是線性的,不具備擬合非線性關係的靈活性。一個不靈活的模型甚至可能無法擬合訓練數據,在高方差和高偏差這兩種情況下,模型都無法很好地泛化到新數據之上。

一個能記住訓練數據的非常靈活的模型與不能學習訓練數據的不靈活模型之間的平衡稱為偏差-方差權衡(bias-variance-tradeoff),它是機器學習中的一個基本概念。

當我們不限制最大深度時決策樹容易過擬合的原因是它具有無限的靈活性,這意味著它可以持續生長,直到它為每個單獨的觀察點都生成一個葉節點,達到完美地分類。如果返回到之前決策樹的圖像並將最大深度限制為2(僅進行一次拆分),則分類不再100%正確。我們減少了決策樹的方差,但代價是增加了偏差。

限制樹的深度可以減少方差(好)並且增加偏差(壞),一種替代方案是,我們可以將許多決策樹組合成一個稱為隨機森林的集成模型(ensemble model)。

隨機森林


隨機森林是由許多決策樹組成的模型。這個模型不是簡單地平均所有樹(我們可以稱之為“森林”)的預測,而是使用了兩個關鍵概念,名字中的隨機二字也是由此而來:

  • 在構建樹時對訓練數據點進行隨機抽樣
  • 分割節點時考慮特徵的隨機子集

隨機抽樣訓練觀測數據


在訓練時,隨機森林中的每棵樹都會從數據點的隨機樣本中學習。樣本被有放回的抽樣,稱為自助抽樣法(bootstrapping),這意味著一些樣本將在一棵樹中被多次使用。背後的想法是在不同樣本上訓練每棵樹,儘管每棵樹相對於特定訓練數據集可能具有高方差,但總體而言,整個森林將具有較低的方差,同時不以增加偏差為代價。

在測試時,通過平均每個決策樹的預測來進行預測。這種在不同的自助抽樣數據子集上訓練單個學習器,然後對預測進行平均的過程稱為bagging,是bootstrap aggregating的縮寫。

用於拆分節點的隨機特徵子集


隨機森林中的另一個主要概念是,只考慮所有特徵的一個子集來拆分每個決策樹中的每個節點。通常將其設置為sqrt(n_features)以進行分類,這意味著如果有16個特徵,則在每個樹中的每個節點處,只考慮4個隨機特徵來拆分節點。(隨機森林也可以在每個節點處考慮所有的特徵,如迴歸中常見的那樣。這些選項可以在Scikit-Learn Random Forest的實現中控制)。

如果你能理解一棵單獨的決策樹,bagging的理念,以及隨機的特徵子集,那麼你對隨機森林的工作方式也就有了很好的理解:

隨機森林將成百上千棵決策樹組合在一起,在略微不同的觀察集上訓練每個決策樹,在每棵樹中僅考慮有限數量的特徵來拆分節點。隨機森林的最終預測是通過平均每棵樹的預測來得到的。


想理解為什麼隨機森林優於單一的決策樹,請想象以下場景:你要判斷特斯拉的股票是否上漲,現在你身邊有十幾位對該公司都沒有先驗知識的分析師。每個分析師都有較低的偏見,因為他們沒有任何假設,並且可以從新聞報道的數據集中學習。

這似乎是一個理想的情況,但問題是報道中除了真實的信號外也可能包含噪音。 因為分析師們完全根據數據做出預測,即他們具有很高的靈活性,也就意味著他們可能會被無關的信息所左右。分析師們可能會從同一數據集中得出不同的預測。此外,如果提供不同的報道訓練集,每個分析師都有高方差,並得出截然不同的預測。

解決方案是不依賴於任何一個人,而是彙集每個分析師的投票。此外,與隨機森林一樣,允許每個分析師僅使用一部分報道,並希望通過採樣來消除噪聲信息的影響。在現實生活中,我們也依賴於多種信息來源(從不信任亞馬遜的單獨評論),因此,不僅決策樹的思想很直觀,而且將它們組合在一起成為隨機森林的想法同樣如此。

實踐中的隨機森林


接下來,我們將在Python中用Scikit-Learn構建一個隨機森林。我們不是學習一個簡單的問題,而是會使用一個被分為訓練集和測試集的真實數據,我們使用測試集來估計模型對新數據的性能,這也可以幫我們確定模型過擬合的程度。

數據集


我們要解決的問題是一個二元分類任務,目的是預測個人的健康狀況。數據集的特徵代表個人的社會經濟和生活方式,標籤為0表示健康狀況不佳,1表示身體健康。該數據集由疾病控制和預防中心收集,可在此處獲取。


一文讀懂隨機森林的解釋和實現(附python代碼)


數據樣本

通常,一個數據科學項目80%的工作是在清洗,探索和提取數據中的特徵。然而這篇文章我們的重點在於建模(有關其他步驟的詳細信息,請參閱本文)。

這是一個不平衡的分類問題,因此準確率(accuracy)並不是一個合適的衡量指標。作為替代,我們將利用ROC和AUC,AUC是一個從0(最差)到1(最佳)的度量值,隨機猜測得分為0.5。我們還可以繪製ROC曲線來評估模型。

這個notebook包含了決策樹和隨機森林的實現,但在這裡我們只關注隨機森林。 在讀取數據後,我們就可以實例化並且訓練一個隨機森林,具體如下:


一文讀懂隨機森林的解釋和實現(附python代碼)



在幾分鐘的訓練後,模型已準備好對測試數據進行預測了,如下:


一文讀懂隨機森林的解釋和實現(附python代碼)



我們預測分類(predict)以及預測概率(predict_proba)來計算ROC AUC。一旦我們有了對測試集的預測結果,我們就可以計算出ROC AUC。


一文讀懂隨機森林的解釋和實現(附python代碼)


結果


隨機森林的最終測試集ROC AUC為0.87,而具有無限最大深度的單一決策樹的最終測試集ROC AUC為0.67。如果查看訓練分數,則兩個模型都達到了1.0的 ROC AUC,這也是可以預料到的,因為我們給這些模型提供了訓練答案,並且沒有限制每棵樹的最大深度。

雖然隨機森林過擬合了(在訓練數據上比在測試數據上做得更好),但在測試數據上它比單一決策樹泛化地更好。隨機森林具有較低的方差(好處),同時能保持與一棵決策樹相同的低偏差(也是好處)。

我們還可以繪製單個決策樹(頂部)和隨機森林(底部)的ROC曲線。靠近左上角的曲線代表著更好的模型:


一文讀懂隨機森林的解釋和實現(附python代碼)


決策樹ROC曲線

一文讀懂隨機森林的解釋和實現(附python代碼)


隨機森林ROC曲線

隨機森林明顯優於單一決策樹。

另一個我們可以採用的模型診斷措施是繪製測試集預測結果的混淆矩陣(詳細信息,請參閱notebook):


一文讀懂隨機森林的解釋和實現(附python代碼)



在左上角和右下角它顯示了模型的正確預測,在左下角和右上角顯示了模型誤判的預測。我們可以使用這類圖來診斷我們的模型,來決定它是否表現的足夠良好並可以投入生產。

特徵重要性(Feature Importances)


隨機森林中的特徵重要性表示在該特徵上拆分的所有節點的基尼不純度減少的總和。我們可以使用它來嘗試找出隨機森林認為最重要的預測變量。可以從一個訓練好的隨機森林中提取特徵重要性,並將其放入Pandas的DataFrame中,如下所示:


一文讀懂隨機森林的解釋和實現(附python代碼)



通過告訴我們哪些變量在類之間最具辨別力,特徵重要性可以讓我們更好地洞察問題。例如,DIFFWALK是表明患者是否行走困難的的重要的特徵,這在問題的上下文中也說得通。

通過從最重要的特徵中構建額外的特徵,特徵重要性可以被用於特徵工程(feature engineering)。我們還可以通過刪除不重要的特徵,來把特徵重要性用於特徵選擇。

可視化森林中的樹


最後,我們可以可視化在森林中的單個決策樹。這次我們必須限制樹的深度,否則它將太大而無法被轉換為一幅圖像。為了製作下圖,我將最大深度限制為6。但這仍然產生了一棵我們無法完全解析的大樹!不過由於我們深入地研究過決策樹,我們還是可以通過這幅圖掌握這個模型的工作原理。


一文讀懂隨機森林的解釋和實現(附python代碼)


隨機森林中的單棵決策樹


下一步


下一步是使用Scikit-Learn中的RandomizedSearchCV通過隨機搜索來優化隨機森林。優化是指在給定數據集上找到模型的最佳超參(hyperparameters)。最佳超參將隨著數據集的不同而變化,因此我們必須在每個數據集上單獨執行優化這也稱為模型調整(model tuning)。

我喜歡將模型調整視為給一個機器學習算法尋找最佳設置。我們可以在隨機森林中優化的東西包括決策樹的數量,每個決策樹的最大深度,拆分每個節點的最大特徵數量,以及葉子節點中所能包含的最大數據點數。

有關隨機森林模型優化的隨機搜索的具體實現,請參閱Jupyter Notebook。


完整的運行示例


下面的代碼是使用repl.it創建的,它展示了Python中隨機森林的一個完整的交互式運行示例。你可以隨意運行和更改代碼(加載包可能需要一些時間)。


一文讀懂隨機森林的解釋和實現(附python代碼)


建議查看原文中的交互環境


結論


雖然我們不需要理解底層原理就可以在Python中構建功能強大的機器學習模型,但我發現瞭解幕後發生的事情會更有效。在本文中,我們不僅在Python中構建和使用了隨機森林,而且我們還從基礎出發瞭解了該模型。

我們首先查看了單獨的決策樹,這也是一個隨機森林的基本構成要素,然後我們學習瞭如何通過在一個稱為隨機森林的集成模型中組合數百個決策樹來解決單個決策樹的高方差問題。隨機森林可以總結為使用觀測數據的隨機抽樣,特徵的隨機抽樣並且平均各個樹的預測。

從這篇文章中理解到的關鍵概念是:

  • 決策樹:一種直觀的模型,可根據詢問有關特徵值的一系列問題做出決策。具有低偏差和高方差的特徵,這會導致過擬合訓練數據。
  • 基尼不純度:決策樹在拆分每個節點時嘗試最小化的度量。表示根據節點中的樣本分佈對隨機選擇的樣本分類錯誤的概率。
  • 自助抽樣法:有放回地對觀察值進行隨機採樣。
  • 隨機特徵子集:考慮對決策樹中每個節點的分割時,選擇一組隨機特徵。
  • 隨機森林:使用自助抽樣法,隨機特徵子集和平均投票來進行預測的由許多決策樹組成的集合模型。這是Bagging的一個例子。
  • 偏差方差權衡:機器學習中的核心問題,描述了具有高靈活性(高方差),即可以很好地學習訓練數據,但以犧牲泛化新數據的能力的模型,與無法學習訓練數據的不靈活(高偏差)的模型之間的平衡。隨機森林減少了單個決策樹的方差,從而可以更好地預測新數據。

希望本文為你提供了在項目中使用隨機森林所需的信心和對原理的理解。隨機森林是一種強大的機器學習模型,但這不應該阻止我們理解它的工作機制。我們對模型的瞭解越多,我們就越有能力有效地使用它並解釋它如何進行預測。

一如既往,歡迎進行評論反饋和建設性的批評。可以通過Twitter @koehrsen_will與我聯繫。本文最初發佈於enlight,一個用於研究機器學習的開源社區。感謝enlight和用來託管文中代碼的repl.it。

原文標題:An Implementation and Explanation of the Random Forest in Python副標題:A guide for using and understanding the random forest by building up from a single decision tree原文鏈接:https://towardsdatascience.com/an-implementation-and-explanation-of-the-random-forest-in-python-77bf308a9b76


譯者簡介

一文讀懂隨機森林的解釋和實現(附python代碼)


和中華,留德軟件工程碩士。由於對機器學習感興趣,碩士論文選擇了利用遺傳算法思想改進傳統kmeans。目前在杭州進行大數據相關實踐。加入數據派THU希望為IT同行們儘自己一份綿薄之力,也希望結交許多志趣相投的小夥伴。

— 完 —

關注清華-青島數據科學研究院官方微信公眾平臺“THU數據派”及姊妹號“數據派THU”獲取更多講座福利及優質內容。


分享到:


相關文章: