除了绘制树部分代码有借鉴,其他代码都是自己亲手完成,历时2天时间,过程稍微痛苦,当看到运行结果出现在面前时,一切都是高兴的,感觉过程也变得美妙了~
由于更喜欢C++编程,所以使用python类来完成~~~~,个人感觉面向对象更容易和更适合实现生成决策树的软件系统
由于是代码的第一稿,还没有精简,比较长,所以先贴出来运行结果,再给出代码
此软件系统:可以指定决策树的深度
1.使用的样本集
'''''
提供训练样本集
每个example由多个特征值+1个分类标签值组成
比如第一个example=['youth', 'no', 'no', '1', 'refuse'],此样本的含义可以解读为:
如果一个人的条件是:youth age,no working, no house, 信誉值credit为1
那么此类人会被分类到refuse一类中,即在相亲中被拒绝
每个example的特征值类型为:
['age', 'working', 'house', 'credit']
每个example的分类标签class_label取值范围为:'refuse'或者'agree'
'''
data_list = [['youth', 'no', 'no', '1', 'refuse'],
['youth', 'no', 'no', '2', 'refuse'],
['youth', 'yes', 'no', '2', 'agree'],
['youth', 'yes', 'yes', '1', 'agree'],
['youth', 'no', 'no', '1', 'refuse'],
['mid', 'no', 'no', '1', 'refuse'],
['mid', 'no', 'no', '2', 'refuse'],
['mid', 'yes', 'yes', '2', 'agree'],
['mid', 'no', 'yes', '3', 'agree'],
['mid', 'no', 'yes', '3', 'agree'],
['elder', 'no', 'yes', '3', 'agree'],
['elder', 'no', 'yes', '2', 'agree'],
['elder', 'yes', 'no', '2', 'agree'],
['elder', 'yes', 'no', '3', 'agree'],
['elder', 'no', 'no', '1', 'refuse']]
feat_list = ['age', 'working', 'house', 'credit']
2. 运行得到的样本集的决策树
=============== samples decision-tree dict ===================len( samples decision-tree dict ): 1
type( samples decision-tree dict ): <class 'dict'>np.shape( samples decision-tree dict ): ()
len(dict_shape): 0
samples decision-tree dict = {
house :{
no :{
working :{
no :{
age : {'elder': 'refuse', 'youth': 'refuse'}
}
yes : agree
}
}
yes : agree
}
}
======
绘制的决策树图形
总上面可以看到,当决策树在age特征节点时,age的子节点都是refuse,说明此人不管什么年龄,都会被决绝,很容易知道age节点在决策树中没有任何意义,完全可以将working特征值=no时的子节点设置为refuse,下面我们对决策树的生成终止条件重新设置后,再看得到的决策树。设置leastFeatNum=4,上面决策树是leastFeatNum=3时生成的。
#决策树生成终止的条件,当样本的特征少于leastFeatNum个时,不再继续求样本集的决策树
leastFeatNum = 3
#创建ID3算法生成决策树类的对象
samples = CID3DecisionTree(train_data_list, feat_list, leastFeatNum)
#生成决策树字典
samples.create_tree()
leastFeatNum=4时,得到的决策树字典和绘制图形如下所示:
=============== samples decision-tree dict ===================
len( samples decision-tree dict ): 1
type( samples decision-tree dict ): <class 'dict'>
np.shape( samples decision-tree dict ): ()
len(dict_shape): 0
samples decision-tree dict = {
house :{
no :{
working : {'no': 'refuse', 'yes': 'agree'}
}
yes : agree
}
}
======
可以看到,此时决策树更简洁更效率~
3.代码
# -*- coding: utf-8 -*-
"""
@author: 蔚蓝的天空Tom
Talk is cheap,show me the code
Aim:ID3算法生成决策树(字典存储), 并绘制决策树图形
"""
import numpy as np
import math
import matplotlib.pyplot as plt
varnamestr = lambda v,nms: [ vn for vn in nms if id(v)==id(nms[vn])][0]
class CUtileTool(object):
'''提供有用的方法 比如dump_list方法,可以打印给定的list的相关信息'''
def dump_list(self, src_list, src_list_namestr):
'''逐行打印list
:param self:类实例自身
:param src_list:被打印的源list
:return 无
'''
print('\n============',src_list_namestr,'================')
list_len = len(src_list)
list_shape = np.shape(src_list)
print('type(',src_list_namestr,'):',type(src_list)) #<class 'list'>
print('np.shape(',src_list_namestr,'):',np.shape(src_list))
if 1 == len(list_shape):
print(src_list)
elif 2 == len(list_shape):
for i in range(list_len):
if 0 == i:
print('[',src_list[i])
elif (list_len - 1) == i:
print(src_list[i],']')
else:
print(src_list[i])
else:
print(src_list)
print('======\n')
return
def dump_array(self, src_a, src_dict_namestr):
'''''
逐行打印array
:param self:类实例自身
:param src_a:被打印的源array
:return 无
'''
print('\n===============',src_dict_namestr,'===================')
a_len = len(src_a)
a_shape = np.shape(src_a)
print('type(',src_dict_namestr,'):',type(src_a)) #<class 'list'>
print('np.shape(',src_dict_namestr,'):',np.shape(src_a))
if 1 == len(a_shape):
print(src_a)
elif 2 == len(a_shape):
for i in range(a_len):
if 0 == i:
print('[',src_a[i])
elif (a_len - 1) == i:
print(src_a[i],']')
else:
print(src_a[i])
else: