數據分析_算法_決策樹

概述

決策樹是數據挖掘經典算法,既可以做分類,又可以做迴歸。下面介紹決策樹的基本概念和相關術語,算法方面講解ID3、C4.5、CART算法,並闡述各自的特點及其使用場景,最後用典型案例“泰坦尼克生存”作爲實戰,過程中會介紹模型評價機制和相關方法。

基本概念

在這裏插入圖片描述
一個完整的決策樹會經歷:構造剪枝兩個過程。

構造

構造的過程就是選擇什麼屬性作爲節點的過程,那麼在構造過程中,會存在三種節點:根節點、節點、葉節點。
節點之間存在父子關係。比如根節點會有子節點,子節點會有子子節點,但是到了葉節點就停止了,葉節點不存在子節點。那麼在構造過程中,你要解決三個重要的問題:

  1. 選擇哪個屬性作爲根節點 。
  2. 選擇哪些屬性作爲子節點 。
  3. 什麼時候停止並得到目標狀態,即葉節點。

實際上最重要的是選擇根節點的方法,如果能有一種“方法“確定根節點,那麼這個方法就可以應用到子節點。後面主要講的就是這個“方法”也就是上面提到的三個算法。

剪枝

一個決策樹構造出來並沒有結束,還需要對其進行“修剪”,目的是防止過擬合,是使得模型擁有較好的泛化能力。

過擬合:模型的訓練結果過好,以至於在實際應用的過程中,會存在“死板”的情況,導致分類錯誤,就像第三幅圖一樣,第一幅圖是與之相反的欠擬合。跳出模型想一下,類別之間從大方向上是存在某種可以量化的區別的,那麼他們之間的“區別=“區分曲線”是不會那麼刁鑽的,應該是相對比較“通用”或者說是相對“光滑圓潤”
在這裏插入圖片描述
一般來說,剪枝可以分爲“預剪枝”(Pre-Pruning)和“後剪枝”(Post-Pruning)。
預剪枝:在決策樹構造時就進行剪枝。方法是在構造的過程中對節點進行評估,如果對某個節點進行劃分,在驗證集中不能帶來準確性的提升,那麼對這個節點進行劃分就沒有意義,這時就會把當前節點作爲葉節點,不對其進行劃分。應用比較少,一般在建模之前,我們會主觀確定需要擬合的變量,把意義不大的或者數據質量不好的排除。
後剪枝:在生成決策樹之後再進行剪枝,通常會從決策樹的葉節點開始,逐層向上對每個節點進行評估。如果剪掉這個節點子樹,與保留該節點子樹在分類準確性上差別不大,或者剪掉該節點子樹,能在驗證集中帶來準確性的提升,那麼就可以把該節點子樹進行剪枝。方法是:用這個節點子樹的葉子節點來替代該節點,類標記爲這個節點子樹中最頻繁的那個類。也就是把頻率最高的情況當作是這個分類的唯一情況

算法

C4.5是ID3的改進,應用很廣泛,CART可以用於分離和迴歸,前兩者只能應用於分類。

相關概念

:它表示了信息的不確定度
計算信息熵的數學公式:
在這裏插入圖片描述
p(i|t) 代表了節點 t 爲分類 i 的概率,其中 log2 爲取以 2 爲底的對數。這裏我們不是來介紹公式的,而是說存在一種度量,它能幫我們反映出來這個信息的不確定度。當不確定性越大時,它所包含的信息量也就越大,信息熵也就越高。不理解沒關係,後面會帶入數據。

ID3

ID3 算法計算的是信息增益,信息增益指的就是劃分可以帶來純度的提高,信息熵的下降。它的計算公式,是父親節點的信息熵減去所有子節點的信息熵。在計算的過程中,我們會計算每個子節點的歸一化信息熵,即按照每個子節點在父節點中出現的概率,來計算這些子節點的信息熵。所以信息增益的公式可以表示爲:在這裏插入圖片描述
公式中 D 是父親節點,Di 是子節點,Gain(D,a) 中的 a 作爲 D 節點的屬性選擇。在這裏插入圖片描述比如針對圖上這個例子,D 作爲節點的信息增益爲:在這裏插入圖片描述
假如我們的訓練集數據如下:
在這裏插入圖片描述
我們基於 ID3 的算法規則,完整地計算下我們的訓練集,訓練集中一共有 7 條數據,3 個打籃球,4 個不打籃球,所以根節點的信息熵是:
在這裏插入圖片描述
如果你將天氣作爲屬性的劃分,會有三個葉子節點 D1、D2 和 D3,分別對應的是晴天、陰天和小雨。我們用 + 代表去打籃球,- 代表不去打籃球。那麼第一條記錄,晴天不去打籃球,可以記爲 1-,於是我們可以用下面的方式來記錄 D1,D2,D3:
D1(天氣 = 晴天)={1-,2-,6+}
D2(天氣 = 陰天)={3+,7-}
D3(天氣 = 小雨)={4+,5-}
我們先分別計算三個葉子節點的信息熵:
在這裏插入圖片描述
那麼作爲子節點的歸一化信息熵 = 3/7 * 0.918 + 2/7 *1.0 + 2/7 * 1.0=0.965。
所以天氣作爲屬性節點的信息增益爲,Gain(D , 天氣)=0.985-0.965=0.020。
同理我們可以計算出其他屬性作爲根節點的信息增益,它們分別爲 :
Gain(D , 溫度)=0.128
Gain(D , 溼度)=0.020
Gain(D , 颳風)=0.020
我們能看出來溫度作爲屬性的信息增益最大。因爲 ID3 就是要將信息增益最大的節點作爲父節點,這樣可以得到純度高的決策樹,所以我們將溫度作爲根節點。其決策樹狀圖分裂爲下圖所示:
在這裏插入圖片描述
然後我們要將上圖中第一個葉節點,也就是 D1={1-,2-,3+,4+}進一步進行分裂,往下劃分,計算其不同屬性(天氣、溼度、颳風)作爲節點的信息增益,可以得到:
Gain(D , 溼度)=1
Gain(D , 天氣)=1
Gain(D , 颳風)=0.3115
我們能看到溼度,或者天氣爲 D1 的節點都可以得到最大的信息增益,這裏我們選取溼度作爲節點的屬性劃分。同理,我們可以按照上面的計算步驟得到完整的決策樹,結果如下:
在這裏插入圖片描述
於是我們通過 ID3 算法得到了一棵決策樹。ID3 的算法規則相對簡單,可解釋性強。同樣也存在缺陷,比如我們會發現 ID3 算法傾向於選擇取值比較多的屬性。這樣,如果我們把“編號”作爲一個屬性(一般情況下不會這麼做,這裏只是舉個例子),那麼“編號”將會被選爲最優屬性 。但實際上“編號”是無關屬性的,它對“打籃球”的分類並沒有太大作用。
所以 ID3 有一個缺陷就是,有些屬性可能對分類任務沒有太大作用,但是他們仍然可能會被選爲最優屬性。這種缺陷不是每次都會發生,只是存在一定的概率。在大部分情況下,ID3 都能生成不錯的決策樹分類。針對可能發生的缺陷,後人提出了新的算法進行改進。

C4.5

C4.5 在ID3的基礎上進行了改進,避免了上述的情況。

  • 採用信息增益率
    因爲 ID3 在計算的時候,傾向於選擇取值多的屬性。爲了避免這個問題,C4.5 採用信息增益率的方式來選擇屬性。信息增益率 = 信息增益 / 屬性熵,具體的計算公式這裏省略。當屬性有很多值的時候,相當於被劃分成了許多份,雖然信息增益變大了,但是對於 C4.5 來說,屬性熵也會變大,所以整體的信息增益率並不大。
  • 採用悲觀剪枝
    ID3 構造決策樹的時候,容易產生過擬合的情況。在 C4.5 中,會在決策樹構造之後採用悲觀剪枝(PEP),這樣可以提升決策樹的泛化能力。悲觀剪枝是後剪枝技術中的一種,通過遞歸估算每個內部節點的分類錯誤率,比較剪枝前後這個節點的分類錯誤率來決定是否對其進行剪枝。這種剪枝方法不再需要一個單獨的測試數據集。
  • ※離散化處理連續屬性
    C4.5 可以處理連續屬性的情況,對連續的屬性進行離散化的處理。比如打籃球存在的“溼度”屬性,不按照“高、中”劃分,而是按照溼度值進行計算,那麼溼度取什麼值都有可能。該怎麼選擇這個閾值呢,C4.5 選擇具有最高信息增益的劃分所對應的閾值
  • 處理缺失值
    針對數據集不完整的情況,C4.5 也可以進行處理。 假如數據集如下:在這裏插入圖片描述
    我們不考慮缺失的數值,可以得到溫度 D={2-,3+,4+,5-,6+,7-}。溫度 = 高:D1={2-,3+,4+} ;溫度 = 中:D2={6+,7-};溫度 = 低:D3={5-} 。這裏 + 號代表打籃球,- 號代表不打籃球。比如 ID=2 時,決策是不打籃球,我們可以記錄爲 2-。
    Gain(D′, 溫度)=Ent(D′)-0.792=1.0-0.792=0.208
    屬性熵 =1.459, 信息增益率 Gain_ratio(D′, 溫度)=0.208/1.459=0.1426。
    D′的樣本個數爲 6,而 D 的樣本個數爲 7,所以所佔權重比例爲 6/7,所以:
    Gain_ratio(D, 溫度)=6/7*0.1426=0.122

前面我們講了兩種決策樹分類算法 ID3 和 C4.5,瞭解了它們的數學原理。你可能會問,公式這麼多,在實際使用中該怎麼辦呢?實際上,我們可以使用一些數據挖掘工具使用它們,比如 Python 的 sklearn,或者是 Weka(一個免費的數據挖掘工作平臺),它們已經集成了這兩種算法。

CART

ID3 是基於信息增益做判斷,C4.5 在 ID3 的基礎上做了改進,提出了信息增益率的概念。實際上 CART 分類樹與 C4.5 算法類似,只是屬性選擇的指標採用的是基尼係數。ID3 和 C4.5 算法可以生成二叉樹或多叉樹,而 CART 只支持二叉樹。同時 CART 決策樹比較特殊,既可以作分類樹,又可以作迴歸樹
在經濟學中,基尼係數是用來衡量一個國家收入差距的常用指標。當基尼係數大於 0.4 的時候,說明財富差異懸殊。基尼係數在 0.2-0.4 之間說明分配合理,財富差距不大。
基尼係數本身反應了樣本的不確定度。當基尼係數越小的時候,說明樣本之間的差異性小,不確定程度低。分類的過程本身是一個不確定度降低的過程,即純度的提升過程。所以 CART 算法在構造分類樹的時候,會選擇基尼係數最小的屬性作爲屬性的劃分。
假設 t 爲節點,那麼該節點的 GINI 係數的計算公式爲:
在這裏插入圖片描述
這裏 p(Ck|t) 表示節點 t 屬於類別 Ck 的概率,節點 t 的基尼係數爲 1 減去各類別 Ck 概率平方和。
通過下面這個例子,我們計算一下兩個集合的基尼係數分別爲多少:
集合 1:6 個都去打籃球;
集合 2:3 個去打籃球,3 個不去打籃球。
針對集合 1,所有人都去打籃球,所以 p(Ck|t)=1,因此 GINI(t)=1-1=0。
針對集合 2,有一半人去打籃球,而另一半不去打籃球,所以p(C1|t)=0.5,p(C2|t)=0.5,GINI(t)=1-(0.50.5+0.50.5)=0.5。
通過兩個基尼係數你可以看出,集合 1 的基尼係數最小,也證明樣本最穩定,而集合 2 的樣本不穩定性更大。

CART 分類樹

# encoding=utf-8
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score

import numpy as np
# 準備數據集
iris=load_iris()
# 獲取特徵集和分類標識
features = iris.data
labels = iris.target
# 隨機抽取33%的數據作爲測試集,其餘爲訓練集
train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33, random_state=0)
# 創建CART分類樹
clf = DecisionTreeClassifier(criterion='gini')
# 擬合構造CART分類樹
clf = clf.fit(train_features, train_labels)
# 用CART分類樹做預測
test_predict = clf.predict(test_features)
# 預測結果與測試集結果作比對
score = accuracy_score(test_labels, test_predict)
print("CART分類樹準確率 %.4lf" % score)
# 使用K折交叉驗證  統計決策樹準確率
print(u'cross_val_score準確率爲 %.4lf' % np.mean(cross_val_score(clf, features, labels, cv=10)))
  • 創建 CART 分類樹,可以直接使用 DecisionTreeClassifier 這個類。創建這個類的時候,默認情況下 criterion 這個參數等於 gini,也就是按照基尼係數來選擇屬性劃分,即默認採用的是 CART 分類樹。
  • train_test_split 可以幫助我們把數據集抽取一部分作爲測試集,這樣我們就可以得到訓練集和測試集。

CART 迴歸樹

CART 迴歸樹劃分數據集的過程和分類樹的過程是一樣的,只是迴歸樹得到的預測結果是連續值,而且評判“不純度”的指標不同。在 CART 分類樹中採用的是基尼係數作爲標準,在 CART 迴歸樹中要根據樣本的混亂程度,也就是樣本的離散程度來評價“不純度”。
我們假設 x 爲樣本的個體,均值爲 u。爲了統計樣本的離散程度,我們可以取差值的絕對值,或者方差
其中差值的絕對值爲樣本值減去樣本均值的絕對值:在這裏插入圖片描述
方差爲每個樣本值減去樣本均值的平方和除以樣本個數:在這裏插入圖片描述所以這兩種節點劃分的標準,分別對應着兩種目標函數最優化的標準,即用最小絕對偏差(LAD),或者使用最小二乘偏差(LSD)。這兩種方式都可以讓我們找到節點劃分的方法,通常使用最小二乘偏差的情況更常見一些。

這裏我們使用到 sklearn 自帶的波士頓房價數據集,該數據集給出了影響房價的一些指標,比如犯罪率,房產稅等,最後給出了房價。


# encoding=utf-8
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_error
from sklearn.tree import DecisionTreeRegressor
# 準備數據集
boston=load_boston()
# 探索數據
print(boston.feature_names)
# 獲取特徵集和房價
features = boston.data
prices = boston.target
# 隨機抽取33%的數據作爲測試集,其餘爲訓練集
train_features, test_features, train_price, test_price = train_test_split(features, prices, test_size=0.33)
# 創建CART迴歸樹
dtr=DecisionTreeRegressor()
# 擬合構造CART迴歸樹
dtr.fit(train_features, train_price)
# 預測測試集中的房價
predict_price = dtr.predict(test_features)
# 測試集的結果評價
print('迴歸樹二乘偏差均值:', mean_squared_error(test_price, predict_price))
print('迴歸樹絕對值偏差均值:', mean_absolute_error(test_price, predict_price)) 
  • 使用 dtr=DecisionTreeRegressor() 初始化一棵 CART 迴歸樹
  • 我們能看到 CART 迴歸樹的使用和分類樹類似,只是最後求得的預測值是個連續值。
  • 不能用K折交叉檢驗,因爲那是檢查分類樹的正確率的,這是迴歸。

CART 決策樹的剪枝

CART 決策樹的剪枝主要採用的是 CCP 方法,它是一種後剪枝的方法,英文全稱叫做 cost-complexity prune,中文叫做代價複雜度。這種剪枝方式用到一個指標叫做節點的表面誤差率增益值,以此作爲剪枝前後誤差的定義。用公式表示則是:
在這裏插入圖片描述
其中 Tt 代表以 t 爲根節點的子樹,C(Tt) 表示節點 t 的子樹沒被裁剪時子樹 Tt 的誤差,C(t) 表示節點 t 的子樹被剪枝後節點 t 的誤差,|Tt|代子樹 Tt 的葉子數,剪枝後,T 的葉子數減少了|Tt|-1。
所以節點的表面誤差率增益值等於節點 t 的子樹被剪枝後的誤差變化除以剪掉的葉子數量。因爲我們希望剪枝前後誤差最小,所以我們要尋找的就是最小α值對應的節點,把它剪掉。這時候生成了第一個子樹。重複上面的過程,繼續剪枝,直到最後只剩下根節點,即爲最後一個子樹。

泰坦尼克生存預測

import pandas as pd
import numpy as np
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
import graphviz

train_data = pd.read_csv('./train.csv')
test_data = pd.read_csv('./test.csv')
#train_data.info()
#train_data.describe()
#train_data.describe(include=['O'])
#train_data.tail()
#train_data.head()
# 數據清洗
train_data['Age'].fillna(train_data['Age'].mean(),inplace = True)
test_data['Age'].fillna(test_data['Age'].mean(),inplace = True)
train_data['Fare'].fillna(train_data['Fare'].mean(),inplace = True)
test_data['Fare'].fillna(test_data['Fare'].mean(),inplace = True)
#print(train_data['Embarked'].value_counts())
train_data['Embarked'].fillna('S',inplace = True)
test_data['Embarked'].fillna('S',inplace = True)
# 特徵選擇
features = ['Pclass','Sex','Age','SibSp','Parch','Fare','Embarked']
train_features = train_data[features]
train_labels = train_data['Survived']
test_features = test_data[features]
dvec=DictVectorizer(sparse=False)
train_features=dvec.fit_transform(train_features.to_dict(orient='record'))
#print(dvec.feature_names_)

# 構造 ID3 決策樹
clf = DecisionTreeClassifier(criterion='entropy')#ID3
#決策樹訓練
clf.fit(train_features, train_labels)

test_features=dvec.transform(test_features.to_dict(orient='record'))
# 決策樹預測
pred_lables = clf.predict(test_features)

# 得到決策樹準確率,因爲測試集沒有結果,只能用訓練集
acc_decision_tree = round(clf.score(train_features,train_labels),6)
print(u'score 準確率爲 %.4lf' %acc_decision_tree)


# 使用K折交叉驗證 統計決策樹準確率
print(u'cross_val_score準確率爲 %.4lf' % np.mean(cross_val_score(clf, train_features, train_labels, cv=10)))

dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.view()

生成的決策樹如下:
在這裏插入圖片描述
需要用到graphviz包,通過在anaconda prompt界面輸入 conda install python-graphviz 可以直接安裝graphviz。

  • clf = DecisionTreeClassifier(criterion=‘entropy’);entropy: 基於信息熵,也就是 ID3 算法,實際結果與 C4.5 相差不大;gini:默認參數,基於基尼係數。CART 算法是基於基尼係數做屬性劃分的,所以 criterion=gini 時,實際上執行的是 CART 算法。
  • 創建分類樹的參數:
DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=None,
            max_features=None, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, presort=False, random_state=None,
            splitter='best')

這些參數代表的含義:
在這裏插入圖片描述

生存預測的關鍵流程在這裏插入圖片描述

總結

  1. ID3 算法,基於信息增益做判斷。
    優點:算法簡單,通俗易懂
    缺陷:無法處理缺失值;只能處理離散值,無法處理連續值;用信息增益作爲劃分規則,存在偏向於選擇取值較多的特徵。因爲特徵取值越多,說明劃分的越細,不確定性越低,信息增益則越高;容易出現過擬合
  2. C4.5 算法,基於信息增益率做判斷。
    優點:能夠處理缺省值 ;能對連續值做離散處理;使用信息增益比,能夠避免偏向於選擇取值較多的特徵。因爲信息增益比=信息增益/屬性 。屬性熵是根據屬性的取值來計算的,一相除就會抵消掉;在構造樹的過程中,會剪枝,減少過擬合。
    缺點:構造決策樹,需要對數據進行多次掃描和排序,效率低
  3. CART 算法,分類樹是基於基尼係數做判斷。迴歸樹是基於偏差做判斷。
  4. 特徵選擇是分類模型好壞的關鍵。選擇什麼樣的特徵,以及對應的特徵值矩陣,決定了分類模型的好壞。通常情況下,特徵值不都是數值類型,可以使用 DictVectorizer 類進行轉化。
  5. 模型準確率需要考慮是否有測試集的實際結果可以做對比,當測試集沒有真實結果可以對比時,需要使用 K 折交叉驗證 cross_val_score;
  6. Graphviz 可視化工具可以很方便地將決策模型呈現出來,幫助你更好理解決策樹的構建。
    在這裏插入圖片描述在這裏插入圖片描述
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章