因為有 Scikit-Learn
這樣的庫,現在用Python實作任何機器學習算法都非常容易。實際上,我們現在不需要任何潛在的知識來了解模型如何工作。雖然不需要了解所有細節,但了解模型如何訓練和預測對工作仍有幫助。比如:如果性能不如預期,我們可以診斷模型或當我們想要說服其他人使用我們的模型時,我們可以向他們解釋模型如何做出決策的。
在本文中,我們将介紹如何在Python中建構和使用Random Forest,而不是僅僅顯示代碼,我将嘗試了解模型的工作原理。我将從一個簡單的單一決策樹開始,然後以解決現實世界資料科學問題的方式完成随機森林。本文的完整代碼
在GitHub上 以 Jupyter Notebook的形式提供 。了解決策樹
決策樹是随機森林的建構塊,它本身就是個直覺的模型。我們可以将決策樹視為詢問有關我們資料問題的流程圖。這是一個可解釋的模型,因為它決定了我們在現實生活中的做法:在最終得出決定之前,我們會詢問有關資料的一系列問題。
決策樹的主要技術細節是如何建構有關資料的問題,決策樹是通過形成能夠最大限度減少
基尼系數的問題而建立的。稍後我會讨論Gini Impurity,但這意味着決策樹試圖形成盡可能純的節點,其中包含來自單個類的高比例樣本(資料點)的節點。
Gini Impurity和建構樹可能有點難以了解,是以首先讓我們建構一個決策樹,以便可以更好的了解它。
關于最簡單問題的決策樹
我們從一個非常簡單的二進制分類問題開始,如下所示:
我們的資料隻有兩個特征(标簽),且隻有6個資料點。
雖然這個問題很簡單,但它不是線性可分的,這意味着我們不能通過資料繪制一條直線來對點進行分類。然而,我們可以繪制一系列劃分類的直線,這基本上是決策樹在形成一系列問題時将要做的事情。
要建立決策樹并在資料上訓練,我們可以使用Scikit-Learn:
from sklearn.tree import DecisionTreeClassifier
# Make a decision tree and train
tree = DecisionTreeClassifier(random_state=RSEED)
tree.fit(X, y)
在訓練過程中,我們為模型提供特征和标簽,以便學習根據特征對點進行分類。我們沒有針對這個簡單問題的測試集,但是在測試時,我們隻給模型提供功能并讓它對标簽做出預測。
我們可以在訓練資料上測試我們模型的準确性:
print(f'Model Accuracy: {tree.score(X, y)}')
Model Accuracy: 1.0
我們看到它100%正确,這是我們所期望的,因為我們給了它訓練的答案。
可視化決策樹
當我們訓練決策樹時,實際上會發生什麼?我發現了解決策樹的最有用的方法是通過可視化,我們可以使用Scikit-Learn的功能(詳細資訊請檢視
筆記本或
本文)。
上圖顯示了決策樹的整個結構,除葉節點(終端節點)外,所有節點都有5個部分:
- 問題基于特征值詢問資料:每個問題都有對或錯的答案。根據問題的答案,資料點在樹中移動。
- Gini:節點的Gini雜質。當我們向下移動樹時,平均權重基尼系數必須減少。
- samples:節點中的觀察數。
- value:每個類的樣本數量。例如,頂部節點在類0中有2個樣本,在類1中有4個樣本。
- class:節點中點的多數分類。在葉節點的情況下,這是對節點中所有樣本的預測。
葉節點沒有問題,因為這些是最終預測的地方。要對新節點進行分類,隻需向下移動樹,使用點的特征來回答問題,直到到達class預測的葉節點。你可以使用上面的點進行嘗試,或者進行不同的預測。
基尼系數
在這一點上,我們應該嘗試了解基尼系數。簡而言之,Gini Impurity是随機選擇的樣本被節點中的樣本分布标記錯誤的機率。例如,在頂部(根)節點中,有44.4%錯誤的可能性根據節點中樣本标簽的分布對随機選擇的資料點進行分類。我們可以使用下面這個等式得到這個值:
節點的Gini系數n是1減去每個J類的p_i平方的總和,讓我們計算出根節點的基尼系數。
在每個節點處,決策樹在要素中搜尋要拆分的值,進而最大限度地減少基尼系數。(
拆分節點的
替代方法是使用資訊增益然後,它以
遞歸過程重複此拆分過程,直到達到最大深度,或者每個節點僅包含來自一個類的樣本。每層樹的權重總基尼系數必須減少。在樹的第二層,總權重基尼系數值為0.333:
最後一層的權重總Gini系數變為0意味着每個節點都是純粹的,并且從該節點随機選擇的點不會被錯誤分類。雖然這似乎是好結果,但這意味着模型可能過度拟合,因為節點僅使用是通過訓練資料建構的。
過度拟合:為什麼森林比一棵樹更好
你可能會想問為什麼不隻使用一個決策樹?它似乎是完美的分類器,因為它沒有犯任何錯誤!記住這其中的關鍵點是樹在訓練資料上沒有犯錯。因為我們給樹提供了答案。機器學習模型的要點是很好地概括測試資料。不幸的是,當我們不限制決策樹的深度時,它往往會過度拟合。
當我們的模型具有高方差并且基本上記憶訓練資料時,一定會發生過度拟合。這意味着它可以很好地在訓練資料上,但由于測試資料不同,它将無法對測試資料做出準确的預測!我們想要的是一個能很好地學習訓練資料的模型,并且可以在其他資料集上發揮作用。當我們不限制最大深度時,決策樹容易過度拟合的原因是因為它具有無限的複雜性,這意味着它可以保持增長,直到它為每個單獨的觀察隻有一個葉節點,完美地對所有這些進行分類。
要了解為什麼決策樹具有高差異,我們可以用一個人來考慮它。想象一下,你覺得明天蘋果股票會上漲,你會問一些分析師。每一位分析師都可能會有很大差異并且會嚴重依賴他們可以通路的資料。一位分析師可能隻閱讀親蘋果新聞,是以她認為價格會上漲,而另一位分析師最近從她的朋友那裡聽到蘋果産品的品質開始下降,她可能就認為價格會下降。這些個體分析師的差異很大,因為他們的答案極其依賴于他們所看到的資料。
因為每個分析師都可以通路不同的資料,是以預計個體差異會很大,但整個集合的總體方差應該減少。使用許多個體本質上是随機森林背後的想法:而不是一個決策樹,使用數百或數千個樹來形成一個強大的模型。(過度拟合的問題被稱為
偏差-方差權衡,它是機器學習中的一個基本主題)。
随機森林
是許多決策樹組成的模型。這個模型不僅僅是一個森林,而且它還是随機的,因為有兩個概念:
- 随機抽樣的資料點;
- 基于要素子集拆分的節點;
随機抽樣
随機森林背後的關鍵是每棵樹在資料點的随機樣本上訓練。樣本用替換(稱為bootstrapping)繪制,這意味着一些樣本将在一個樹中多次訓練。這個想法是通過對不同樣本的每棵樹進行訓練,盡管每棵樹相對于一組特定的訓練資料可能有很大的差異,但總體而言,整個森林的方差都很小。每個學習者在資料的不同子集上學習,然後進行平均的過程被稱為bagging,簡稱bootstrap aggregating。
用于拆分節點的随機特征子集
随機森林背後的另一個關鍵點是,隻考慮所有特征的子集來分割每個決策樹中的每個節點。通常,這被設定為sqrt(n_features)意味着在每個節點處,決策樹考慮在特征的樣本上分割總計特征總數的平方根。考慮到每個節點的所有特征,也可以訓練随機森林。
如果你掌握單個決策樹、bagging決策樹和随機特征子集,那麼你就可以很好地了解随機森林的工作原理。随機森林結合了數百或數千個決策樹,在略微不同的觀察集上訓練每個決策樹,并且僅考慮有限數量的特征來分割每個樹中的節點。随機森林做出的最終預測是通過平均每棵樹的預測來做出的。
随機森林實踐
與其他Scikit-Learn模型非常相似,在Python中使用随機森林隻需要幾行代碼。我們将建構一個随機森林,但不是針對上面提到的簡單問題。為了将随機森林與單個決策樹的能力進行對比,我們将使用分為訓練和測試的真實資料集。
資料集
我們要解決的問題是二進制分類任務。這些特征是個人的社會經濟和生活方式特征,标簽是健康狀況不佳為0和身體健康為1。此資料集是由
中心疾病控制和預防收集,
可以在這裡找到。這是一個不平衡的分類問題,是以準确性不是一個合适的名額。相反,我們将測量
接收器工作特性區域曲線(ROC AUC),從0(最差)到1(最佳)的度量,随機猜測得分為0.5。我們還可以繪制ROC曲線以評估模型性能。
該
包含了決策樹和随機森林的實作,但在這裡我們隻專注于随機森林。在讀取資料後,我們可以實作并訓練随機森林如下:
from sklearn.ensemble import RandomForestClassifier
# Create the model with 100 trees
model = RandomForestClassifier(n_estimators=100,
bootstrap = True,
max_features = 'sqrt')
# Fit on training data
model.fit(train, train_labels)
在訓練幾分鐘後,準備好對測試資料進行如下預測:
# Actual class predictions
rf_predictions = model.predict(test)
# Probabilities for each class
rf_probs = model.predict_proba(test)[:, 1]
我們進行類預測(predict)以及predict_proba計算ROC AUC所需的預測機率()。一旦我們進行了預測測試,我們就可以将它們與測試标簽進行比較,以計算出ROC AUC。
from sklearn.metrics import roc_auc_score
# Calculate roc auc
roc_value = roc_auc_score(test_labels, rf_probs)
結果
最終的ROC
AUC是随機森林為0.87,而單一決策樹是0.67。如果我們檢視訓練分數,我們注意到兩個模型都達到了1.0 ROC AUC,因為我們給這些模型提供了訓練答案,并沒有限制最大深度。然而,盡管随機森林過度拟合,但它能夠比單一決策樹更好地推廣測試資料。
如果我們檢查模型,我們會看到單個決策樹達到最大深度55,總共12327個節點。随機森林中的平均決策樹的深度為46和13396個節點。即使平均節點數較多,随機森林也能更好地推廣!
我們還可以繪制單個決策樹(頂部)和随機森林(底部)的ROC曲線。頂部和左側的曲線是更好的模型:
我們看到随機森林明顯優于單一決策樹。我們可以采用模型的另一個診斷措施是繪制測試預測的混淆矩陣:
特征重要性(Feature Importances)
随機森林中的特征重要性表示在該特征上拆分的所有節點上
Gini系數減少 總和。我們可以使用這些來嘗試找出随機森林最重要的預測變量,同時也可以從訓練有素的随機森林中提取特征重要性,并将其放入Pandas資料框中,如下所示:
import pandas as pd
# Extract feature importances
fi = pd.DataFrame({'feature': list(train.columns),
'importance': model.feature_importances_}).\
sort_values('importance', ascending = False)
# Display
fi.head()
feature importance
DIFFWALK 0.036200
QLACTLM2 0.030694
EMPLOY1 0.024156
DIFFALON 0.022699
USEEQUIP 0.016922
我們還可以通過删除具有0或低重要性的特征來使用特征重要性來
選擇特征在森林中可視化樹
最後,我們可以在森林中可視化單個決策樹。這次,我們必須限制樹的深度,否則它将太大而無法轉換為圖像。為了制作我将最大深度限制為6,這仍然導緻我們無法完全解析的大樹!
優化決策樹
下一步可能是通過随機搜尋和
Scikit-Learn中 RandomizedSearchCV來優化随機森林。
優化是指在給定資料集上找到模型的最佳超參數。最佳超參數将在資料集之間變化,是以我們必須在每個資料集上單獨執行優化(也稱為模型調整)。我喜歡将模型調整視為尋找機器學習算法的最佳設定。有關随機森林模型優化的随機搜尋的實作,請參閱
Jupyter Notebook。結論
在本文中,我們不僅在Python中建構和使用了随機森林,而且還對模型的進行了分析。
我們首先檢視了一個單獨的決策樹,一個随機森林的基本建構塊,然後我們看到了如何在一個集合模型中組合數百個決策樹。當與bagging特征一起使用和随機抽樣時,該集合模型被稱為随機森林。從這篇文章中了解的關鍵概念是:
- 決策樹:直覺模型,根據詢問有關特征值的問題流程圖做出決策,通過過度拟合訓練資料表示方差高。
-
Gini
Impurity:衡量決策樹在拆分每個節點時嘗試最小化的度量。表示根據節點中樣本的分布對來自節點的随機選擇的樣本進行分類的機率。
- Bootstrapping:用替換的方式随機觀察組進行采樣。随機森林用于訓練每個決策樹的方法。
- 随機的特征子集:在考慮如何在決策樹中分割每個節點時選擇一組随機特征。
- 随機森林:由數百或數千個決策樹組成的集合模型,使用自舉,随機特征子集和平均投票來進行預測。這是一個bagging整體的例子。
- 偏差-方差權衡:機器學習中的基本問題,描述了高複雜度模型之間的權衡,以采用最好的方式學習訓練資料,代價是無法推廣到測試資料以及簡單的模型(高偏見)甚至無法學習訓練資料。随機森林減少了單個決策樹的方差,同時還準确地學習了訓練資料,進而更好地預測了測試資料。
希望本文為你提供了開始在項目中使用随機森林所需的信心和了解。随機森林是一種強大的機器學習模型,但這不應該阻止我們知道它是如何工作的!
本文由
阿裡雲雲栖社群組織翻譯。
文章原标題《an-implementation-and-explanation-of-the-random-forest-in-python》
作者:
William Koehrsen譯者:虎說八道,審校:。
文章為簡譯,更為詳細的内容,請檢視
原文