Peter教你談情說AI | 09決策樹(下)—既能迴歸又能分類的模型

Hello Kitty到底是貓還是女孩?讓決策樹告訴我們真僞。

特徵選取

我們提取七個特徵,用來判斷一個形象,是人是貓。這七個特徵包括:有否蝴蝶結;是否穿衣服;是否高過5個蘋果;是否有鬍子;是否圓臉;是否有貓耳朵;是否兩腳走路。

用一個表格來表現這七個特徵則,如下圖所示(第一列爲 Label,第二至八列爲7個特徵,每個特徵只有兩個取值,Yes 或者 No):

Table-1

用 ID3 算法構造分類樹

本例中,我們選用最簡單的 ID3 算法,代入數據進行計算。

(1)根據信息熵的概念,我們先來計算 Entropy(S)。因爲總共只有兩個類別:人和貓,因此 n==2。

(2)然後我們再分別計算各個特徵的:

因爲無論哪個特徵,都只有兩個特徵值:Yes 或者 No,因此value(T)總共只有兩個取值。

下面以“Has a bow”爲例來示意其計算過程。

依次計算其他幾項,得出如下結果:

(3)進一步計算,得出 InfoGain(Has cat ears) 最大,因此“Has cat ears”是第一個分裂節點。

而從這一特徵對應的類別也可以看出,所有特徵值爲 No 的都一定是 Girl;特徵值爲 Yes,可能是 Girl 也可能是 Cat,那麼第一次分裂,我們得出如下結果:

現在“Has cat ears”已經成爲了分裂點,則下一步將其排除,用剩下的6個 Feature 繼續分裂成樹:

Table-2

Table-2 爲第二次分裂所使用的訓練數據,相對於 Table-1,“Has cat ears”列,和前7行對應“Has cat ears”爲 No 的數據都已經被移除,剩下部分用於第二次分裂。

如此反覆迭代,最後使得7個特徵都成爲分裂點。

需要注意的是,如果某個特徵被選爲當前輪的分裂點,但是它在現存數據中只有一個值,另一個值對應的記錄爲空,則這個時候針對不存在的特徵值,將它標記爲該特徵在所有訓練數據中所佔比例最大的類型。

對本例而言,當我們將“Wear Clothes”作爲分裂點時,會發現該特徵只剩下了一個選項——Yes(如下 Table-3 所示)。此時怎麼給“Wear Clothes”爲 No 的分支做標記呢?

Table-3

這時就要看在 Table-1 中,“Wear Clothes”爲 No 的記錄中是 Girl 多還是 Cat 多。一目瞭然,在 Table-1 中這兩種記錄數量爲 0:6,因此“Wear Clothes”爲 No 的分支直接標誌成 Cat。

根據上述方法,最終我們構建出瞭如下決策樹:

決策樹構建過程,如下代碼所示:

    DecisionTree induceTree(training_set, features) {
        If(training_set中所有的輸入項都被標記爲同一個label){
          return 一個標誌位該label的葉子節點;
        } else if(features爲空) {
          # 默認標記爲在所有training_set中所佔比例最大的label 
          return 一個標記爲默認label的葉子節點;  
        } else {
          選取一個feature,F;
          以F爲根節點創建一棵樹currentTree;
          從Features中刪除F;
          foreach(value V of F) {                                
              將training_set中feature F的取值爲V的元素全部提取出來,組成partition_v;
              branch_v= induceTree(partition_V, features);
              將branch_v添加爲根節點的子樹,根節點到branch_v的路徑爲F的V值;
          }
              returncurrentTree;
        }
    }

後剪枝優化決策樹

決策樹剪枝

剪枝是優化決策樹的常用手段。剪枝方法大致可以分爲兩類:

  1. 先剪枝(局部剪枝):在構造過程中,當某個節點滿足剪枝條件,則直接停止此分支的構造。
  2. 後剪枝(全局剪枝):先構造完成完整的決策樹,再通過某些條件遍歷樹進行剪枝。

後剪枝優化 Hello Kitty 樹

現在,決策樹已經構造完成,所以我們採用後剪枝法,對上面決策樹進行修剪。

如圖中顯示,最後兩個分裂點“Has round face”和“Has a bow”存在並無意義——想想也是啊,無論人貓,都有可能是圓臉,也都可以戴蝴蝶結啊。

以我們遍歷所有節點,將沒有區分作用的節點刪除。完成後,我們的決策樹變成了下面這樣:

代碼實現

下面的代碼就是用 numpy 和 sklearn 來實現例子中的訓練分類樹來判斷 Hello Kitty 種族所對應的程序。

    from sklearn import tree
    from sklearn.model_selection im
    port train_test_split
    import numpy as np

    #9個女孩和8只貓的數據,對應7個feature,yes取值爲1,no爲0
    features = np.array([
        [1, 1, 0, 0, 1, 0, 1],
        [1, 1, 1, 0, 0, 0, 1],
        [0, 1, 0, 0, 0, 0, 1],
        [1, 1, 0, 0, 1, 0, 1],
        [0, 1, 0, 0, 1, 0, 0],
        [0, 1, 0, 0, 1, 0, 1],
        [1, 1, 0, 0, 1, 0, 0],
        [0, 1, 0, 0, 1, 0, 1],
        [0, 1, 0, 1, 1, 1, 1],
        [1, 0, 1, 1, 1, 1, 0],
        [0, 0, 0, 1, 1, 1, 0],
        [1, 0, 1, 1, 1, 1, 0],
        [0, 0, 0, 1, 1, 1, 0],
        [1, 0, 0, 1, 1, 1, 0],
        [0, 0, 1, 0, 1, 1, 0],
        [1, 1, 1, 1, 1, 1, 0],
        [1, 0, 1, 1, 1, 1, 0]
    ])

    #1 表示是女孩,0表示是貓  
    labels = np.array([
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [0],
        [0],
        [0],
        [0],
        [0],
        [0],
        [0],
        [0],
    ])

    # 從數據集中取20%作爲測試集,其他作爲訓練集
    X_train, X_test, y_train, y_test = train_test_split(
        features,
        labels,
        test_size=0.2,
        random_state=0,
    )

    # 訓練分類樹模型
    clf = tree.DecisionTreeClassifier()
    clf.fit(X=X_train, y=y_train)

    # 測試
    print(clf.predict(X_test))
    # 對比測試結果和預期結果
    print(clf.score(X=X_test, y=y_test))

    # 預測HelloKitty
    HelloKitty = np.array([[1,1,1,1,1,1,1]])
    print(clf.predict(HelloKitty))

最後輸出爲:

[1 1 0 0]

0.75

[0]

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