机器学习(周志华)第四章习题解答

转自:http://blog.csdn.NET/wzmsltw/article/details/51059394
本文是对周志华的《机器学习》的习题解答,文章整理的很好,为方便之后查看,记录如下~
~~~
注:本文中的代码均使用Python,常用工具包包括 pandas,scikit-learn,numpy, scipy,matplotlib等。


4.1试证明对于不含冲突数据(即特征向量完全相同但标记不同)的训练集,必存在与训练集一致(即训练误差为0)的决策树
答:假设不存在与训练集一致的决策树,那么训练集训练得到的决策树至少有一个节点上存在无法划分的多个数据(若节点上没有冲突数据,那么总是能够将数据分开的)。这与前提-不含冲突数据 矛盾,因此必存在与训练集一致的决策树
 
4.2试析使用“最小训练误差”作为决策树划分选择的缺陷。
答:若以最小训练误差作为决策树划分的依据,由于训练集和真实情况总是会存在一定偏差,这使得这样得到的决策树会存在过拟合的情况,对于未知的数据的泛化能力较差。因此最小训练误差不适合用来作为决策树划分的依据。
 
4.3试编程实现基于信息熵进行划分选择的决策树算法,并为表4.3中数据生成一棵决策树
答:基于信息熵进行划分选择的决策树算法即ID3决策树,代码见我的另外一篇博文:ID3决策树的Python实现


4.4试编程实现基于基尼指数进行划分选择的决策树算法,并为表4.2中数据生成预剪枝、后剪枝决策树,并与未剪枝决策树进行比较。
答:基于基尼指数进行划分选择的决策树算法即CART决策树,代码见我的另外一篇博文:CART决策树与剪枝处理


4.5试编程实现基于对率回归进行划分选择的决策树算法,并为表4.3中数据生成一棵决策树
答:由于不知道该如何用对率回归做划分选择,所以此题暂时不会写。若读到此文的朋友了解相关内容可以在文后评论。非常感激~
 
4.6试选择4个UCI数据集,对上述3种算法所产生的未剪枝、预剪枝、后剪枝决策树进行实验比较,并进行适当的统计显著性检验。
 答:我选了一个UCI数据集:Wine Data Set。这个数据集共有大约180条数据,12种特征,其标签为1、2、3共三种(应该是三种酒吧)。我对数据的顺序进行了随机,取前140个数据作为训练集,后40个数据作为测试集
按照4.3与4.4中的代码,得到的决策树如下:
ID3决策树:


CART未剪枝决策树:


CART预剪枝决策树:




CART后剪枝决策树:


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


4.7图4.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一致。
  • 9
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 什么是泛化能力?泛化能力和过拟合之间有什么关系? 泛化能力是指模型在新的、未见过的数据上的表现能力。模型的泛化能力与其对训练数据的拟合程度有关,通常来说,过拟合的模型泛化能力较差。 2. 什么是交叉验证?交叉验证的作用是什么? 交叉验证是一种通过将数据集分成若干个子集来进行模型评估的方法。具体地,将数据集分成k个子集,每个子集都轮流作为测试集,其余子集作为训练集,重复k次,最终得到k个模型的评估结果的平均值。交叉验证的作用是提高模型评估的可靠性和泛化能力。 3. 留出法、k折交叉验证和留一法的区别是什么?它们各自适用于什么情况? 留出法是将数据集分成两部分,一部分作为训练集,另一部分作为测试集。留出法适用于数据集较大的情况。 k折交叉验证是将数据集分成k个子集,每个子集都轮流作为测试集,其余子集作为训练集,重复k次,最终得到k个模型的评估结果的平均值。k折交叉验证适用于数据集较小的情况。 留一法是k折交叉验证的一种特殊情况,即将数据集分成n个子集,每个子集都作为测试集,其余子集作为训练集,重复n次。留一法适用于数据集较小且样本数较少的情况。 4. 为什么要对数据进行预处理?数据预处理的方法有哪些? 数据预处理可以提高模型的表现,并且可以减少过拟合的风险。数据预处理的方法包括:标准化、归一化、缺失值填充、特征选择、特征降维等。 5. 什么是特征选择?特征选择的方法有哪些? 特征选择是指从所有特征中选择出对模型预测结果有重要贡献的特征。特征选择的方法包括:过滤式方法、包裹式方法和嵌入式方法。其中,过滤式方法是基于特征间的关系进行特征选择,包裹式方法是基于模型的性能进行特征选择,嵌入式方法是将特征选择嵌入到模型训练中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值