決策樹是機器學習的常見算法,分為分類樹和回歸樹。當對一個樣本的分類進行預測時使用分類樹,當對樣本的某一個值進行預測時使用回歸樹。本文是有關決策樹的第一部分,主要介紹分類樹的幾種構建方法,以及如何使用分類樹測試分類。
目錄如下:
1、分類樹的基本概念
2、采用數據集說明
3、划分數據集的幾種方式
4、構造分類樹
5、使用分類樹測試分類
6、寫在后面的話
一 分類樹的基本概念
分類樹(classification tree)簡單地說,就是根據訓練數據集構造一個類似樹形的分類決策模型,然后用這個模型來輔助決策。
例如下圖是一個簡單的是否舉行某個活動的決策樹(分類樹):
我們可以通過上面的決策樹進行預測,當天氣晴朗,交通暢通時,我們預測該活動很可能要舉辦;當天下小雨交通擁擠時,我們預測活動很可能被取消。
這只是一個簡單的小例子,真實中的決策樹方法包括以下幾個步驟:
(1) 收集數據:可以使用任何方法。
(2)准備數據:樹構造算法只適用於標稱型數據,因此數值型數據必須離散化。
(3)選取划分算法:根據數據的特點,選取合適的划分算法
(4)構造決策樹:使用選取的划分算法構造樹形的決策模型
(5)測試算法:使用經驗樹計算錯誤率
(6)使用算法:使用決策樹模型預測決策
二 采用數據集說明
UCI數據集 是機器學習不錯的數據集網站,本文選取其中的 Balloons 數據集,將其內容用中文表示如下。
該數據主要是根據幾個因素預測氣球是否會破。
三 划分數據集的幾種方式
決策樹的幾種經典實現方式是ID3,C4.5 和 CART
其中C4.5是對ID3的改進,C4.5和ID3都是分類樹,CART 即可用作分類樹,又可用於回歸樹,當CART用作分類時使用基尼指數作為划分依據,當CART用作回歸時使用最小方差作為划分依據。
信息熵
熵(entropy),也即信息熵,是度量樣本集合純度的一種指標。一個數據集的熵越大,則說明該數據分類的純度越純。
D表示數據集,假設D共有m個類別,Pk 表示第k個類別占樣本總數的比例,數據集熵的公式如下:
如上面給出的關於氣球的數據集,只有 “會” 和 “不會”兩種分類,“會”有7個,“不會”有9個,占比分別是 P1 =7/16 , P2=9/16
按照熵的公式 可得 Ent(D) = -P1 * log2P1 - P2*log2P2 = 0.989
代碼實現:
1 from math import log 2 import operator 3 4 def calc_entropy(data_set): 5 """計算數據集的熵""" 6 count = len(data_set) 7 label_counts = {} 8 9 # 統計數據集中每種分類的個數 10 for row in data_set: 11 label = row[-1] 12 if label not in label_counts.keys(): 13 label_counts[label] = 1 14 else: 15 label_counts[label] += 1 16 17 # 計算熵 18 entropy = 0.0 19 for key in label_counts: 20 prob = float(label_counts[key]) / count 21 entropy -= prob * log(prob, 2) 22 return entropy
信息增益法
ID3算法使用信息增益作為划分數據集的依據。整個數據集的熵稱作 原始熵,數據集D根據某個特征划分之后的熵為條件熵,信息增益 = 原始熵 - 條件熵 。用信息增益划分的具體做法是:計算每一類特征V對應的信息增益,然后挑選信息增益最小的特征進行划分。
信息增益公式為:
其中v 為特征a的一個分類,pv 為 v分類占特征a總個數的比例,Dv 根據特征a 的v分類進行划分之后的數據集。
代碼實現:
1 def choose_best_feature_1(data_set): 2 """選取信息增益最高的特征""" 3 feature_count = len(data_set[0]) - 1 4 # 數據集的原始熵 5 base_entropy = calc_entropy(data_set) 6 # 最大的信息增益 7 best_gain = 0.0 8 # 信息增益最大的特征 9 best_feature = -1 10 11 # 遍歷計算每個特征 12 for i in range(feature_count): 13 feature = [example[i] for example in data_set] 14 feature_value_set = set(feature) 15 new_entropy = 0.0 16 17 # 計算信息增益 18 for value in feature_value_set: 19 sub_data_set = split_data_set(data_set, i, value) 20 prob = len(sub_data_set) / float(len(data_set)) 21 new_entropy += prob * calc_entropy(sub_data_set) 22 gain = base_entropy - new_entropy 23 24 # 比較得出最大的信息增益 25 if gain > best_gain: 26 best_gain = gain 27 best_feature = i 28 29 return best_feature
增益率法
ID3所采用的信息增益划分數據集是可能對數目較多的屬性有偏好,C4.5 算法避免了這個問題,使用“增益率”來選擇最優化分屬性。
信息增益率公式:
其中Gain_ratio(D,a) 表示 根據特征 a 划分之后的信息增益率, IV(a)為 特征a 的固有值
代碼實現:
1 def choose_best_feature_2(data_set): 2 """根據增益率選取划分特征""" 3 feature_count = len(data_set[0]) - 1 4 # 數據集的原始熵 5 base_entropy = calc_entropy(data_set) 6 # 最大的信息增益率 7 best_gain_ratio = 0.0 8 # 信息增益率最大的特征 9 best_feature = -1 10 11 # 遍歷計算每個特征 12 for i in range(feature_count): 13 feature = [example[i] for example in data_set] 14 feature_value_set = set(feature) 15 new_entropy = 0.0 16 # 固有值 17 intrinsic_value = 0.0 18 19 # 計算信息增益 20 for value in feature_value_set: 21 sub_data_set = split_data_set(data_set, i, value) 22 prob = len(sub_data_set) / float(len(data_set)) 23 new_entropy += prob * calc_entropy(sub_data_set) 24 intrinsic_value -= prob * log(prob, 2) 25 gain = base_entropy - new_entropy 26 gain_ratio = gain / intrinsic_value 27 28 # 比較得出最大的信息增益率 29 if gain_ratio > best_gain_ratio: 30 best_gain_ratio = gain_ratio 31 best_feature = i 32 33 return best_feature
基尼指數法
當CART用做分類樹時,使用“基尼指數”來選擇划分特征。基尼指數是另外一種表示數據集純度的指標。
基尼值:
基尼指數:
代碼實現:
1 def calc_gini(data_set): 2 """計算數據集的基尼值""" 3 count = len(data_set) 4 label_counts = {} 5 6 # 統計數據集中每種分類的個數 7 for row in data_set: 8 label = row[-1] 9 if label not in label_counts.keys(): 10 label_counts[label] = 1 11 else: 12 label_counts[label] += 1 13 14 # 計算基尼值 15 gini = 1.0 16 for key in label_counts: 17 prob = float(label_counts[key]) / count 18 gini -= prob * prob 19 return gini 20 21 22 def choose_best_feature_3(data_set): 23 """根據基尼指數選擇划分特征""" 24 feature_count = len(data_set[0]) - 1 25 # 最小基尼指數 26 min_gini_index = 0.0 27 # 基尼指數最小的特征 28 best_feature = -1 29 30 # 遍歷計算每個特征 31 for i in range(feature_count): 32 feature = [example[i] for example in data_set] 33 feature_value_set = set(feature) 34 35 # 基尼指數 36 gini_index = 0.0 37 # 計算基尼指數 38 for value in feature_value_set: 39 sub_data_set = split_data_set(data_set, i, value) 40 prob = len(sub_data_set) / float(len(data_set)) 41 gini_index += prob * calc_gini(sub_data_set) 42 43 # 比較得出最小的基尼指數 44 if gini_index < min_gini_index or min_gini_index == 0.0: 45 min_gini_index = gini_index 46 best_feature = i 47 48 return best_feature
四 構造分類樹
每次根據划分算法選出最佳的划分特征進行划分,然后對子數據集進行遞歸划分,直到所有子集的純度都為1,即構成了決策樹。
構造決策樹代碼:
1 def create_division_tree(data_set, labels): 2 """創建決策樹""" 3 class_list = [example[-1] for example in data_set] 4 5 # 所有分類相同時返回 6 if class_list.count(class_list[0]) == len(class_list): 7 return class_list[0] 8 9 # 已經遍歷完所有特征 10 if len(data_set[0]) == 1: 11 return get_top_class(class_list) 12 13 # 選取最好的特征 14 best_feat = choose_best_feature_1(data_set) 15 best_feat_label = labels[best_feat] 16 17 # 划分 18 my_tree = {best_feat_label: {}} 19 del (labels[best_feat]) 20 value_set = set([example[best_feat] for example in data_set]) 21 for value in value_set: 22 sub_labels = labels[:] 23 my_tree[best_feat_label][value] = create_division_tree(split_data_set(data_set, best_feat, value), sub_labels) 24 return my_tree
構造的決策樹存在在Python 字典類型中,不能直觀地看清決策樹層次,這里我們使用Matplotlib 模塊提供的繪圖工具繪制出決策樹的模型如下:
我們可以看到使用不同的划分算法,構造的決策樹是不一樣的。
五 使用決策樹測試分類
通過決策樹預測測試樣本時,就是根據測試樣本的特征屬性 從決策樹根節點開始不斷向下遍歷,直到葉子節點。
1 def classify(division_tree, feat_labels, test_vector): 2 """遍歷決策樹對測試數據進行分類""" 3 first_key = list(division_tree.keys())[0] 4 second_dict = division_tree[first_key] 5 6 feat_index = feat_labels.index(first_key) 7 test_key = test_vector[feat_index] 8 9 test_value = second_dict[test_key] 10 11 if isinstance(test_value, dict): 12 class_label = classify(test_value, feat_labels, test_vector) 13 else: 14 class_label = test_value 15 return class_label
六 寫在后面的話
本文完整代碼見https://gitee.com/beiyan/machine_learning/tree/master/decision_tree,本文只是分類樹方法的簡單實現,關於回歸樹的介紹,以及決策樹的剪枝算法,數值型數據離散方法等 將在后序文章中介紹。