1. 程式人生 > >機器學習之二:決策樹

機器學習之二:決策樹

本文為作者學習K近鄰演算法後的整理筆記,僅供學習使用!

決策樹

1、概述 

  決策樹(Decision Tree)實在已知各種情況發生概率的基礎上,通過構成決策樹來求取淨現值的期望值大於等於0的概率,評價專案風險,判斷其可行性的決策分析方法,是直觀運用概率分析的一種圖解法。

2、基本原理

(1)工作原理:

     a、獲取原始資料集

     b、基於最好的屬性值劃分資料集

     c、資料將向下傳遞到樹分支的下一個節點,再這個節點上,可以再次對資料進行劃分

(2)遞迴結束的條件:

     a、程式遍歷完所有劃分資料集的屬性

     b、每個分支下的所有實力都具有相同的分類

3、優缺點

(1)優點

    計算複雜度不高,輸出結果易於理解,對中間值的缺失不敏感,可以處理不相關特徵資料

(2)缺點

    可能會產生過度匹配問題(過擬合)

  適用資料型別:數值型和標稱型

4、一般流程

(1)收集資料:可以使用任何方法

(2)準備資料:樹構造演算法只適用於標稱型資料,因此數值型資料必須離散化(資料預處理)

(3)分析資料:可以使用任何方法,構造樹完成之後,檢查圖形是否符合預期

(4)訓練演算法:構造樹的資料結構

(5)測試演算法:使用經驗樹計算錯誤率

(6)使用演算法:此步驟可以使用於任何監督學習演算法

5、構建決策樹:ID3是演算法

(1)簡介

    a、對於例項,計算各個例項的資訊增益

    b、將資訊增益最大的屬性作為根節點,根節點的各個取值作為子集進行分類

    c、對於子集下, 若只含有正例或反例,直接得到判決;否則遞迴呼叫演算法,再次尋找子節點

(2)公式以及名詞解釋

    a、公式

                                                                   

    b、名詞解釋

      夏農熵:表示資料集的不確定性

      條件熵:在某個條件下,資料集的不確定性

      資訊增益:香濃熵 - 條件熵,在某一條件下,資訊不確定性減少的程度

(3)缺點:

    ID3採用的資訊增益度量存在一個缺點:它一般會選擇屬性值較多的Feature。資訊增益反映的是給定一個條件以後不確定減少的程度,必然是分得越細的資料集的確定性越高,也就是條件熵越小,資訊增益越大。

    當資料集中存在自增列(ID)時,採用ID3演算法會將ID列作為根節點。

(4)程式碼示例

    a、建立資料集

# 建立資料集
def create_dataset():
    dataset = [[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,0,'no']]
    label = ['no surfacing', 'flippers']
    return dataset, label

    b、計算香濃熵

# 獲取夏農熵
def calc_shannon_ent(dataset):
    label_count = len(dataset)
    entries_count = {}
    
    for entry in dataset:
        current_label = entry[-1]
        if current_label not in entries_count:
            entries_count[current_label] = 0
        entries_count[current_label] += 1
    
    shannon_ent = 0.0
    for key in entries_count:
        probability = float(entries_count[key]) / label_count # 求概率
        shannon_ent -= probability * log(probability, 2)
    return shannon_ent

    c、選擇最優的特徵進行拆分資料集

# 拆分資料集
def split_dataset(dataset, axis, value):
    new_dataset = []
    for data in dataset:
        if data[axis] == value:
            reduced_data = data[:axis]
            reduced_data.extend(data[axis+1 : ])
            new_dataset.append(reduced_data)
    return new_dataset

# 選擇最優的特徵進行拆分資料集
def choose_best_feature_to_split(dataset):
    num_features = len(dataset[0]) - 1  # 特徵數
    base_entropy = calc_shannon_ent(dataset) # 計算夏農熵
    best_info_gain = 0.0
    best_feature = -1 # 最優特徵
    for i in range(num_features):
        feature_list = [example[i] for example in dataset]
        unique_vals = set(feature_list)
        new_entropy = 0.0
        for value in unique_vals:
            sub_dataset = split_dataset(dataset, i, value)
            prob = len(sub_dataset) / float(len(dataset)) # 概率
            new_entropy += prob * calc_shannon_ent(sub_dataset) # 拆分後夏農熵
        info_gain = base_entropy - new_entropy
        if(info_gain > best_info_gain):
            best_info_gain = info_gain
            best_feature = i
    return best_feature

    d、構建決策樹

def majority_cnt(class_list):
    class_count = {}
    for vote in class_list:
        if vote not in class_count.keys():
            class_count[vote] = 0
            class_count[vote] += 1
        sorted_class_count = sorted( class_count.iteritem(), key=operator.itemgetter(1), reversed = True)
        return sorted_class_count[0][0]
    
def create_tree(dataset, labels):
    class_list = [example[-1] for example in dataset]
    if(class_list.count(class_list[0]) == len(class_list)):
        return class_list[0]
    if len(dataset[0]) == 1:
        return majority_cnt(class_list)
    best_feature = choose_best_feature_to_split(dataset)
    best_feature_label = labels[best_feature]
    my_tree = {best_feature_label:{}}
    del(labels[best_feature])
    feature_values = [example[best_feature] for example in dataset]
    unique_values = set(feature_values)
    for value in unique_values:
        sub_labels = labels[:]
        my_tree[best_feature_label][value] = create_tree(split_dataset(dataset, best_feature, value), sub_labels)
    return my_tree

    e、使用構建好的決策樹

# 使用
def my_classify(input_tree, featLabels, textvec):
    first_key = list(input_tree.keys())[0]
    second_dict = input_tree[first_key]
    feat_index = featLabels.index(first_key)
    for key in second_dict.keys():
        if textvec[feat_index] == key:
            if type(second_dict[key]).__name__ == "dict":
                classLabel = my_classify(second_dict[key], featLabels, textvec)
            else:
                classLabel = second_dict[key]
    return classLabel

    f、儲存

# 儲存
def store_tree(input_tree, file_name):
    import pickle
    fw = open(file_name, 'wb')
    pickle.dump(input_tree,fw)
    fw.close()

def grab_tree(file_name):
    import pickle
    fr = open(file_name, 'rb')
    return pickle.load(fr)

    g、呼叫

my_data, labels = create_dataset()
my_tree = create_tree(my_data, labels.copy())
store_tree(my_tree, "DecisionTree.txt")
my_load_tree = grab_tree("DecisionTree.txt")
predict_label1 = my_classify(my_load_tree, labels, [1,0])
predict_label2 = my_classify(my_load_tree, labels, [1,1])

print(predict_label1, predict_label2)

6、構建決策樹:C4.5

(1)  C4.5是對ID3演算法的改進,相對於ID3演算法主要有以下幾個方面的改進:

    (a)用資訊增益比來選擇屬性

    (b)在決策樹的構造過程中

    (c)對非離散資料也能處理

    (d)能夠對不完整資料進行處理

(2)公式

7、構建決策樹:CART

(1)CART演算法是通過GINI係數選擇最優特徵,同時決定該特徵的最優二值切分點

(2)公式

                                                                  

8、剪枝策略

(1)預剪枝

    邊建立決策樹邊進行剪枝的操作(更實用)。通過限制決策樹深度、葉子節點個數、葉子節點樣本樹,資訊增益量等進行預剪枝操作。

(2)後剪枝

    當建立完決策樹之後來進行剪枝操作。通過一定的衡量標準(葉子節點越多,損失越大):