Python 數據科學手冊 5.8 決策樹和隨機森林

5.8 決策樹和隨機森林

原文:In-Depth: Decision Trees and Random Forests

譯者:飛龍

協議:CC BY-NC-SA 4.0

譯文沒有得到原作者授權,不保證與原文的意思嚴格一致。

之前,我們深入研究了簡單的生成分類器(見樸素貝葉斯分類)和強大的辨別分類器(參見支持向量機)。 這里我們來看看另一個強大的算法的動機 - 一種稱為隨機森林的非參數算法。 隨機森林是組合方法的一個例子,這意味著它依賴于更簡單估計器的整體聚合結果。 這種組合方法的結果令人驚訝,總和可以大于部分:即,多個估器中的多數表決最終可能比執行表決的任何個體的估計更好! 我們將在以下部分中看到這個例子。 我們從標準導入開始:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()

隨機森林是一個例子,建立在決策樹上的組合學習器。 因此,我們將首先討論決策樹本身。

決策樹是分類或標注對象的非常直觀的方法:您只需要詢問一系列問題,它們為弄清楚分類而設計。 例如,如果您想建立一個決策樹,來分類您在遠足時遇到的動物,則可以構建如下所示的樹:

二元分割使其非常有效:在一個結構良好的樹中,每個問題都會將選項數量減少一半,即使在大量分類中也很快縮小選項。 當然,這個技巧是決定在每個步驟中要問哪些問題。 在決策樹的機器學習實現中,問題通常采用數據中軸對齊分割的形式:即,樹中的每個節點使用其中一個特征中的分割值將數據分成兩組。 現在來看一個例子。

創建決策樹

考慮以下二維數據,它擁有四個標簽之一:

from sklearn.datasets import make_blobs

X, y = make_blobs(n_samples=300, centers=4,
                  random_state=0, cluster_std=1.0)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='rainbow');

根據這些數據建立的一個簡單的決策樹,將根據一些定量標準,沿著一個或另一個軸線迭代地分割數據,并且在每個級別,根據其中的多數表決來分配新區域的標簽。 該圖顯示了該數據的決策樹分類器的前四個級別的可視化:

請注意,在第一次拆分之后,上部分支中的每個點保持不變,因此無需進一步細分此分支。 除了包含所有一種顏色的節點,在每個級別,每個區域再次沿著兩個特征之一分裂。

將決策樹擬合到我們的數據的這個過程,可以在 Scikit-Learn 中使用DecisionTreeClassifier估計器來完成:

from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier().fit(X, y)

讓我們寫一個簡單的輔助函數,幫助我們展示分類器的輸出:

def visualize_classifier(model, X, y, ax=None, cmap='rainbow'):
    ax = ax or plt.gca()
    
    # Plot the training points
    ax.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=cmap,
               clim=(y.min(), y.max()), zorder=3)
    ax.axis('tight')
    ax.axis('off')
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    
    # fit the estimator
    model.fit(X, y)
    xx, yy = np.meshgrid(np.linspace(*xlim, num=200),
                         np.linspace(*ylim, num=200))
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

    # Create a color plot with the results
    n_classes = len(np.unique(y))
    contours = ax.contourf(xx, yy, Z, alpha=0.3,
                           levels=np.arange(n_classes + 1) - 0.5,
                           cmap=cmap, clim=(y.min(), y.max()),
                           zorder=1)

    ax.set(xlim=xlim, ylim=ylim)

現在我們可以檢測,決策樹看起來是什么樣子:

visualize_classifier(DecisionTreeClassifier(), X, y)

如果您現在正在運行這個筆記,您可以使用“在線附錄”中包含的幫助腳本,來啟動決策樹構建過程的交互式可視化:

# helpers_05_08 is found in the online appendix
import helpers_05_08
helpers_05_08.plot_tree_interactive(X, y);

請注意,隨著深度的增加,我們傾向于獲得非常奇怪的分類區域; 例如,在第五層,黃色和藍色區域之間有一個高而瘦的紫色區域。 很明顯,這不是真實的,固有的數據分布結果,更多的是數據的特定采樣或噪聲屬性的結果。 也就是說,這個決策樹,即使只有五個層次的深度,顯然對我們的數據過擬合了。

決策樹和過擬合

這種過度擬合是決策樹的一般屬性:在樹中很容易就走得太深,從而擬合特定數據的細節,而不是抽取它們分布的整體屬性。 查看這種過擬合的另一種方法是,查看在不同數據子集上訓練的模型 - 例如,在這個圖中,我們訓練兩種不同的樹,每種都是原始數據的一半:

很明顯,在一些地方,兩棵樹產生一致的結果(例如在四個角落),而在其他地方,這兩棵樹給出非常不同的分類(例如,在任何兩個簇之間的區域中)。 關鍵觀察是,分類不太確定的地方,會發生不一致,因此通過使用這兩種樹的信息,我們可能會得到更好的結果!

如果您正在運行這個筆記,以下功能允許您交互顯示樹的擬合,在數據的隨機子集上訓練:

# helpers_05_08 is found in the online appendix
import helpers_05_08
helpers_05_08.randomized_tree_interactive(X, y)

正如使用來自兩棵樹的信息,改善了我們的結果,我們可能希望使用來自許多樹的信息,進一步改善我們的結果。

估計器的組合:隨機森林

這個概念 - 多個過擬合估計器可以組合,來減少這種過擬合的影響 - 是一種稱為裝袋的組合方法。 這個方法使用了一組并行估計器,每個都對數據過擬合,并對結果進行平均以找到更好的分類。 隨機決策樹的一個組合被稱為隨機森林。

這種類型的裝袋分類,可以使用 Scikit-Learn 的BaggingClassifier元估計器手動進行,如下所示:

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier

tree = DecisionTreeClassifier()
bag = BaggingClassifier(tree, n_estimators=100, max_samples=0.8,
                        random_state=1)

bag.fit(X, y)
visualize_classifier(bag, X, y)

在這個例子中,我們將每個估計器擬合訓練點的 80% 隨機子集進行來隨機化數據。 在實踐中,通過在選擇分割的方式中添加一些隨機性,來更有效地隨機化決策樹:這樣,所有數據每次都有助于擬合,但是擬合的結果仍然具有所需的隨機性。 例如,當確定要分割的特征時,隨機化樹可以從前幾個特征中選擇。 您可以在 Scikit-Learn 文檔中閱讀這些隨機策略的更多技術細節和參考。

在 Scikit-Learn 中,隨機決策樹的優化組合在RandomForestClassifier估計器中實現,它自動地處理所有的隨機化。 所有你需要做的是選擇一些估計器,它將很快(如果需要則并行)擬合樹的組合:

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(n_estimators=100, random_state=0)
visualize_classifier(model, X, y);

我們看到,通過對超過 100 個隨機擾動的模型取平均,我們最終得到一個整體模型,更接近我們關于如何分割參數空間的直覺。

隨機森林回歸

在上一節中,我們在分類范圍內考慮了隨機森林。 隨機森林也可以用于回歸(即連續而不是分類變量)。 用于此的估計器是RandomForestRegressor,并且語法與我們之前看到的非常相似。

考慮以下數據,由快速和慢速振蕩的組合產生:

rng = np.random.RandomState(42)
x = 10 * rng.rand(200)

def model(x, sigma=0.3):
    fast_oscillation = np.sin(5 * x)
    slow_oscillation = np.sin(0.5 * x)
    noise = sigma * rng.randn(len(x))

    return slow_oscillation + fast_oscillation + noise

y = model(x)
plt.errorbar(x, y, 0.3, fmt='o');

使用隨機森林回歸器,我們可以找到最佳擬合曲線,

這里的真實模型以灰色平滑曲線中顯示,隨機森林模型由紅色鋸齒曲線顯示。 可以看出,非參數隨機森林模型足夠靈活,可以擬合多周期數據,而不需要指定多周期模型!

示例:隨機森林數字分類

早些時候我們快速瀏覽了手寫數字數據(參見 Scikit-Learn 介紹)。 讓我們再次使用它,來看看如何在這個上下文中使用隨機森林分類器。

from sklearn.datasets import load_digits
digits = load_digits()
digits.keys()
# dict_keys(['target', 'data', 'target_names', 'DESCR', 'images'])

為了提醒我們,我們正在觀察什么,我們展示前幾個數據點。

# set up the figure
fig = plt.figure(figsize=(6, 6))  # figure size in inches
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)

# plot the digits: each image is 8x8 pixels
for i in range(64):
    ax = fig.add_subplot(8, 8, i + 1, xticks=[], yticks=[])
    ax.imshow(digits.images[i], cmap=plt.cm.binary, interpolation='nearest')
    
    # label the image with the target value
    ax.text(0, 7, str(digits.target[i]))

我們可以快速使用隨機森林對這些數字分類,像這樣:

from sklearn.cross_validation import train_test_split

Xtrain, Xtest, ytrain, ytest = train_test_split(digits.data, digits.target,
                                                random_state=0)
model = RandomForestClassifier(n_estimators=1000)
model.fit(Xtrain, ytrain)
ypred = model.predict(Xtest)

我們可以看一看分類器的分類報告:

from sklearn import metrics
print(metrics.classification_report(ypred, ytest))
             precision    recall  f1-score   support

          0       1.00      0.97      0.99        38
          1       1.00      0.98      0.99        44
          2       0.95      1.00      0.98        42
          3       0.98      0.96      0.97        46
          4       0.97      1.00      0.99        37
          5       0.98      0.96      0.97        49
          6       1.00      1.00      1.00        52
          7       1.00      0.96      0.98        50
          8       0.94      0.98      0.96        46
          9       0.96      0.98      0.97        46

avg / total       0.98      0.98      0.98       450

為了更好的度量,繪制混淆矩陣:

from sklearn.metrics import confusion_matrix
mat = confusion_matrix(ytest, ypred)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False)
plt.xlabel('true label')
plt.ylabel('predicted label');

我們發現,簡單無調整的隨機森林,產生了數據的非常準確的分類。

隨機森林總結

本節簡要介紹了組合估計器的概念,特別是隨機森林 - 隨機決策樹的整體。 隨機森林是一個強大的方法,具有幾個優點:

  • 訓練和預測都非???,因為底層決策樹簡單。 此外,兩個任務都可以直接并行化,因為各個樹是完全獨立的實體。
  • 多個樹提供了概率分類:估計器之間的多數表決提供了概率估計(在 Scikit-Learn 中使用predict_proba()方法來訪問)。
  • 非參數模型是非常靈活的,因此可以在其他估計器擬合不足的任務上表現良好。

隨機森林的主要缺點是結果不容易解釋:即如果要對分類模型的含義作出總結,隨機森林可能不是最佳選擇。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容