Python 數(shù)據(jù)科學(xué)手冊 5.8 決策樹和隨機(jī)森林

5.8 決策樹和隨機(jī)森林

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

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

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

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

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

隨機(jī)森林是一個(gè)例子,建立在決策樹上的組合學(xué)習(xí)器。 因此,我們將首先討論決策樹本身。

決策樹是分類或標(biāo)注對象的非常直觀的方法:您只需要詢問一系列問題,它們?yōu)榕宄诸惗O(shè)計(jì)。 例如,如果您想建立一個(gè)決策樹,來分類您在遠(yuǎn)足時(shí)遇到的動(dòng)物,則可以構(gòu)建如下所示的樹:

二元分割使其非常有效:在一個(gè)結(jié)構(gòu)良好的樹中,每個(gè)問題都會(huì)將選項(xiàng)數(shù)量減少一半,即使在大量分類中也很快縮小選項(xiàng)。 當(dāng)然,這個(gè)技巧是決定在每個(gè)步驟中要問哪些問題。 在決策樹的機(jī)器學(xué)習(xí)實(shí)現(xiàn)中,問題通常采用數(shù)據(jù)中軸對齊分割的形式:即,樹中的每個(gè)節(jié)點(diǎn)使用其中一個(gè)特征中的分割值將數(shù)據(jù)分成兩組。 現(xiàn)在來看一個(gè)例子。

創(chuàng)建決策樹

考慮以下二維數(shù)據(jù),它擁有四個(gè)標(biāo)簽之一:

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');

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

請注意,在第一次拆分之后,上部分支中的每個(gè)點(diǎn)保持不變,因此無需進(jìn)一步細(xì)分此分支。 除了包含所有一種顏色的節(jié)點(diǎn),在每個(gè)級別,每個(gè)區(qū)域再次沿著兩個(gè)特征之一分裂。

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

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

讓我們寫一個(gè)簡單的輔助函數(shù),幫助我們展示分類器的輸出:

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)

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

visualize_classifier(DecisionTreeClassifier(), X, y)

如果您現(xiàn)在正在運(yùn)行這個(gè)筆記,您可以使用“在線附錄”中包含的幫助腳本,來啟動(dòng)決策樹構(gòu)建過程的交互式可視化:

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

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

決策樹和過擬合

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

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

如果您正在運(yùn)行這個(gè)筆記,以下功能允許您交互顯示樹的擬合,在數(shù)據(jù)的隨機(jī)子集上訓(xùn)練:

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

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

估計(jì)器的組合:隨機(jī)森林

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

這種類型的裝袋分類,可以使用 Scikit-Learn 的BaggingClassifier元估計(jì)器手動(dòng)進(jìn)行,如下所示:

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)

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

在 Scikit-Learn 中,隨機(jī)決策樹的優(yōu)化組合在RandomForestClassifier估計(jì)器中實(shí)現(xiàn),它自動(dòng)地處理所有的隨機(jī)化。 所有你需要做的是選擇一些估計(jì)器,它將很快(如果需要?jiǎng)t并行)擬合樹的組合:

from sklearn.ensemble import RandomForestClassifier

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

我們看到,通過對超過 100 個(gè)隨機(jī)擾動(dòng)的模型取平均,我們最終得到一個(gè)整體模型,更接近我們關(guān)于如何分割參數(shù)空間的直覺。

隨機(jī)森林回歸

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

考慮以下數(shù)據(jù),由快速和慢速振蕩的組合產(chǎn)生:

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');

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

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

示例:隨機(jī)森林?jǐn)?shù)字分類

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

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

為了提醒我們,我們正在觀察什么,我們展示前幾個(gè)數(shù)據(jù)點(diǎn)。

# 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]))

我們可以快速使用隨機(jī)森林對這些數(shù)字分類,像這樣:

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)

我們可以看一看分類器的分類報(bào)告:

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');

我們發(fā)現(xiàn),簡單無調(diào)整的隨機(jī)森林,產(chǎn)生了數(shù)據(jù)的非常準(zhǔn)確的分類。

隨機(jī)森林總結(jié)

本節(jié)簡要介紹了組合估計(jì)器的概念,特別是隨機(jī)森林 - 隨機(jī)決策樹的整體。 隨機(jī)森林是一個(gè)強(qiáng)大的方法,具有幾個(gè)優(yōu)點(diǎn):

  • 訓(xùn)練和預(yù)測都非??欤?yàn)榈讓記Q策樹簡單。 此外,兩個(gè)任務(wù)都可以直接并行化,因?yàn)楦鱾€(gè)樹是完全獨(dú)立的實(shí)體。
  • 多個(gè)樹提供了概率分類:估計(jì)器之間的多數(shù)表決提供了概率估計(jì)(在 Scikit-Learn 中使用predict_proba()方法來訪問)。
  • 非參數(shù)模型是非常靈活的,因此可以在其他估計(jì)器擬合不足的任務(wù)上表現(xiàn)良好。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容