• 沒有找到結果。

9 . 4 树剪枝

在文檔中 关 于 封 面 (頁 171-174)

图9-2的数据保存在一个以恤键分隔的文本文档狀0加 中 数 据 。为从上述数据中构建一棵回 归 树’ 在? 3 ^如提示符下敲入如下命令:

>>> m y D a t l = r e g T r e e s .l o a d D a t a S e t ( ' e x O .t x t 1)

>>> myMatl=smat (myDatl)

>>> r e g T r e e s .c r e a t e T r e e (myMatl)

{ ' s p I n d ' : 1, 1s p V a l ' : m a t r i x ( [ t 0 . 3 9 4 3 5 ] ] ) , 1 r i g h t ' : {'s p I n d ' : 1, 's p V a l 1 : m a t r i x ( [[ 0 . 1 9 7 8 3 4 ] ] ) , ' r i g h t ' : - 0 . 0 2 3 8 3 8 1 5 5 5 5 5 5 5 5 5 5 3 , ' l e f t ' :

1 . 0 2 8 9 5 8 3 6 6 6 6 6 6 6 6 4 } , 'l e f t ' : { ' s p I n d ' : 1, 's p V a l ' : m a t r i x { [[ 0.5 8 2 0 0 2 ] ] ) , ' r i g h t 1 : 1. 9 8 0 0 3 5 0 7 1 4 2 8 5 7 1 7 , 1l e f t 1 : { 'spInd' : 1, 1s p V a l 1 : m a t r i x ([[

0 . 7 9 7 5 8 3 ] ] ) , 'r i g h t 1 : 2 . 9 8 3 6 2 0 9 5 3 4 8 8 3 7 2 4 , ' l e f t 1 : 3 . 9 8 7 1 6 3 2 0 0 0 0 0 0 0 0 4 } } }

可以检査一下该树的结构以确保树中包含5个叶节点。读者也可以在更复杂的数据集上构建 回归树并观察实验结果。

到现在为止,已经完成回归树的构建,但是需要某种措施来检查构建过程否得当。下面将介 绍 树 剪 枝 (treepruning)技 术 ,它通过对决策树剪枝来达到更好的预测效果。

9 . 4 树剪枝

一棵树如果节点过多,表明该模型可能对数据进行了“过拟合”。那 么 ,如何判断是否发生了 过拟合?前面章节中使用了测试集上某种交叉验证技术来发现过拟合,决策树亦是如此。本节将 对此进行讨论,并分析如何避免过拟合。

通过降低决策树的复杂度来避免过拟合的过程称为剪枝(pnming)。其实本章前面巳经进行 过剪枝处理。在 函 数 也003纽6社3? 1 ^ ( )中的提前终止条件,实际上是在进行一种所谓的预剪 枝 (prepruning)操 作 。另一种形式的剪枝需要使用测试集和训练集,称 作 后 剪 枝 (?03中]1™ ^ ) 。 本节将分析后剪枝的有效性,但首先来看一下预剪枝的不足之处。

9 . 4 . 1 预剪枝

上节两个简单实验的结果还是令人满意的,但背后存在一些问题。树构建算法其实对输人的 参 数1013和101泗_常 敏感 ,如果使用其他值将不太容易达到这么好的效果。为了说明这一点,

在尸7<^«1提示符下输人如下命令

>>> r e g T r e e s .c r e a t e T r e e ( m y M a t ,o p s = (0,1))

与上节中只包含两个节点的树相比,这里构建的树过于臃肿,它甚至为数据集中每个样本都 分配了一个叶节点。

图9-3中的散点图,看上去与图9-1非常相似。但如果仔细地观察^轴就会发现,前者的数量级 是后者的1 0 _。这将不是问题,对吧?现在用该数据来构建一棵新的树(数据存放在¥ 2 .时 中 ), 在Python提示符下输人以下命令:

>>> m y D a t 2 = r e g T r e e s •l o a d D a t a S e t ( 1e x 2 .t x t 1)

>>> m y M a t 2 = m a t ( m y D a t 2 )

>>> r e g T r e e s .c r e a t e T r e e (myMat2)

168

9

章 树 回 归

{'spInd' : 0, 's p V a l ' : m a t r i x ( [[ 0 . 4 9 9 1 7 1 ] ] ) , 1 r i g h t 1 : {'spInd': 0, 'spVal' : m a t r i x ( [[ 0 . 4 5 7 5 6 3 ] ] ) , 'r i g h t 1 : - 3 . 6 2 4 4 7 8 9 0 6 9 7 6 7 4 3 8 ,

■left': 7 . 9 6 9 9 4 6 1 2 4 9 9 9 9 9 9 9 } , 11

0, 1s p V a l ' : m a t r i x ( [[ 0 . 9 5 8 5 1 2 ] ] ) , ' r i g h t ' : 1 1 2 . 4 2 8 9 5 5 7 5 0 0 0 0 0 1 , 'l e f t 1 : 1 0 5 . 2 4 8

2 3 5 0 0 0 0 0 0 1 } } } }

9 - 3

将图

9-1

的数据的

)

棚放大

100

倍后的新数据集

不知 你注意 到 没 有 ,从图

9-1

数据集构建出来的树只有两个叶节点,而这里构建的新树则有 很 多 叶节 点。产生这个现象的原因在于,停止条件七

013

对误差的数量级十分敏感。如果在选项

中花费时间并对上述误差容忍度取平方值,或许也能得到仅有两个叶节点组成的树:

>>> r e g T r e e s .c r e a t e T r e e ( m y M a t 2 ,o p s = (10000,4))

{ 'spInd' : 0, 1s p V a l ' : m a t r i x ( [[ 0 . 4 9 9 1 7 1 ] ] ) , 1 r i g h t ' : - 2 . 6 3 7 7 1 9 3 2 9 7 8 7 2 3 4 1 , 1l e f t ' : 1 0 1 . 3 5 8 1 5 9 3 7 7 3 5 8 5 5 }

然 而 ,通过不断修改停止条件来得到合理结果并不是很好的办法。事实上,我们常常甚至不确 定到底需要寻找什么样的结果。这正是机器学习所关注的内容,计算机应该可以给出总体的概貌。

下节将讨论后剪枝,即利用测试集来对树进行剪枝。由于不需要用户指定参数,后剪枝是一 个更理想化的剪枝方法。

9 . 4 . 2 后剪枝

使用后剪枝方法需要将数据集分成测试集和训练集。首先指定参数,使得构建出的树足够大、

9 . 4

树剪枝

169

170

9

章 树 回 归

testData

01^

加 ()函数首先需要确认测试集是否为空

0

。一 旦 非 空 ,则反复递归调用函数

£ ^ ^ ( )

对测试数据进行切分。因为 树是 由其他数据集(训 练 集 )生 成 的 ,所以测试集上会有一 些样本与原数据集样本的取值范围不同。一旦出现这种情况应当怎么办?数据发生过拟合应该进 行剪枝吗?或者模型正确不需要任何剪枝?这里假设发生了过拟合,从而对树进行剪枝。

接下来要检查某个分支到底是子树还是节点。如 果是子树,就调用函数

9

^ « ^ ()来 对 该 子 树 进行剪枝。在对左右两个分支完成剪枝之后,还需要检查它们是否仍然还是子树。如果两个分支 已经不再是子树,那么就可以进行合并。具体做法是对合并前后的误差进行比较。如果合并后的 误差比不合并的误差小就进行合并操作,反之则不合并直接返回

o

接下来看看实际效果,将程序清单

9-3

的代码添加到比

8

公沈

3.?7

文 件并保存,在?沖如提示符 下输入下面的命令:

>>> r e l o a d ( r e g T r e e s )

< m o d u l e 1r e g T r e e s 1 f r o m 'r e g T r e e s . p y c 1>

为了创建所有可能中最大的树,输人如下 命令:

>>> m y T r e e = r e g T r e e s .c r e a t e T r e e ( m y M a t 2 , o p s = {0,1))

输人以下命令导人测试数据:

>>> m y D a t T e s t = r e g T r e e s .l o a d D a t a S e t { 1e x 2 t e s t .t x t 1)

>>> m y M a t 2 T e s t = m a t { m y D a t T e s t )

输人以下命令,执行剪枝过程:

>>> r e g T r e e s .p r u n e ( m y T r e e , m y M a t 2 T e s t ) m e r g i n g

m e r g i n g m e r g i n g

m e r g i n g

{ 1s p I n d ' : 0, ' s p V a l 1 : m a t r i x {[[ 0 . 4 9 9 1 7 1 ] ] ) , 1 r i g h t ' : { ' s p I n d 1 : 0, ' a p V a l ' :

01, ' X e f t ': { ' s p I n d ' : 0, ' s p V a l ' : m a t r i x ( [[ 0 . 9 6 0 3 9 8 ] ] ) , ' r i g h t ' : 1 2 3 . 5 5 9 7 4 7 , ' l e f t ' : 1 1 2 . 3 8 6 7 6 4 } } } , ' l e f t ' : 9 2 . 5 2 3 9 9 1 4 9 9 9 9 9 9 9 4 } } } }

可以看到 ,大量的节点已经被剪枝掉了,但没有像预期的那样剪枝成两部分,这说明后剪枝 可能不如预剪枝有效。一 般 地 ,为了寻求最佳模型可以同时使用两种剪枝技术。

下节将重用部分巳有的树构建代码来创建一种新的树。该树仍采用二元切分,但叶节点不再 是简 单的数值,取而代之的是一些线性模型。

在文檔中 关 于 封 面 (頁 171-174)