機器學習之決策樹(數據分析師學習必備)——糖潮麗子的博客

現實生活中,我們會進行各種各樣的選擇。不論是挑選商品,還是挑選任何東西,都是通過以往經驗所得。如果我們把挑選東西背後的邏輯整理成一個結構圖,你會發現它實際上就是一個樹狀圖,就像公司人員結構組成那樣,這就是我們本篇博客要講解的內容——決策樹。

決策樹是一種機器學習的方法。決策樹的生成算法有ID3, C4.5和CART等。決策樹是一種樹形結構,其中每個內部節點表示一個屬性上的判斷,每個分支代表一個判斷結果的輸出,最後每個葉節點代表一種分類結果。
在這裏插入圖片描述

1、主題

本篇博客講述決策樹算法,以及通過算法實現分類與迴歸任務。
先來了解一下樹的概念:
樹:是由節點和邊兩種元素組成的結構。理解樹,就需要理解幾個關鍵詞:根節點、父節點、子節點和葉子節點。
父節點和子節點是相對的,說白了子節點由父節點根據某一規則分裂而來,然後子節點作爲新的父親節點繼續分裂,直至不能分裂爲止。而根節點是沒有父節點的節點,即初始分裂節點,葉子節點是沒有子節點的節點,如下圖所示:
在這裏插入圖片描述
決策樹利用如上圖所示的樹結構進行決策,每一個非葉子節點是一個判斷條件,每一個葉子節點是結論。從跟節點開始,經過多次判斷得出結論。

2、目標

  • 熟知決策樹算法的原理,訓練與預測方式。
  • 分類樹與迴歸樹的訓練準則及各自的度量標準。
  • 三種常用的決策樹算法。
  • 使用決策樹實現分類與迴歸任務。

3、信息熵

講解決策樹之前,我們需要知道信息熵的概念。

3.1 概念

信息熵,在1948年由香農提出。用來描述系統信息量的不確定度
不確定性越大,則信息熵越大,反之,信息熵越小。

例如,4只獵豹參與賽跑,每隻獵豹的能力都是旗鼓相當,平分秋色。我們很難確定哪隻獵豹會獲得勝利,因此,這種情況下,不確定性很大,信息熵就大。但是,假設讓1只獵豹與3只蝸牛進行賽跑,則獵豹取勝便是毋容置疑的,因此,這種情況下,不確定性很小,信息熵就小。

練習:

以下哪個選項的信息熵最大? (C
A 明天會下雨。
B 足球是圓的。
C 下一期雙色球的一等獎的中獎號碼是紅球:1,2,3,4,5,6,藍球:7。
D 下週二某支股票會上漲。

3.2 計算方式

假設隨機變量具有M個值,分別爲: V1,V2 ,… ,Vm 。並且各個值出現的概率如下:
在這裏插入圖片描述
則變量的信息期望值(信息熵)爲:
在這裏插入圖片描述
信息熵公式:
在這裏插入圖片描述
例如:
一個班級男生了60人,女生有40人。那麼男生的概率是0.6,女生的概率是0.4。
信息熵 H(X)= - (0.6log2(0.6) + 0.4log2(0.4)) 。

3.3 概率分佈與信息熵

對於信息熵,我們可以用概率分佈來衡量,對於隨機變量X,其分佈越均衡,則不確定性越多,信息熵越大。其分佈越不均衡,則不確定性越小,信息熵越小。

import numpy as np
import matplotlib.pyplot as plt

plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["font.size"] = 12

# 假設隨機變量X可以取兩個值,一個值的概率爲p,則另外一個值的概率爲1 - p。
p = np.linspace(0.01, 0.99, 100)
# 計算在不同概率分佈下的信息熵。
h = -p * np.log2(p) - (1 - p) * np.log2(1 - p)
plt.plot(p, h)
plt.xlabel("p1取值")
plt.ylabel("信息熵")
plt.title("概率-信息熵對比")
plt.show()

結果:
在這裏插入圖片描述
從以上圖中我們可以看出當p1取值越來越大時,信息熵就越大,分佈就越來越均衡,也就是不確定性越大。p1取值爲0.5時,信息熵最大,p1和p2概率都是0.5,這時候分佈均等,不確定性也是最大的。

如果我們把概率分佈轉換到數據集上。信息熵體現的就是數據的不純度,即樣本類別的均衡程度
樣本類別越均衡,不純度越高,信息熵越大。反之,樣本類別越不均衡,不純度越低,信息熵越小。

我們可以進行如下的表示:
信息熵 =》 概率(比例)均衡度 =》 不純度

練習:

不通過計算,以下哪個數據集的信息熵最大? (C
A 箱子中有9個紅球,1個白球。
B 班級中有30個男生,25個女生。
C飲料店成交30單,其中10單蘋果味,10單哈密瓜味,10單葡萄味。
D 路口經過55輛車,其中50輛本地車,5輛外地車。

4、決策樹訓練與預測

4.1 決策樹概念

決策樹 是一種樹形結構通過特徵的不同來將樣本數據劃分到不同的分支(子樹)中,最終,每個樣本一定會劃分到一個葉子節點中。 我們可以將每個特徵視爲一個問題(提問),特徵值的不同,就視爲樣本給出的不同答案,然後,我們就可以根據一系列問題(特徵),將樣本劃分到不同的葉子節點中。決策樹是一種非參數監督學習方法,可以用於分類與迴歸

樹形結構適合一對多的情形。
例如:家族族譜,公司組織機構等都是樹形結構。

4.2 訓練決策樹

例如,給定如下的數據集:
在這裏插入圖片描述
我們就可以將三個特徵作爲三個問題,依次來“詢問”數據集中的每個樣本,經過每個樣本依次“作答”之後,就可以將樣本劃分到不同的分支中,這樣,決策樹就訓練完成。其實,決策樹的訓練,就是根據訓練集去構建一顆決策樹。結果如下圖所示。
在這裏插入圖片描述

4.3 預測原理

當在訓練集上構建決策樹後,我們就可以對未知樣本進行預測。
預測的過程爲根據未知樣本的特徵,逐步進行分支選擇(回答問題),直到葉子節點爲止。
那麼,我們就可以使用該葉子節點中的已知樣本來預測該未知樣本。
可是,我們預測的依據是什麼呢?
我們可以想象,假設對與兩個人進行性格測試,兩個人回答一些相同的選擇題,如果兩個人的選項完全一致,則說明兩個人的性格存在很大的相似性。
同樣,決策樹是根據特徵值來劃分樣本的(這類似於回答問題)。
如果樣本經過層層劃分之後,分到了同一個葉子節點中,則表明這些樣本應該也是非常
相似的。

因此,我們就可以使用在同一個葉子節點中的已知樣本,去預測未知樣本的標籤了。

預測的方式爲:

  • 對於分類樹,使用葉子節點中,類別數量最多的類別,作爲未知樣本的類別。
  • 對於迴歸樹,使用葉子節點中,所有樣本的均值,作爲未知樣本的類別。

例如,樣本11預測的類別爲:能。

5、分類決策樹

5.1 訓練的疑問

從剛纔的介紹可知,決策樹可以看做由若干個節點構成,其中,每個節點包含一定數量的樣本(根節點包含所有樣本數據)。
決策樹的訓練過程就是根據特徵值來分割樣本數據。

然而,從剛纔訓練決策樹的方式上,我們需要解決如下的問題:

  • 我們是否可以先根據“擁有房產”或“婚姻情況”特徵進行劃分?當選擇特徵劃分樣本時,順序是否是任意的?
  • 對於連續變量類型的特徵,年收入爲什麼選擇以97.5來進行劃分,而不是其他值?
    在這裏插入圖片描述

5.2 信息增益

信息增益在決策樹算法中是用來選擇特徵的指標,信息增益越大,則這個特徵的選擇性越好。
信息增益(IG-Information gain)定義如下:
在這裏插入圖片描述
信息增益就是父節點的不純度減去所有子節點不純度(加權)。
我們要優先選擇信息增益大的節點當做父節點。

練習:

假設你是總經理助理,目前有10份文件,其中4個與M公司有關,6個與N公司有關。我們需要對文件 進行整理,目前X與Y兩個盒子,我們會選擇( A )。
A 4個與M公司相關的文件放入X,6個與N公司相關的文件放入Y。
B 3個與M公司相關的文件放入X,另外1個與6個與N公司相關的文件放入Y。
C 1個與M公司相關的文件放入X,另外3個與6個與N公司相關的文件放入Y。
D 所有文件放入X或Y中,另外一個盒子空閒。

就像我們整理文件一樣,在選擇特徵分裂樣本時,我們應該讓子節點的不純度儘可能的低,這樣就可以更快的完成訓練(更少的分割次數),同時,在預測未知樣本時,也會具有更高的準確度。

因此,在我們選擇特徵進行劃分時,特徵的順序不是任意的,而是應該選擇在分割樣本集後,能夠使得所有子節點不純度最低(加權)的特徵。由於父節點的不純度是不變的,因此,能夠讓所有子節點不純度最小的特徵,實際上也就是能夠所得信息增益最大的特徵。 而這,也正是訓練分類決策樹時,選擇特徵順序的依據。

5.3 訓練規則

訓練分類決策樹的具體規則如下:

  1. 將每一個特徵看成是一種分裂可能。特徵可以分爲離散型與連續性
  • 離散型特徵,每一個類別可以劃分爲一個子節點(多叉樹),或者屬於類別A與不屬於類別A(二叉樹)。
  • 對於連續性特徵,可以劃分爲大於等於A與小於A。
  1. 從根節點開始,選擇可獲得最大信息增益的特徵進行分裂(實現信息增益最大化)。
  2. 對子節點繼續選擇能夠獲得最大信息增益的特徵進行分裂,直到滿足如下條件之一,停止分裂。
  • 所有葉子節點中的樣本屬於同一個類別。
  • 樹達到指定的最大深度(max_depth),每次分裂視爲一層。
  • 葉子節點包含的樣本數量小於指定的最小分裂樣本數量(min_samples_split)。
  • 如果分裂後,葉子節點包含的樣本數量小於指定的葉子最小樣本數量 (min_samples_leaf)。

5.4 分類決策樹示例

以不純度衡量使用信息熵爲例,父節點的信息熵爲:
在這裏插入圖片描述
如果以特徵“擁有房產”作爲分裂特徵,則:
在這裏插入圖片描述
在這裏插入圖片描述

因此,特徵“擁有房產”的信息增益爲:
在這裏插入圖片描述
對於收入來說,爲連續型變量,我們這裏將收入的取值進行排序,然後選擇“否”與“是”的分界點(75與85之間,95與100之間),取平均值進行分割:
在這裏插入圖片描述
在這裏插入圖片描述
從上面的結果中可知,相比於收入=80來說,收入=97.5可以獲得更大的信息增益。
這也就是爲什麼我們一開始選擇年收入(信息增益大的)作爲父節點,作爲分裂條件。

6、不純度度量標準

不純度可以採用如下方式度量:

  • 信息熵(Entropy)
  • 基尼係數(Gini Index)
  • 錯誤率(classification error)

6.1 信息熵

在這裏插入圖片描述

  • m:節點中含有樣本的類別數量。
  • p(i | D):節點中,屬於類別的樣本佔節點中樣本總數的比例(概率)。

6.2 基尼係數

在這裏插入圖片描述

6.3 錯誤率

在這裏插入圖片描述

無論哪種度量標準,都有一個特性:
如果樣本以相同的比例分佈於不同的類別時,度量值最大,不純度最高。如果所有的樣本都屬於同一個類別,則度量值爲0,不純度最低。

# 定義函數,返回基尼係數。
def gini(p):
    return 1 - p ** 2 - (1 - p) ** 2

# 定義函數,返回信息熵。
def entropy(p):
    return -p * np.log2(p) - (1 - p) * np.log2(1 - p)

# 定義函數,返回錯誤率。
def error(p):
    return 1 - np.max([p, 1 - p], axis=0)

# 定義概率的取值範圍。
p = np.linspace(0.01, 0.99, 200)
# 計算信息熵。
en = entropy(p)
# 計算縮放的信息熵。
en2 = en * 0.5
# 計算錯誤率。
err = error(p)
# 計算基尼係數。
g = gini(p)
fig = plt.figure()
for i, lab, ls, c, in zip([en, en2, g, err], ["信息熵", "信息熵(縮放)", "基尼係數", "錯誤率"],
    ["-", ":", "--", "-."], ["r", "g", "b", "y"]):
    plt.plot(p, i, label=lab, linestyle=ls, lw=2, color=c)
    plt.legend(loc="right", bbox_to_anchor=(1.55, 0.8))
    plt.axhline(y=0.5, linewidth=1, color='k', linestyle="--")
    plt.axhline(y=1.0, linewidth=1, color='k', linestyle="--")
    plt.ylim([0, 1.1])
    plt.xlabel("概率1取值")
    plt.ylabel("純度係數")
plt.show()

結果:
在這裏插入圖片描述
可以看到信息熵、信息熵(縮放)、基尼係數、錯誤率他們都會隨着不純度的增大而增大,隨着不純度的減小而減小。

7、決策樹算法

決策樹主要包含以下三種算法:

  • ID3
  • C4.5
  • CART(Classification And Regression Tree)

7.1 ID3

ID3(Iterative Dichotomiser3-迭代二分法)算法是非常經典的決策樹算法,該算法描述如下:

  • 使用多叉樹結構
  • 使用信息熵作爲不純度度量標準,選擇信息增益最大的特徵分割數據

ID3算法簡單,訓練較快。但該算法具有一些侷限,如下:

  • 不支持連續特徵
  • 不支持缺失值
  • 僅支持分類,不支持迴歸
  • 在選擇特徵時,會傾向於選擇類別多的特徵

7.2 C4.5

C4.5算法是在ID3算法上改進而來,該算法描述如下:

  • 使用多叉樹結構
  • 僅支持分類,不支持迴歸

不過,C4.5在ID3算法上,進行了一些優化,包括:

  • 支持對缺失值的處理
  • 支持將連續值進行離散化處理
  • 使用信息熵作爲不純度度量標準,但選擇信息增益率(而不是信息增益)最大的特徵分裂節點。

信息增益率的定義方式爲:
在這裏插入圖片描述

  • IH(f) :根據特徵 f 的不同類別值比例(概率),計算得到的信息熵。

之所以從信息增益改爲信息增益率,是因爲在ID3算法中,傾向於選擇類別多的特徵,因此,經過這樣的調整,在C4.5中就可以得到緩解。因爲類別多的特徵在計算信息熵時,往往會比類別少的特徵信息熵 IH(f) 大。這樣,就可以在分母上進行一定的懲罰。

def entropy(p):
    return np.sum(-p * np.log2(p))

# 計算在不同類別數量時,信息熵的對比。每個元素代表一個類別所佔的比例。
a1 = np.array([0.4, 0.6])
a2 = np.array([0.3, 0.3, 0.2, 0.2])
a3 = np.array([0.1] * 10)
print(entropy(a1))
print(entropy(a2))
print(entropy(a3))

結果:
在這裏插入圖片描述
從結果中可以看出,類別比較多的話信息熵也會比較大。

7.3 CART

CART(Classification And Regression Tree),分類與迴歸樹。該算法描述如下:

  • 使用二叉樹結構
  • 支持連續值與缺失值處理
  • 既支持分類,也支持迴歸
    - 使用基尼係數作爲不純度度量標準,選擇基尼增益最大的特徵分裂節點(分類)
    - 使用MSE或MAE最小的特徵分類節點(迴歸)

8、迴歸決策樹

當使用迴歸決策樹時,與分類決策樹會有所不同。
迴歸任務的標籤( 值)是連續的,故之前以分類爲基礎的不純度度量標準(信息熵,基尼係數與錯誤率)都不適用於迴歸樹,因此,在迴歸樹中,自然也就沒有信息增益,信息增益率或基尼增益等概念了。可以說,分類決策樹選擇特徵的方式,完全不適用於迴歸決策樹。

對於迴歸決策樹,會使用葉子節點的均值來預測未知樣本。
同時,迴歸決策樹使用MSE或MAE作爲評估指標,用來選擇特徵。也就是說,迴歸決策樹在選擇特徵上,每次選擇能夠使得MSE或MAE最小的特徵,用來分裂節點。

9、程序(代碼)實現

在scikit-learn中,使用優化的CART算法來實現決策樹。

9.1 分類

scikit-learn中,提供DecisionTreeClassifier類,用來實現決策樹分類

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

X, y = load_iris(return_X_y=True)
# 爲了後續的可視化方便,這裏選擇兩個特徵。
X = X[:, :2]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,
random_state=0)
# criterion:不純度度量標準,默認爲gini。
# gini:基尼係數 entropy:信息熵
# splitter:選擇分裂節點的方式。默認爲best。
# best:在最好的位置分裂節點。 random:在隨機的位置分裂節點。
# max_depth:樹的最大深度,默認爲None(不限制深度)。
# min_samples_split:分裂節點的最小樣本數,默認爲2。
# min_samples_leaf:分裂節點後,葉子節點最少的樣本數量,默認爲1。
# max_features:分裂節點時,考慮的最大特徵數量,默認爲None(考慮所有特徵)。
# random_state:隨機種子。
tree = DecisionTreeClassifier()
tree.fit(X_train, y_train)
print(tree.score(X_train, y_train))
print(tree.score(X_test, y_test))

決策樹參數:
criterion:不純度度量標準,默認爲gini。
gini:基尼係數 entropy:信息熵
splitter:選擇分裂節點的方式。默認爲best。
best:在最好的位置分裂節點。 random:在隨機的位置分裂節點。
max_depth:樹的最大深度,默認爲None(不限制深度)。
min_samples_split:分裂節點的最小樣本數,默認爲2。
min_samples_leaf:分裂節點後,葉子節點最少的樣本數量,默認爲1。
max_features:分裂節點時,考慮的最大特徵數量,默認爲None(考慮所有特徵)。
random_state:隨機種子。

結果:
在這裏插入圖片描述
結果中,訓練集高於測試集,原因就在於過擬合。
我們發現,模型存在嚴重的過擬合傾向,原因在於,如果沒有指定樹的深度,則默認會訓練一顆完全生長的決策樹(不限深度),這會容易導致模型複雜化,從而過分依賴於訓練集數據的特性,造成過擬合。

我們可以從不同深度樹的決策邊界,來證實這一點。

from matplotlib.colors import ListedColormap
def plot_decision_boundary(model, X, y):
    color = ["r", "g", "b"]
    marker = ["o", "v", "x"]
    class_label = np.unique(y)
    cmap = ListedColormap(color[: len(class_label)])
    x1_min, x2_min = np.min(X, axis=0)
    x1_max, x2_max = np.max(X, axis=0)
    x1 = np.arange(x1_min - 1, x1_max + 1, 0.02)
    x2 = np.arange(x2_min - 1, x2_max + 1, 0.02)
    X1, X2 = np.meshgrid(x1, x2)
    Z = model.predict(np.c_[X1.ravel(), X2.ravel()])
    Z = Z.reshape(X1.shape)
    plt.contourf(X1, X2, Z, cmap=cmap, alpha=0.5)
    for i, class_ in enumerate(class_label):
        plt.scatter(x=X[y == class_, 0], y=X[y == class_, 1],c=cmap.colors[i], label=class_, marker=marker[i])
    plt.legend()
    
plt.figure(figsize=(15, 10))
for index, depth in enumerate([1, 4, 7, 12], start=1):
    plt.subplot(2, 2, index)
    plt.title(f"最大深度:{depth}")
    tree = DecisionTreeClassifier(random_state=0, max_depth=depth)
    tree.fit(X_train, y_train)
    plot_decision_boundary(tree, X_test, y_test)

結果:
在這裏插入圖片描述
最大深度爲1時,只能分成兩個類別,因爲只能建立一個二叉樹,沒有辦法變出更多的分類。
最大深度爲4的時候,三個類別,可以有4個問題,比深度爲1時要複雜。
當最大深度越來越大時,決策邊界越來越複雜,模型也就越複雜。

對於決策樹來說,最大深度對模型有着較重要的影響,如果最大深度很小,意味着僅進行少數的切分,容易欠擬合,但是,如果最大深度很大,則意味着可能進行較多次切分,容易過擬合。

# 定義列表,用來存儲在不同深度下,模型的分值。
train_score = []
test_score = []
for depth in range(1, 13):
    tree = DecisionTreeClassifier(random_state=0, max_depth=depth)
    tree.fit(X_train, y_train)
    train_score.append(tree.score(X_train, y_train))
    test_score.append(tree.score(X_test, y_test))
    
plt.plot(train_score, marker="o", c="red", label="訓練集")
plt.plot(test_score, marker="o", c="green", label="測試集")
plt.legend()

結果:
在這裏插入圖片描述
從運行結果中,我們可知,隨着最大深度的增加,訓練集的表現越來越好,但是測試集的表現,是先增加後減少,這說明,在樹深度較小時,模型是欠擬合的,因此,增加樹深度,能夠提升預測效果,但隨着深度的增加,模型越來越依賴於訓練集,這反而降低預測效果,造成過擬合。

9.2 迴歸

scikit-learn中,提供DecisionTreeRegressor類,用來實現決策樹迴歸。

from sklearn.datasets import load_boston
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split

X, y = load_boston(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,
random_state=0)

# 迴歸決策樹的參數,可以參考分類決策樹的參數。
tree = DecisionTreeRegressor(max_depth=3)
tree.fit(X_train, y_train)
print(tree.score(X_train, y_train))
print(tree.score(X_test, y_test))

結果:
在這裏插入圖片描述
在這裏插入圖片描述

10、總結

我們學習了以下內容:

  • 決策樹的三種算法
    分別是:ID3、C4.5、CART

  • 分類樹節點分裂準則。
    ①將每一個特徵看成是一種分裂可能。特徵可以分爲離散型與連續性。
    ②從根節點開始,選擇可獲得最大信息增益的特徵進行分裂(實現信息增益最大化)。
    ③對子節點繼續選擇能夠獲得最大信息增益的特徵進行分裂,直到滿足如下條件之一,停止分裂。

  • 迴歸樹節點分裂準則。
    對於迴歸決策樹,會使用葉子節點的均值來預測未知樣本。
    同時,迴歸決策樹使用MSE或MAE作爲評估指標,用來選擇特徵。也就是說,迴歸決策樹在選擇特徵上,每次選擇能夠使得MSE或MAE最小的特徵,用來分裂節點。

  • 深度對決策樹的影響。
    對於決策樹來說,最大深度對模型有着較重要的影響,如果最大深度很小,意味着僅進行少數的切分,容易欠擬合,但是,如果最大深度很大,則意味着可能進行較多次切分,容易過擬合。

在這裏插入圖片描述
顏值高的關注/點贊 鼓勵下唄!

學習鏈接:
https://www.cnblogs.com/yonghao/p/5061873.html
https://www.cnblogs.com/molieren/articles/10664954.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章