決策樹與ID3算法

1.概念與目的

決策樹是一種基本的分類與迴歸方法.它可以認爲是if-then規則的集合,也可以認爲是定義在特徵空間與類空間上的條件概率分佈.主要優點是模型具有可讀性,分類速度快.
決策樹主要抓住三個步驟:特徵選擇、決策樹的生成和決策樹的修剪
CART決策樹也叫分類與迴歸決策樹,注意掌握生成時最優切分變量和切分點的算法生成的思想。
在這裏插入圖片描述

2.決策樹模型

分類決策樹模型是一種描述對實例進行分類的樹形結構。決策樹由節點(node)和有向邊(directed edge)組成。節點有兩種類型:內部節點(internal node)和葉節點。內部節點表示一個特徵或屬性,葉節點表示一個類。
用決策樹分類,從根節點開始,對實例的某個特徵進行測試,根據測試的結果,將實例分別到其子節點;這時每個子節點對於着該特徵的一個取值,如此遞歸直到葉節點,最後將實例分到葉節點的類中去。決策樹的路勁具有互斥且完備的性質

3.策略

決策樹學習本質上是從訓練數據集中歸納出一組分類規則.我們需要的是一個與訓練數據矛盾較小,同時具有很好的泛化能力的決策樹.決策樹學習的損失函數通常是正則化的極大似然函數,決策樹學習的策略是以損失函數爲目標函數的最小化。當損失函數確定後,學習問題就變爲在損失函數意義下選擇最優決策樹的問題。但是從所有的決策時中選取最優決策樹是NP完全問題,所以現實中通常採用啓發式方法,近似求解這一最優化問題,得到次最優的解。

決策樹學習
假定給定訓練數據集T=(x(1),y(1)),(x(2),y(2)),…,(x(m),y(m)),其中x(i)=(x1,x2,…,xn)T爲輸入實例(特徵向量),n爲特徵個數,y(i)∈1,2,…,k爲類標記,i=1,2,…,m,m爲樣本容量。學習的目標是根據給定的訓練數據集構建一個決策樹模型,使它能夠對實例進行正確的分類。

開始時,將所有訓練數據都放在根節點,然後選擇一個最優特徵,然後將數據集分割成子集,如果某個子集裏面的數據能夠被基本正確分類,則構建葉節點;如果某個子集不能被正確分類,則繼續選擇一個新的最優特徵,繼續分割數據,一直遞歸下去,直到所有的數據集被正確分類,或沒有合適的特徵爲止。

以上方法對未知的數據未必有好的分類能力,可能發生過擬合現象,需要對生成的決策樹進行剪枝,使得它有更好的泛化能力。
總結下來,學習算法包括 特徵選擇->決策樹生成->決策時剪枝的過程。生成只考慮局部最優,剪枝則考慮全局最優。

4.特徵選擇

原則:
如果利用一個特徵進行分類的結果與隨機分類的結果沒有很大差別,則稱這個特徵是沒有分類能力的.扔掉這樣的特徵對決策樹學習的精度影響不大.通常特徵選擇的準則是信息增益或信息增益比。

(1)信息熵:
熵是衡量隨機變量不確定性的度量.熵越大,隨機變量的不確定性就越大.信息熵是信息量的期望
在這裏插入圖片描述
條件熵表示在已知隨機變量X的條件下隨機變量Y的不確定性.
在這裏插入圖片描述
(2)信息增益
信息增益(information gain)表示得知特徵X的信息而使得類Y的信息不確定性減少。
特徵A對訓練數據集D的信息增益g(D,A),定義爲集合D的經驗熵H(D)與特徵A在給定條件下D的經驗條件熵H(D|A)之差,即
g(D,A)=H(D)−H(D|A)
一般地,熵H(X)與條件熵H(Y|X)之差稱爲互信息(mutual information)。
在給定訓練數據集D和特徵A,經驗熵H(D)表示對數據集D進行分類的不確定性。而經驗條件熵H(D|A)表示在特徵A給定的條件下對數據集D進行分類的不確定性,那麼它們的差就表示由於特徵A而使得對數據集D的分類的不確定性減少的程度。信息增益大的特徵具有更強的分類能力。
(3)信息增益算法
假設訓練數據集爲D,|D|表示樣本容量,即樣本個數。設有K個類Ck,k=1,2,…,K,|Ck|爲屬於類Ck的樣本個數,∑k=1K|Ck|=|D|。
設特徵A有n個不同的取值a1,a2,…,an,根據特徵A的取值將D劃分爲n個子集D1,D2,…,Dn,|Di|爲Di的樣本個數,∑i=1n|Dk|=|D|。記子集Di中屬於類Ck的樣本集合爲Dik,|Dik|爲Dik的樣本個數。

算法:
輸入:訓練數據集D和特徵A
輸出:特徵A對訓練數據集D的信息增益g(D,A)
1)計算數據集D的經驗熵H(D)
在這裏插入圖片描述
2)計算特徵A對數據集D的經驗條件熵H(D|A)
在這裏插入圖片描述
3)計算信息增益
g(D,A)=H(D)−H(D|A)

(4)信息增益比
以信息增益比作爲劃分訓練數據集的特徵,存在偏向於選擇取值較多的特徵的問題。使用信息增益比(information gain ratio)可以對這個問題進行校正。
特徵A對訓練數據集D的信息增益比gR(D,A)定義爲信息增益g(D,A)與訓練數據集D關於特徵A的值的熵HA(D)之比,即
在這裏插入圖片描述

5.決策樹的生成

(1)ID3算法:
核心是在決策樹各個結點上應用信息增益準則選擇信息增益最大且大於閾值的特徵,遞歸地構建決策樹.ID3相當於用極大似然法進行概率模型的選擇.由於算法只有樹的生成,所以容易產生過擬合.
(2)C4.5算法:
C4.5算法與ID3算法相似,改用信息增益比來選擇特徵.

6.決策樹的剪枝

(1)在學習時過多考慮如何提高對訓練數據的正確分類,從而構建出過於複雜的決策樹**,產生過擬合現象.解決方法是對已生成的決策樹進行簡化,稱爲剪枝.**
(2)設樹的葉結點個數爲|T|,每個葉結點有Nt個樣本點,其中k類樣本點有Ntk個,剪枝往往通過極小化決策樹整體的損失函數
在這裏插入圖片描述
來實現,其中經驗熵.剪枝通過加入a|T|項來考慮模型複雜度,實際上就是用正則化的極大似然估計進行模型選擇.
(3)剪枝算法:
剪去某一子結點,如果生成的新的整體樹的損失函數值小於原樹,則進行剪枝,直到不能繼續爲止.具體可以由動態規劃實現.

6.ID3算法代碼實現

ID3算法對比:C4.5決策樹算法,參考《數據挖掘十大算法之C4.5算法》;
區別:ID3算法是計算信息增益值,而C4.5算法採用的是信息增益比,對分裂屬性的目標函數做出了改進。

# -*- coding: utf-8 -*-
from math import log
from collections import Counter

class DecisionTree(object):
    def __init__(self, input_data, labels):
        pass

    def create_decision_tree(self, data_set, labels): # 輸出樹形結構
        class_list = [data[-1] for data in data_set]
        if class_list.count(class_list[0]) == len(class_list): # 如果剩下的數據集的類別都一樣
            return class_list[0]
        if len(data_set[0]) == 1:                              # 如果數據集沒有特徵,只剩下類別,選擇類別最多的輸出
            major_label = Counter(data_set).most_common(1)[0]
            return major_label

        feature_index = self.get_feature_with_biggest_gain(data_set, labels) # 獲取最大信息增益的特徵
        feature_name = labels[feature_index]
        del labels[feature_index]

        feature_set = set([ data[feature_index] for data in data_set ]) # 找到該特徵的所有可能取值
        decision_tree = {feature_name: {}}
        for i in feature_set: 
        # 遍歷該特徵的所有取值,將數據集分割成各個子集,然後遞歸對各個子集進行同樣的特徵選擇
            feature_data_list = [ data for data in data_set if data[feature_index] == i ] # 滿足
            new_data_list = []
            for j in feature_data_list: # 移除已經選擇的特徵,獲取子集
                new_data = j[:]
                del new_data[feature_index]
                new_data_list.append(new_data)
            #print(i, new_data_list)
            new_lables = labels[:]
            decision_tree[feature_name][i] = self.create_decision_tree(new_data_list, new_lables)

        return decision_tree

    def cal_data_set_entropy(self, data_set): # 計算數據集的經驗熵
        total_num = len(data_set)
        class_list = [data[-1] for data in data_set]
        class_dict = dict()
        for i in class_list:
            ck_num = class_dict.get(i, 0)
            class_dict[i] = ck_num + 1

        entropy = 0
        for k in class_dict:
            ck_rate = float(class_dict[k])/total_num
            entropy -= ck_rate * log(ck_rate, 2)
        return entropy

    def get_feature_with_biggest_gain(self, data_set, labels): #獲取最大信息增益的特徵
        feature_num = len(labels)
        data_entropy = self.cal_data_set_entropy(data_set)
        biggest_gain_index = None
        biggest_gain = 0
        for i in range(feature_num):
        # 遍歷所有特徵,找出最大的信息增益特徵
            condition_entroy = self.cal_feature_condition_entropy(data_set, i)
            gain = data_entropy - condition_entroy
            if gain > biggest_gain:
                biggest_gain_index = i
                biggest_gain = gain
        #print(labels[biggest_gain_index], biggest_gain)
        return biggest_gain_index

    def cal_feature_condition_entropy(self, data_set, index): # 計算某個特徵的條件熵
        total_num = len(data_set)
        feature_list = [data[index] for data in data_set]
        feature_dict = dict()
        for i in feature_list:
            feature_num = feature_dict.get(i, 0)
            feature_dict[i] = feature_num + 1

        condition_entropy = 0
        for k in feature_dict:
            feature_rate = float(feature_dict[k])/total_num
            feature_data_set = [data for data in data_set if data[index] == k]
            entropy = self.cal_data_set_entropy(feature_data_set)
            condition_entropy += feature_rate * entropy
        return condition_entropy

train_data = "*/input/3.DecisionTree/lenses.txt"
with open(train_data) as f:
    lenses = [line.strip().split('\t') for line in f.readlines()] # 特徵之間用tab鍵隔離開
    labels = ['age', 'prescript', 'astigmatic', 'tearRate']

#[['young', 'myope', 'no', 'reduced', 'no lenses'], 
# ['young', 'myope', 'no', 'normal',  'soft']
dTree = DecisionTree(lenses, labels)
print(dTree.create_decision_tree(lenses, labels))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章