目录
决策树的构造
信息增益
划分数据集
递归构建决策树
使用Matplotlib注解绘制树形图
决策树是最经常使用的数据挖掘算法。
决策树的一般流程:
- 收集数据:可以使用任何方法;
- 准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化;
- 分析数据:可以使用任何方法,构造树完成之后骂我们应该检查图形是否符合预期;
- 训练算法:构造树的数据结构;
- 测试算法:使用经验树计算错误率;
- 使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。
划分数据集的大原则是:将无序的数据变得更加有序。组织杂乱无章数据的一种方法就是使用信息论度量信息,信息论是量化处理信息的分支科学。
再换分数剧集之前之后发生的变化成为信息增益,获得信息增益最高的特征就是最好的选择。
“熵”——描述为信息的期望值:
如果待分类的事务可能划分在多个分类之中,则符号的信息定义为
其中是选择该分类的概率。
为了计算熵,我们需要计算所有类别多有可能值包含的信息期望值,通过下面的公式得到:
计算给定数据集香农熵的代码:
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 提供了一个注解工具annotations,它可以在数据图形上添加文本注解。