头歌 机器学习 第1关:决策树算法详解
任务描述 本关任务:编写一个使用决策树算法进行信息增益计算及结点划分的程序。 相关知识 为了完成本关任务,你需要掌握:1.决策树模型,2.决策树模型用于分类,3.决策树信息熵构建。 决策树模型 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论中熵的概念。
决策树由结点和有向边组成。结点有两种类型:内部结点和叶结点,其中内部结点表示一个特征或属性,叶结点表示一个类。一般的,一棵决策树包含一个根结点、若干个内部结点和若干个叶结点。叶结点对应于决策结果,其他每个结点则对应于一个属性测试。每个结点包含的样本集合根据属性测试的结果被划分到子结点中,根结点包含样本全集,从根结点到每个叶结点的路径对应了一个判定测试序列。在下图中,圆和方框分别表示内部结点和叶结点。决策树学习的目的是为了产生一棵泛化能力强,即处理未见示例能力强的决策树。下图为决策树的示意图:
决策树根据任务的不同可以分为回归树和分类树,在本次课程中,我们主要实现分类树的构建。 决策树分类器 决策树算法分类和人类在进行决策时的处理机制类似,依据对一系列属性取值的判定得出最终决策。决策树是一棵树结构,其每个非叶子节点表示一个特征属性上的测试,每个分支表示这个特征属性在某个值域上的输出,而每个叶子节点对应于最终决策结果。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点对应的类别作为决策结果。
决策树学习的目的是产生一棵泛化性能强,即处理未见示例能力强的决策树。其基本流程遵循“分而治之”的策略,算法伪代码如下图所示: 1. 输入:训练集D={(x_1,y_1),(x_2,y_2),⋯,(x_m,y_m)}; 2. 属性集A={a_1,a_2,⋯,a_d}. 3. 过程:函数TreeGenerate(D,A) 4. 1: 生成节点node 5. 2: if D中样本全属于同一类别C then 6. 3: 将node标记为C类叶节点;return 7. 4: end if 8. 5: if A=∅ or D中样本在A上取值相同 then 9. 6: 将node标记为叶节点,其类别标记为D中样本数最多的类;return 10. 7: end if 11. 8: 从A中选择最优 划分属性a_*; 12. 9: for a_*的每一个取值a_*^v do 13. 10: 为node生成一个分支;令D_v表示D中在a_*上取值为a_*^v的样本子集; 14. 11: if D_v=∅ then 15. 12: 将分支节点标记为叶节点,其类别标记为D中样本最多的类;return 16. 13: else 17. 14: 以TreeGenerate(D_v,A\{a_*})为分支节点 18. 15: end if 19. 16: end for 20. 输出:以node为根节点的一棵决策树 上述算法最关键的是第8行,即如何选择最优划分,选择的标准是什么。一般而言,随着划分的不断进行,决策树每个分支包含的样本会越来越属于同一类,即节点的“纯度”越来越高。但是为了得到一棵泛化性能强的决策树,根据“奥卡姆剃刀”原则:越是小型的决策树越优于大型的决策树,我们希望最终得到的决策树规模越小越好。因此我们选择划分后能够将样本“纯度提升”最大的那个属性作为最优划分。
当我们选择一个属性进行划分后,信息的纯度将增加,信息的不确定性将随之减少。我们用信息增益来度量样本纯度的提升。假设离散属性a有V个可能的取值{a1,a2,⋯,aV}{a1,a2,⋯,aV},若使用a来对样本集D进行划分,则会产生V个分支节点,其中第v个分支节点包含了D中所有在属性a上取值为avav的样本,记为DvDv。因此我们可以将信息增益的公式记为如下:
因此,信息增益越大,则意味着使用属性a进行划分获得的“纯度提升”越大。著名的ID3决策树算法就是以信息增益为准则来选择划分属性。 信息增益的计算 我们使用鸢尾花的数据来完成相关计算。首先是数据导入,这里使用sklearn中的数据: 1. import numpy as np 2. from sklearn import datasets 3. d=datasets.load_iris() 4. x=d.data[:,2:] 5. y=d.target 然后是信息熵计算的方法: 1. #定义二分类问题的信息熵计算函数np.sum(-p*np.log(p)) 2. def entropy(p): 3. return -p*np.log(p)-(1-p)*np.log(1-p) 然后,就可以根据信息熵对数据进行实现划分,从而实现决策树信息熵构建,下面为主要的参考代码: 1. # 根据最有划分属性和值进行划分的函数 2. def split(x,y,d,value): 3. index_a=(x[:,d]<=value) 4. index_b=(x[:,d]>value) 5. return x[index_a],x[index_b],y[index_a],y[index_b] 6. 7. 8. from collections import Counter 9. # 信息熵的计算,可参考上述公式和代码编写 10. def entropy(y): 11. pass 12. 13. # 计算最优划分属性best_d和值best_v 14. def try_spit(x,y): 15. best_entropy=float("inf") 16. best_d,best_v=-1,-1 17. for d in range(x.shape[1]): 18. sorted_index=np.argsort(x[:,d]) 19. for i in range(1,len(x)): 20. if x[sorted_index[i-1],d] != x[sorted_index[i],d]: 21. v=(x[sorted_index[i-1],d]+x[sorted_index[i],d])/2 22. x_l,x_r,y_l,y_r=split(x,y,d,v) 23. e=entropy(y_l)+entropy(y_r) 24. if e<best_entropy: 25. best_entropy,best_d,best_v=e,d,v 26. return best_entropy,best_d,best_v 编程要求 根据提示,在右侧编辑器补充代码,实现决策树信息熵构建,包括: 1. 划分的函数 2. 信息熵计算的函数 3. 最优划分属性和最优值计算的函数 4. 进行划分,并打印划分后的信息熵值 测试说明 平台会对你编写的代码进行测试: 预期输出: 提示:
参照示例完成任务 开始你的任务吧,祝你成功!
import numpy as np
from sklearn import datasets
from collections import Counter
#######Begin#######
# 划分函数
def split(x,y,d,value):
index_a = (x[:,d] <= value)
index_b = (x[:,d] > value)
return x[index_a], x[index_b], y[index_a], y[index_b]
#######End#########
#######Begin#######
# 信息熵的计算
def entropy(y):
counter = Counter(y)
res = 0.0
for num in counter.values():
p = num / len(y)
res += -p * np.log(p)
return res
#######End#########
#######Begin#######
# 计算最优划分属性和值的函数
def try_spit(x,y):
best_entropy = float('inf')
best_d, best_v = -1, -1
for d in range(x.shape[1]):
sorted_index = np.argsort(x[:,d])
for i in range(1, len(x)):
if x[sorted_index[i-1], d] != x[sorted_index[i], d]:
v = (x[sorted_index[i-1], d] + x[sorted_index[i], d]) / 2
x_l, x_r, y_l, y_r = split(x, y, d, v)
e = entropy(y_l) + entropy(y_r)
if e < best_entropy:
best_entropy = e
best_d = d
best_v = v
return best_entropy, best_d, best_v
#######End#########
# 加载数据
d = datasets.load_iris()
x = d.data[:, 2:]
y = d.target
# 计算出最优划分属性和最优值
best_entropy, best_d, best_v = try_spit(x, y)
# 使用最优划分属性和值进行划分
x_l, x_r, y_l, y_r = split(x, y, best_d, best_v)
# 打印结果
print("叶子结点的熵值:")
print(entropy(y_l))
print("分支结点的熵值:")
print(entropy(y_r))
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)