決策樹是最經常使用的數據挖掘算法。
決策樹的構造
決策樹的一般流程:
- 收集數據:可以使用任何方法;
- 準備數據:樹構造算法只適用於標稱型數據,因此數值型數據必須離散化;
- 分析數據:可以使用任何方法,構造樹完成之後罵我們應該檢查圖形是否符合預期;
- 訓練算法:構造樹的數據結構;
- 測試算法:使用經驗樹計算錯誤率;
- 使用算法:此步驟可以適用於任何監督學習算法,而使用決策樹可以更好地理解數據的內在含義。
信息增益
劃分數據集的大原則是:將無序的數據變得更加有序。組織雜亂無章數據的一種方法就是使用信息論度量信息,信息論是量化處理信息的分支科學。
再換分數劇集之前之後發生的變化成爲信息增益,獲得信息增益最高的特徵就是最好的選擇。
“熵”——描述爲信息的期望值:
如果待分類的事務可能劃分在多個分類之中,則符號的信息定義爲
其中是選擇該分類的概率。
爲了計算熵,我們需要計算所有類別多有可能值包含的信息期望值,通過下面的公式得到:
計算給定數據集香農熵的代碼:
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))
那麼按照什麼樣的特徵進行劃分呢?
——選擇最大信息增益的特徵進行劃分
這裏設置原始香農熵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,它可以在數據圖形上添加文本註解。