机器学习-周志华-课后习题答案-决策树

本文深入探讨了决策树算法的关键概念,包括如何确保训练误差为零、最小训练误差的缺陷、基于信息熵和基尼指数的决策树划分选择,并通过实例展示了不同决策树算法的表现。

4.1试证明对于不含冲突数据(即特征向量完全相同但标记不同)的训练集,必存在与训练集一致(即训练误差为0)的决策树

答:假设不存在与训练集一致的决策树,那么训练集训练得到的决策树至少有一个节点上存在无法划分的多个数据(若节点上没有冲突数据,那么总是能够将数据分开的)。这与前提-不含冲突数据 矛盾,因此必存在与训练集一致的决策树

 

4.2试析使用“最小训练误差”作为决策树划分选择的缺陷。

答:若以最小训练误差作为决策树划分的依据,由于训练集和真是情况总是会存在一定偏差,这使得这样得到的决策树会存在过拟合的情况,对于未知的数据的泛化能力较差。因此最小训练误差不适合用来作为决策树划分的依据。

 

4.3试编程实现基于信息熵进行划分选择的决策树算法,并为表4.3中数据生成一棵决策树

答:基于信息熵进行划分选择的决策树算法即ID3决策树,代码见我的另外一篇博文:ID3决策树的Python实现


4.4试编程实现基于基尼指数进行划分选择的决策树算法,并为表4.2中数据生成预剪枝、后剪枝决策树,并与未剪枝决策树进行比较。

答:基于基尼指数进行划分选择的决策树算法即CART决策树,代码见我的另外一篇博文:CART决策树与剪枝处理


4.5试编程实现基于对率回归进行划分选择的决策树算法,并为表4.3中数据生成一棵决策树

答:由于不知道该如何用对率回归做划分选择,所以此题暂时不会写。若读到此文的朋友了解相关内容可以在文后评论。非常感激~

 

4.6试选择4UCI数据集,对上述3种算法所产生的未剪枝、预剪枝、后剪枝决策树进行实验比较,并进行适当的统计显著性检验。

 答:我选了一个UCI数据集:Wine Data Set。这个数据集共有大约180条数据,12种特征,其标签为1、2、3共三种(应该是三种酒吧)。我对数据的顺序进行了随机,取前140个数据作为训练集,后40个数据作为测试集

按照4.3与4.4中的代码,得到的决策树如下:

ID3决策树:


CART未剪枝决策树:


CART预剪枝决策树:


CART后剪枝决策树:

可以看出,后剪枝比起预剪枝不容易出现欠拟合的情况。


4.74.2是一个递归算法,若面临巨量数据,则决策树的层数会很深,使用递归方法易导致“栈”溢出,试使用“队列”数据结构,以参数maxDepth控制数的最大深度,写出与图4.2等价、但不使用递归的决策树生成算法。

 答:下面算法我没有尝试写对应的代码,若有朋友写过欢迎交流/指正。

以下代码为 队列+MaxDepth控制,即广度优先搜索。其实我觉得这里如果要用MaxDepth进行控制的话,应该选择堆栈而非队列,即应该用深度优先搜索。但下面还是给出队列的形式。若要改为深度优先搜索只需要将先进后出 改成 先进先出即可(即数据存取都在一端)。

——————————————————————————————————————————————————————

输入:训练集 D={(x1,y1),(x2,y2),...,(xm,ym)};

      属性集 A={a1,a2,...,ad}

      最大深度 MaxDepth

过程:函数TreeGenerate(D,A,MaxDepth)

1:生成节点root

2:if D中样本全部属于同一类别C then

3:     将root标记为C类叶节点;return

4:end if

5:if A=空集 or D中样本在A上取值相同 then

6:     将root标记为叶节点,其类别标记为D中样本数最多的类;return

7:end if

8:从A中选择最优划分属性a*;

9:将root标记为分支节点,属性为属性a*;

10:将root放入NodeQueue;

11:将D放入DataQueue;

12:将A\{a*}放入AQueue;

13:初始化深度depth=1;

14:将depth放入DepthQueue;

15:while NodeQueue 非空:

16:     取出NodeQueue队尾的节点rNode,其对应的属性是ra*;

17:     取出DataQueue队尾的数据集rD;     #此处r均指队尾rear

18:     取出AQueue队尾的属性集rA;

19:     取出DepthQueue队尾的元素rdepth;

20:     if rdepth==MaxDepth:

21:          将rNode标记为叶节点,类别标记为rD中样本最多的类;

22:          continue;     #跳过本次循环,即不再对这个节点做展开

23:     for ra*的每一个取值ra*v do:

24:          为rNode生成一个分支节点,令rDv表示rD在ra*上取值为ra*v的样本子集;

25:          if rDv为空 then:

26:               将分支节点标记为叶节点,其类别标记为rD中样本最多的类;

27:          else if rD中样本全部属于同一类别C then

28:               将分支节点标记为C类叶节点;

29:          else if rA=空集 or rD中样本在A上取值相同 then

30:               将分支节点标记为叶节点,其类别标记为rD中样本数最多的类;

31:          else:

32:               从rA中选择最优划分属性a*v;

33:               将分支节点的属性记为a*v;

34:               将分支节点放入NodeQueue的队头;

35:               将rDv放入DataQueue的队头;

36:               将rA\{a*v}放入AQueue的队头;

37:               将(rDepth+1)放入DepthQueue的队头;

38:          end if

39:     end for

40:end while

输入:以root为根节点的一棵决策树

——————————————————————————————————————————————————————


4.8试将决策树生成的深度优先搜索过程修改为广度优先搜索,以参数MaxNode控制树的最大结点数,将题4.7中基于队列的决策树算法进行改写。对比题4.7中的算法,试分析哪种方式更易于控制决策树所需储存不超过内存。

 答:在4.7中写的基于队列的算法本身就是广度优先搜索的。若要写成深度优先搜索的方式应该将队列换成堆栈即可。

以下对4.7中的代码进行改写,用队列+MaxNode控制

——————————————————————————————————————————————————————

输入:训练集 D={(x1,y1),(x2,y2),...,(xm,ym)};

      属性集 A={a1,a2,...,ad}

      最大节点数 MaxNode

过程:函数TreeGenerate(D,A,MaxNode)

1:生成节点root

2:if D中样本全部属于同一类别C then

3:     将root标记为C类叶节点;return

4:end if

5:if A=空集 or D中样本在A上取值相同 then

6:     将root标记为叶节点,其类别标记为D中样本数最多的类;return

7:end if

8:从A中选择最优划分属性a*;

9:将root标记为分支节点,属性为属性a*;

10:将root放入NodeQueue;

11:将D放入DataQueue;

12:将A\{a*}放入AQueue;

13:初始化节点数numNode=1;

14:while NodeQueue 非空:

15:     取出NodeQueue队尾的节点rNode,其对应的属性是ra*;

16:     取出DataQueue队尾的数据集rD;     #此处r均指队尾rear

17:     取出AQueue队尾的属性集rA;

18:     if numNode==MaxNode:

19:          将rNode标记为叶节点,类别标记为rD中样本最多的类;

20:          continue;     #跳过本次循环,即不再对这个节点做展开。对于下一个节点,由于条件任然成立,故任然不展开

21:     for ra*的每一个取值ra*v do:

22:          为rNode生成一个分支节点,令rDv表示rD在ra*上取值为ra*v的样本子集;

23:          if rDv为空 then:

24:               将分支节点标记为叶节点,其类别标记为rD中样本最多的类;

25:          else if rD中样本全部属于同一类别C then

26:               将分支节点标记为C类叶节点;

27:          else if rA=空集 or rD中样本在A上取值相同 then

28:               将分支节点标记为叶节点,其类别标记为rD中样本数最多的类;

29:          else:

30:               从rA中选择最优划分属性a*v;

31:               将分支节点的属性记为a*v;

32:               将分支节点放入NodeQueue的队头;

33:               将rDv放入DataQueue的队头;

34:               将rA\{a*v}放入AQueue的队头;

35:               将(rDepth+1)放入DepthQueue的队头;

36:          end if

37:         numNode+=1

38:     end for

39:end while

输入:以root为根节点的一棵决策树

——————————————————————————————————————————————————————

讨论:4.7中与4.8中用队列的话均为广度优先搜索,我觉得是出题的时候的疏忽。。

应该是广度优先搜索(队列)+MaxNode控制 与 深度优先搜索(堆栈)+MaxDepth控制 两种方法之间的比较。

个人认为,广度优先搜索(队列)+MaxNode 的方法更容易控制决策树所需内存不溢出。因为最大节点数目是固定的。队列中储存的是当前深度未处理的节点以及当前深度以处理节点的下一级节点,其数目是可控的,总小于最大节点数。而深度优先搜索在堆栈中储存的是当前节点的兄弟节点、当前节点的父节点、当前节点的父节点的兄弟节点.....若一些分支节点的分支数很多,那么堆栈的深度就会比较深,虽然有MaxDepth控制最大深度,但还是可能出现栈溢出的情况。


4.9试将4.4.2节对缺失值的处理机制推广到基尼指数的计算中去。

 答:


 

4.10从网上下载或自己编程实现任意一种多变量决策树算法,并观察其在西瓜数据集3.0上产生的结果。

答:此处要求实现一种多变量决策树算法。实际上4.3与4.4题就是多变量决策树算法。其在西瓜数据集3.0上产生的结果如下


与P85的图4.8一致。

### 周志华机器学习》第二章课后习题答案 #### 2.10 Friedman检验中使用式(2.34)(2.35) 的区别 Friedman检验是一种非参数统计方法,适用于多组相关样本之间的差异分析。当处理多个模型在同一测集上的性能评估时尤为有用。 - **式(2.34)** 主要用于计算各算法排名的平均值及其方差,从而构建出一个衡量不同算法之间相对表现的标准。具体来说,该公式帮助量化每种算法在整个实验中的总体表现位置[^3]。 - **式(2.35)** 则进一步利用上述得到的信息来决定是否存在显著性的差别。通过引入临界值的概念,可以据此判断所观察到的表现差距是否超出了随机波动所能解释的程度之外。如果实际计算所得的结果超过了设定好的阈值,则说明至少有两个被比较的对象间确实存在明显不同的效果。 为了更直观理解这两个公式的应用过程以及它们各自的作用: ```python import numpy as np from scipy.stats import friedmanchisquare # 示例数据:假设有三个分类器A、B、C分别在五个数据集上进行了测 data = [ [87, 92, 85], # 数据集1上的准确率 [89, 90, 88], [91, 93, 86], [88, 91, 87], [90, 94, 89] ] chi_statistic, p_value = friedmanchisquare(*np.array(data).T) print(f"Chi-square statistic: {chi_statistic}") print(f"P-value: {p_value}") if p_value < 0.05: print("At least two classifiers have significantly different performances.") else: print("No significant difference among classifier performances.") ``` 这段Python代码展示了如何运用SciPy库执行Friedman检验,并依据返回的卡方统计量和P值做出结论。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值