使用Python了解分類決策樹(附代碼)(python決策樹分類算法代碼)
作者:Michael Galarnyk
翻譯:李潤嘉
校對:和中華
本文約3600字,建議閱讀15分鐘。
本教程介紹了用于分類的決策樹,即分類樹,包括分類樹的結(jié)構(gòu),分類樹如何進(jìn)行預(yù)測,使用scikit-learn構(gòu)造分類樹,以及超參數(shù)的調(diào)整。
本教程詳細(xì)介紹了決策樹的工作原理
由于各種原因,決策樹一種流行的監(jiān)督學(xué)習(xí)方法。決策樹的優(yōu)點(diǎn)包括,它既可以用于回歸,也可用于分類,易于解釋并且不需要特征縮放。它也有一些缺點(diǎn),比如容易過擬合。本教程介紹了用于分類的決策樹,也被稱為分類樹。
除此之外,本教程還將涵蓋:
- 分類樹的結(jié)構(gòu)(樹的深度,根節(jié)點(diǎn),決策節(jié)點(diǎn),葉節(jié)點(diǎn)/終端節(jié)點(diǎn))
- 分類樹如何進(jìn)行預(yù)測
- 如何通過Python中的scikit-learn構(gòu)造決策樹
- 超參數(shù)調(diào)整
與往常一樣,本教程中用到的代碼可以在我的github(結(jié)構(gòu),預(yù)測)中找到,我們開始吧!
什么是分類樹?
分類和回歸樹(CART)是由Leo Breiman引入的,用一種于解決分類或回歸預(yù)測建模問題的決策樹算法。本文只介紹分類樹。
分類樹
從本質(zhì)上講,分類樹將分類轉(zhuǎn)化為一系列問題。下圖是在IRIS數(shù)據(jù)集(花卉種類)上訓(xùn)練的一個分類樹。根節(jié)點(diǎn)(棕色)和決策節(jié)點(diǎn)(藍(lán)色)中包含了用于分裂子節(jié)點(diǎn)的問題。根節(jié)點(diǎn)即為最頂端的決策節(jié)點(diǎn)。換句話說,它就是你遍歷分類樹的起點(diǎn)。葉子節(jié)點(diǎn)(綠色),也叫做終端節(jié)點(diǎn),它們不再分裂成更多節(jié)點(diǎn)。在葉節(jié)點(diǎn)處,通過多數(shù)投票決定分類。
將三個花卉品種(IRIS數(shù)據(jù)集)一一進(jìn)行分類的分類樹
如何使用分類樹
使用分類樹,要從根節(jié)點(diǎn)(棕色)開始,逐層遍歷整棵樹,直到到達(dá)葉節(jié)點(diǎn)(終端節(jié)點(diǎn))。如下圖所示的分類樹,假設(shè)你有一朵花瓣長度為4.5cm的花,想對它進(jìn)行分類。首先從根節(jié)點(diǎn)開始,先回答“花瓣長度(單位:cm)≤ 2.45嗎?”因?yàn)閷挾却笥?.45,所以回答否。然后進(jìn)入下一個決策節(jié)點(diǎn),回答“花瓣長度(單位:cm)≤ 4.95嗎?”。答案為是,所以你可以預(yù)測這朵花的品種為變色鳶尾(versicolor)。這就是一個簡單的例子。
分類樹如何生長(非數(shù)學(xué)版)
分類樹從數(shù)據(jù)中學(xué)到了一系列“如果…那么…”的問題,其中每個問題都涉及到一個特征和一個分割節(jié)點(diǎn)。從下圖的局部樹(A)可看出,問題“花瓣長度(單位:cm)≤ 2.45”將數(shù)據(jù)基于某個值(本例中為2.45)分成兩個部分。這個數(shù)值叫做分割點(diǎn)。對分割點(diǎn)而言,一個好的值(使得信息增益最大)可將類與類之間分離開。觀察下圖中的B部分可知,位于分割點(diǎn)左側(cè)的所有點(diǎn)都被歸為山鳶尾類(setosa),右側(cè)的所有點(diǎn)則被歸為變色鳶尾類(versicolor)。
從圖中可看出,山鳶尾類(setosa)中所有的38個點(diǎn)都已被正確分類。它是一個純節(jié)點(diǎn)。分類樹在純節(jié)點(diǎn)上不會分裂。它不再產(chǎn)生信息增益。但是不純節(jié)點(diǎn)可以進(jìn)一步分裂。觀察圖B的右側(cè)可知,許多點(diǎn)被錯誤歸類到了變色鳶尾類(versicolor)。換而言之,它包含了分屬于兩個不同類(setosa和versicolor)的點(diǎn)。分類樹是個貪婪算法,這意味著它會默認(rèn)一直分裂直到得到純節(jié)點(diǎn)。而且,該算法會為不純節(jié)點(diǎn)選擇最佳分割點(diǎn)(我們會在下節(jié)介紹數(shù)學(xué)方法)。
在上圖中,樹的最大深度為2。樹的深度是對一棵樹在進(jìn)行預(yù)測之前可分裂次數(shù)的度量。樹可進(jìn)行多次分裂,直到樹的純度越來越高。多次重復(fù)此過程,會導(dǎo)致樹的深度越來越大,節(jié)點(diǎn)越來越多。這會引起對訓(xùn)練數(shù)據(jù)的過擬合。幸運(yùn)的是, 大多數(shù)分類樹的實(shí)現(xiàn)都允許控制樹的最大深度,從而減少過擬合。換而言之,可以通過設(shè)置決策樹的最大深度從而阻止樹的生長超過某個特定深度??赏ㄟ^下圖直觀地了解最大深度。
選擇準(zhǔn)則
本節(jié)解答了信息增益、基尼指數(shù)和熵是如何計(jì)算出來的。
在本節(jié),你可以了解到什么是分類樹中根節(jié)點(diǎn)/決策節(jié)點(diǎn)的最佳分割點(diǎn)。決策樹在某個特征和相對應(yīng)的分割點(diǎn)上進(jìn)行分裂,從而根據(jù)給定的準(zhǔn)則(本例中為基尼指數(shù)或熵)產(chǎn)生最大的信息增益(IG)??梢詫⑿畔⒃鲆婧唵味x為:
IG = 分裂前的信息(父) – 分裂后的信息(子)
通過下圖的決策樹,我們可以更清晰的理解父與子。
下圖為更準(zhǔn)確的信息增益公式。
因?yàn)榉诸悩涫嵌至?,上述公式可以簡化為以下公式?/p>
基尼指數(shù)和熵是兩個用于衡量節(jié)點(diǎn)不純度的常用準(zhǔn)則。
為了更好的理解這些公式,下圖展示了如何使用基尼指數(shù)準(zhǔn)則計(jì)算決策樹的信息增益。
下圖展示了如何使用熵來計(jì)算決策樹的信息增益。
我不打算對細(xì)節(jié)進(jìn)行過多的闡述,但是你應(yīng)當(dāng)知道,不同的不純度度量(基尼指數(shù)和熵)通常會產(chǎn)生相似的結(jié)果。下圖就展示了基尼指數(shù)和熵是極其相似的不純度度量。我猜測,基尼指數(shù)之所以是scikit-learn的默認(rèn)值,是因?yàn)殪氐挠?jì)算過程略慢一些(因?yàn)樗褂昧藢?shù))。
不同的不純度度量(基尼指數(shù)和熵)通常會產(chǎn)生相似的結(jié)果。感謝Data Science StackExchange 和 Sebastian Raschka為本圖提供的靈感。
在結(jié)束本節(jié)之前,我應(yīng)注明,各種決策樹算法彼此不同。比較流行的算法有ID3,C4.5和CART。Scikit-learn使用了CART算法的優(yōu)化版本。你可以點(diǎn)擊此處了解它的時間復(fù)雜度。
使用Python實(shí)現(xiàn)分類樹
我們在上節(jié)介紹了分類樹的理論。之所以需要學(xué)習(xí)如何使用某個編程語言來實(shí)現(xiàn)決策樹,是因?yàn)樘幚頂?shù)據(jù)可以幫助我們來理解算法。
加載數(shù)據(jù)
Iris數(shù)據(jù)集是scikit-learn自帶的數(shù)據(jù)集之一,不需要從外部網(wǎng)站下載。通過下列代碼載入數(shù)據(jù)。
import pandas as pdfrom sklearn.datasets import load_irisdata = load_iris()df = pd.DataFrame(data.data, columns=data.feature_names)df[‘target’] = data.target
原始Pandas df(特征和目標(biāo))
將數(shù)據(jù)劃分為訓(xùn)練集和測試集
下述代碼將75%的數(shù)據(jù)劃分到為訓(xùn)練集,25%的數(shù)據(jù)劃分到測試集合。
X_train, X_test, Y_train, Y_test = train_test_split(df[data.feature_names], df[‘target’], random_state=0)
圖中的顏色標(biāo)注了數(shù)據(jù)框df中的數(shù)據(jù)劃分到了哪類(X_train, X_test, Y_train, Y_test)變量
注意,決策樹的優(yōu)點(diǎn)之一是,你不需要標(biāo)準(zhǔn)化你的數(shù)據(jù),這與PCA和邏輯回歸不同,沒有標(biāo)準(zhǔn)化的數(shù)據(jù)對它們的影響非常大。
Scikit-learn建模的四個步驟
第一步:導(dǎo)入你想使用的模型
在scikit-learn中,所有的機(jī)器學(xué)習(xí)模型都被封裝為Python中的類。
from sklearn.tree import DecisionTreeClassifier
第二步:構(gòu)造模型的實(shí)例
在下列代碼中,我通過設(shè)定max_depth=2來預(yù)剪枝我的樹,從而確保它的深度不會超過2。請注意,這個教程的下一節(jié)將介紹如何為你的樹選擇恰當(dāng)?shù)膍ax_depth值。
還需注意,在下列代碼中,我設(shè)定random_state=0,所以你也可以得到和我一樣的結(jié)果。
clf = DecisionTreeClassifier(max_depth = 2, random_state = 0)
第三步:基于數(shù)據(jù)訓(xùn)練模型
該模型將學(xué)習(xí)X (sepal length, sepal width, petal length, and petal width) 和 Y(species of iris)之間的關(guān)系。
clf.fit(X_train, Y_train)
第四步:預(yù)測未知(測試)數(shù)據(jù)的標(biāo)簽
# predict for 1 observationclf.predict(X_test.iloc[0].values.reshape(1, -1))# Predict for multiple observationsclf.predict(X_test[0:10])
請記住,預(yù)測只是葉節(jié)點(diǎn)中實(shí)例的多數(shù)類。
評估模型性能
盡管有許多評估模型性能的方式(精度,召回率,F(xiàn)1得分,ROC曲線等),我們還是保持簡單的基調(diào),使用準(zhǔn)確率作為評估的標(biāo)準(zhǔn)。
準(zhǔn)確率的定義為:(正確預(yù)測的比例):正確預(yù)測的數(shù)量/總數(shù)據(jù)量
# The score method returns the accuracy of the modelscore = clf.score(X_test, Y_test)print(score)
調(diào)整樹的深度
尋找max_depth最優(yōu)值的過程就是調(diào)整模型的過程。下列代碼輸出了不同max_depth值所對應(yīng)的決策樹的準(zhǔn)確率。
# List of values to try for max_depth:max_depth_range = list(range(1, 6))# List to store the accuracy for each value of max_depth:accuracy = []for depth in max_depth_range: clf = DecisionTreeClassifier(max_depth = depth, random_state = 0)clf.fit(X_train, Y_train) score = clf.score(X_test, Y_test) accuracy.append(score)
由下圖可看出,當(dāng)max_depth的值大于或等于3時,模型的準(zhǔn)確率最高,所以選擇max_depth=3,在準(zhǔn)確率同樣高的情況下,模型的復(fù)雜度最低。
選擇max_depth=3因?yàn)榇藭r模型的精確率高且復(fù)雜度較低。
你需要謹(jǐn)記,max_depth和決策樹的深度并不是一回事。Max_depth是對決策樹進(jìn)行預(yù)剪枝的一個方法。換而言之,如果一棵樹在某個深度純度已經(jīng)足夠高,將會停止分裂。下圖分別展示了當(dāng)max_depth的值為3,4,5時的決策樹。由下圖可知,max_depth為4和5時的決策樹是一模一樣的。它們的深度相同。
請觀察我們是如何得到兩棵一模一樣的樹
如果想知道你訓(xùn)練的決策樹的深度是多少,可以使用get_depth方法。除此之外,可以通過get_n_leaves方法得到葉子節(jié)點(diǎn)的數(shù)量。
盡管本教程已經(jīng)介紹了一些選擇準(zhǔn)則(基尼指數(shù),熵等)和樹的max_depth,請記住你也可以調(diào)整要分裂的節(jié)點(diǎn)的最小樣本(min_samples_leaf),最大葉子節(jié)點(diǎn)數(shù)量(max_leaf_nodes)等。
特征重要性
分類樹的優(yōu)點(diǎn)之一是,它們相對易于解釋?;趕cikit-learn的分類樹可以計(jì)算出特征的重要性,即在給定特征上分裂而導(dǎo)致基尼指數(shù)或熵減小的總量。Scikit-learn對每個特征輸出一個0和1之間的數(shù)值。所有特征的重要性之和為1。下列代碼展示了在決策樹模型中每個特征的重要性。
importances = pd.DataFrame({‘feature’:X_train.columns,’importance’:np.round(clf.feature_importances_,3)})importances = importances.sort_values(‘importance’,ascending=False)
在上述例子中(iris的某個特定的訓(xùn)練集測試集劃分),花瓣寬度的特征重要性權(quán)重最高。我們可以通過察看相應(yīng)的決策樹來確認(rèn)。
這個決策樹僅基于兩個特征進(jìn)行分裂,分別是花瓣寬度(單位:cm)和花瓣長度(單位:cm)
請注意,如果一個特征的重要性分值較低,也并不意味著這個特征對預(yù)測而言不重要,只是說明在樹的較早階段,它未被選擇到。該特征也可能與另一個信息量較高的特征完全相同或高度相關(guān)。特征重要性值不能說明它們對哪個類別具有很好的預(yù)測性,也不會說明可能影響預(yù)測的特征之間的關(guān)系。要注意的是,在進(jìn)行交叉驗(yàn)證或類似的驗(yàn)證時,可以使用來自不同訓(xùn)練集測試集劃分的特征重要性值的平均值。
結(jié)束語
雖然這篇文章只介紹了用于分類的決策樹,但請隨意閱讀我的其他文章《用于回歸的決策樹(Python)》。分類和回歸樹(CART)是一個相對較老的技術(shù)(1984),是更復(fù)雜的技術(shù)的基礎(chǔ)。決策樹的主要缺點(diǎn)之一是它們通常不是最準(zhǔn)確的算法。部分原因是決策樹是一種高方差算法,這意味著訓(xùn)練數(shù)據(jù)中的不同劃分會導(dǎo)致非常不同的樹。如果您對本教程有任何疑問或想法,請隨時通過以下評論或通過Twitter與我們聯(lián)系。
作者簡介:
Michael Galarnyk是一名數(shù)據(jù)科學(xué)家和企業(yè)培訓(xùn)師。他目前在Scripps翻譯研究所工作。
您可以在:
Twitter(https://twitter.com/GalarnykMichael)
Medium(https://medium.com/@GalarnykMichael)
GitHub(https://github.com/mGalarnyk)上找到他。
原文標(biāo)題:
Understanding Decision Trees for Classification in Python
原文鏈接:
https://www.kdnuggets.com/2019/08/understanding-decision-trees-classification-python.htm
編輯:于騰凱
校對:林亦霖
譯者簡介
李潤嘉,首都師范大學(xué)應(yīng)用統(tǒng)計(jì)碩士在讀。對數(shù)據(jù)科學(xué)和機(jī)器學(xué)習(xí)興趣濃厚,語言學(xué)習(xí)愛好者。立志做一個有趣的人,學(xué)想學(xué)的知識,去想去的地方,敢想敢做,不枉歲月。
— 完 —
關(guān)注清華-青島數(shù)據(jù)科學(xué)研究院官方微信公眾平臺“THU數(shù)據(jù)派”及姊妹號“數(shù)據(jù)派THU”獲取更多講座福利及優(yōu)質(zhì)內(nèi)容。