決策樹

決策樹是最經常使用的數據挖掘算法。

決策樹的構造

決策樹的一般流程:

  1. 收集數據:可以使用任何方法;
  2. 準備數據:樹構造算法只適用於標稱型數據,因此數值型數據必須離散化;
  3. 分析數據:可以使用任何方法,構造樹完成之後罵我們應該檢查圖形是否符合預期;
  4. 訓練算法:構造樹的數據結構;
  5. 測試算法:使用經驗樹計算錯誤率;
  6. 使用算法:此步驟可以適用於任何監督學習算法,而使用決策樹可以更好地理解數據的內在含義。

 信息增益

劃分數據集的大原則是:將無序的數據變得更加有序。組織雜亂無章數據的一種方法就是使用信息論度量信息,信息論是量化處理信息的分支科學。

再換分數劇集之前之後發生的變化成爲信息增益,獲得信息增益最高的特徵就是最好的選擇。

“熵”——描述爲信息的期望值

如果待分類的事務可能劃分在多個分類之中,則符號x_i的信息定義爲

l(x_i)=-\log_2p(x_i)

其中p(x_i)是選擇該分類的概率。

爲了計算熵,我們需要計算所有類別多有可能值包含的信息期望值,通過下面的公式得到:

H=-\sum_{i=1}^np(x_i)\log_2p(x_i)

計算給定數據集香農熵的代碼:

from math import log


def calc_shannon_entropy(data_set):
    num_entries = len(data_set)
    label_counts = {}
    for feat_vec in data_set:
        current_label = feat_vec[-1]
        if current_label not in label_counts.keys():
            label_counts[current_label] = 0
        label_counts[current_label] += 1
    shannon_entropy = 0.0
    for key in label_counts:
        prob = float(label_counts[key])/num_entries
        shannon_entropy -= prob * log(prob, 2)
    return shannon_entropy

構造一個簡單的數據集來計算香農熵:

def create_data_set():
    data_set = [[1, 1, 'yes'],
                [1, 1, 'yes'],
                [1, 0, 'no'],
                [0, 1, 'no'],
                [0, 1, 'no']]
    labels = ['no surfacing', 'flippers']
    return data_set, labels


if __name__ == '__main__':
    data_set, labels = create_data_set()
    shannon_entropy = calc_shannon_entropy(data_set)
    print("shannon entropy: %f" % shannon_entropy)

結果:

shannon entropy: 0.970951

熵越高,則混合的數據也越多。數據集中的分類增大時,則熵增大。

劃分數據集

def split_data_set(data_set, axis, value):
    """
    按照給定特徵劃分數據集
    :param data_set:
    :param axis:
    :param value:
    :return:
    """
    return_data_set = []
    for feat_vec in data_set:
        if feat_vec[axis] == value:
            reduced_feat_vec = feat_vec[:axis]
            reduced_feat_vec.extend(feat_vec[axis+1:])
            return_data_set.append(reduced_feat_vec)
    return return_data_set

一個按照人爲設定的特徵劃分的結果:

if __name__ == '__main__':
    data_set, labels = create_data_set()
    
    # 測試不同的數據劃分方式
    print("按axis=0, value=1 的劃分結果: ", split_data_set(data_set, 0, 1))
    print("按axis=0, value=0 的劃分結果: ", split_data_set(data_set, 0, 0))

那麼按照什麼樣的特徵進行劃分呢?

——選擇最大信息增益的特徵進行劃分

Gain = H_{base}-H_{new}

這裏設置原始香農熵base_entropy = 0, 選擇最好劃分特徵的代碼如下:

def choose_best_feature_to_split(data_set):
    """
    選擇最好的數據集劃分方式
    :param data_set:
    """
    num_features = len(data_set[0]) - 1
    base_entropy = calc_shannon_entropy(data_set)
    best_info_gain = 0.0
    best_feature = -1
    for i in range(num_features):
        feature_list = [example[i] for example in data_set]
        unique_values = set(feature_list)
        new_entropy = 0.0
        for value in unique_values:
            sub_data_set = split_data_set(data_set, i, value)
            prob = len(sub_data_set)/float(len(data_set))
            new_entropy += prob * calc_shannon_entropy(sub_data_set)
        info_gain = base_entropy - new_entropy
        if info_gain > best_info_gain:
            best_info_gain = info_gain
            best_feature = i
    return best_feature

結果:

data_set, labels = create_data_set()
best_feature = choose_best_feature_to_split(data_set)
    print("best feature: %d" % best_feature)

遞歸構建決策樹

遞歸結束的條件是:程序遍歷完所有劃分數據集的屬性,或者每個分支下的所有實例都具有相同的分類。如果所有實力具有相同的分類,則得到一個葉子節點或者終止塊。

如果數據集寂靜處理了所有屬性,但是類標籤依然不失唯一的,此時我們需要決定如何定義該葉子節點,這種情況下,通常採用多數表決的方法決定該葉子節點的分類。

def create_tree(data_set, labels):
    """
    創建樹的函數代碼
    :param data_set:
    :param 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:
        return majority_cnt(class_list)
    best_feature = choose_best_feature_to_split(data_set)
    best_feature_label = labels[best_feature]
    tree = {best_feature_label: {}}
    del labels[best_feature]
    feature_values = [data[best_feature] for data in data_set]
    unique_values = set(feature_values)
    for value in unique_values:
        sub_labels = labels[:]
        tree[best_feature_label][value] = create_tree(split_data_set(data_set, best_feature, value), sub_labels)
    return tree

得到決策樹的結果:

data_set, labels = create_data_set()
tree = create_tree(data_set, labels)
print("tree: ", tree)
tree:  {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

使用Matplotlib註解繪製樹形圖

Matplotlib 提供了一個註解工具annotations,它可以在數據圖形上添加文本註解。

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