概述: 最近通过《机器学习实战》这本书学习机器学习的相关算法,此书在第三章讲到了决策树,此算法涉及的数据准备等步骤较多,所以在此进行整理统一,以便日后温习。
算法思想:决策树算法是分类算法的一种,其大致过程是通过已有数据构造决策树,再通过决策树对新输入的数据进行分类。通过已有数据构造决策树时需要注意,由于这属于监督学习,我们必须预先知道已有数据的分类结果。
数据准备:此算法需要把已有数据处理成python的list类型,把一个样本数据的所有特征放在一个列表里作为外部列表的一个元素。简单来说需要把数据处理成一个嵌套列表。
例:
我们把此表中的数据处理为:
def create_dataset():
dataset = [[1,1,'yes']
[1,1,'yes']
[1,0,'no']
[0,1,'no']
[0,1,'no']]
labels = ['no surfacing','flippers']
return dataset,labels
我们会根据数据的特征去划分数据,划分的原则就是使数据变得更加有序,所以这里就需要一个量来度量数据的无序度(或者说复杂度),这个量就是香农熵,简称熵。其计算公式为:
p(xi)指的是样本数据中某个分类占总类别数的比例,也就是概率。
简单点来说,熵越大,数据里面包含的类别就越多,所以我们需要划分数据把这个熵值变得越来越小使数据趋于有序化。
计算熵值的代码如下:
import math
def calc_shannonEnt(dataset):
num_entries = len(dataset)
label_counts = {}
for feat_vec in dataset:
if feat_vec[-1] not in label_counts:
label_counts[feat_vec[-1]] = 0
label_counts[feat_vec[-1]] += 1
shannonEnt = 0.0
for key in label_counts.keys():
pre_percent = float(label_counts[key])/num_entries
new_shannonEnt = pre_percent*math.log(pre_pencent,2)
shannonEnt = shannonEnt-new_shannonEnt
return shannnonEnt
划分数据集:
def split_data(dataset,axis,value):
nwe_dataset = []
for axis_value in dataset:
if axis_value[aixs] == value:
reduce_vec = axis_value[:axis]
reduce_vec_1 = aixs_value[axis+1:]
reduce_vec.extend(reduce_vec_1)
new_dataset.append(reduce_vec)
return new_dataset
选择最好的数据划分方式:
def choose_feature_tosplit(dataset):
num_lie = len(dataset[0])-1
base_shannonEnt = calc_shannonEnt(dataset)
best_feature = -1
best_ingoin = 0.0
for i in range(num_lie):
data_list = [example[i] for example in dataset]
unicalvals = set(data_list)
cur_goin = 0.0
for value in unicalvals:
new_dataset = split_data(data,i,value)
prob = len(cur_shannonEnt)/len(dataset)
cur_goin += prob*(cal_shannonEnt(new_dataset))
mid_value = base_shannonEnt - cur_goin
if(mid_value>best_ingoin):
best_ingoin = mid_value
best_feature = i
return best_feature
此段代码可以看出,如果cur_goin越小,则mid_value就越大,cur_goin越小也对应按当前特征值分组的数据复杂度越小,这样我们选出来的best_feature是对应mid_value最大,也就是对应cur_goin最小的值。这样即筛选出了依据哪种特征划分数据是最好的数据划分方式。
构建决策树:
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 majoritycnt(class_list)
best_feat = choose_feature_tosplit(dataset)
bset_feat_label = labels[best_feat]
my_tree = {best_feat_label:{}}
del(labels[best_feat_label])
feat_values = [example[best_feat] for examole in dataset]
uniquevals = set(feat_values)
for value in uniquevals:
sublabels = labels[:]
my_tree[best_feat_label][value] = create_tree(split_data(dataset,best_feat,value),sublabels)
return my_tree
import operator
def majoritycnt(class_list):
count_dict = {}
for key in class_list:
if key not in count_dict.keys():
count_dict[key] = 0
count_dict[key] += 1
sort_list = sorted(count_dict.iteritems(),key=operator.itemgetter(1),reverse=True)
return sort_list[0][0]
构建决策树有两个递归出口,一是类别完全相同时停止继续划分,二是遍历完所有特征时返回出现次数最多的类。
使用决策树分类:
def classify(input_tree,feat_labels,test_vc):
frist_str = input_tree.keys()[0]
second_dict = input_tree[frist_str]
values = second_dict.keys()
feat_index = feat_labels.index(frist_str)
for value in values:
if test_vc[feat_index] == value:
if type(second_dict[value]).__name__ == 'dict':
class_label=classify(second_dict,feat_labels,test_vc)
else:
class_label = second_dict[key]
return class_label
test_vc是待分类的测试数据,input_tree是构造好的决策树,feat_labels 是特征值的标签列表。