5.8 決策樹和隨機(jī)森林
譯者:飛龍
協(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è)問題都會將選項(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)鍵觀察是,分類不太確定的地方吝梅,會發(fā)生不一致虱疏,因此通過使用這兩種樹的信息,我們可能會得到更好的結(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ī)森林可能不是最佳選擇纹安。