>>> m y D a t [ 0 ] [ - l ] = ' m a y b e '
>>> m y D a t
[[1, 1, 'm a y b e 1], [1, l, ' y e s 1], [1, 0, 'no 1], [0, 1, 'n o '], [0, 1, 'no']]
>>> t r e e s .c a l c S h a n n o n E n t (myDat) 1 . 3 7 0 9 5 0 5 9 4 4 5 4 6 6 8 7
得 到 熵之后,我们就可以按照获取最大信息增益的方法划分数据集,下一节我们将具体学习 如何划分数据集以及如何度量信息增益。
另一个度量集合无序程度的方法是基尼不纯度
$ ( 0
如impurity
) , 简单地说就是从一个数据 集中随机选取子项,度量其被错误分类到其他分组里的概率。本书不采用基尼不纯度方法,这里 就不再做进一步的介绍。下面我们将学习如何划分数据集,并创建决策树。3 . 1 . 2 划分数据集
上节我们学习了如何度量数据集的无序程度,分类算法除了需要测量信息熵,还需要划分数 据 集 ,度量花费数据集的熵,以便判断当前是否正确地划分了数据集。我们将对每个特征划分数 据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集是最好的划分方式。想象一个分 布在二维空间的数据散点图,需要在数据之间划条线,将它们分成两部分,我们应该按照
1
轴还 是少轴划线呢?答案就是本节讲述的内容。要划 分数据集,打开文本编辑器,在
& ^ 8 ^ 7
文件中输人下列的代码:程序清单
3 - 2
按照给定特征划分数据集d e f s p l i t D a t a S e t ( d a t a S e t , axis, v a l u e ) :
r e t D a t a S e t = [] <~~~\
f o r f e a t V e c i n d a t a S e t : 办创建新的此丨对象
if f e a t V e c [axis] == v a l U e :
r e d u c e d F e a t V e c = f e a t V e c [:axis]
r e d u c e d F e a t V e c .e x t e n d { f e a t V e c [ a x i s + l :]) r e t D a t a S e t .a p p e n d ( r e d u c e d F e a t V e c ) r e t u r n r e t D a t a S e t
程序清单
3-2
的代码使用了三个输人参数:待划分的数据集、划分数据集的特征、特征的返 回值。需要注意的是,?7 & 01^
吾言不用考虑内存分配问题。?7
出01^吾言在函数中传递的是列表的 引 用 ,在函数内部对列表对象的修改,将会影响该列表对象的整个生存周期。为了消除这个不良 影 响 ,我们需要在函数的开始声明一个新列表对象。因为该函数代码在同一数据集上被调用多次,为了不修改原始数据集,创建一个新的列表对象
0
。数据集这个列表中的各个元素也是列表,我 们要遍历数据集中的每个元素,一旦发现符合要求的值,则将其添力卩到新创建的列表中。在1£
语 句 中 ,程序将符合特征的数据抽取出来
©
。后面讲述得更简单,这里我们可以这样理解这段代 码 :当我们按照某个特征划分数据集时,就需要将所有符合要求的元素抽取出来。代码中使用了 卩一“
七吾言列表类型自带的战^ ^ ^
和可^
时丨丨方法。这两个方法功能类似,但是在处理多个 列 表 时 ,这两个方法的处理结果是完全不同的。J d
抽取① 要 了 解 更 多 信 息 ,请 参 考 Pan-Ning Tan, Vipin Kumar and Michael Steinbach , Introduction to Data Mining. Pearson Education (Addison-Wesley, 2005), 158.
38
第3
章 决 策 树3 . 1
决策树的构造39
征 ,划分数据集,计算得出最好的划分数据集的特征。函数也0036863匕?03七肛61103口11^ ( > 使 用了程序清单3-1和程序清单3-2中的函数。在函数中调用的数据需要满足一定的要求:第一个要 求 是 ,数据必须是一种由列表元素组成的列表,而且所有的列表元素都要具有相同的数据长度;第二个要求是,数据的最后一列或者每个实例的最后一个元素是当前实例的类别标签。数据集一 旦满足上述要求,我们就可以在函数的第一行判定当前数据集包含多少特征属性。我们无需限定 1如中的数据类型,它们既可以是数字也可以是字符串,并不影响实际计算。
在开始划分数据集之前,程序清单
3-3
的第3
行代码计算了整个数据集的原始香农熵,我们保 存最 初的 无序度量值,.
用于与划分完之后的数据集计算的嫡值进行比较。第1
个 化 :循 环 遍 历 数 据集中的所有特征。使 用 列 表 推 导(List Comprehension)
来创建新的列表,将数据集中所有第丨 个特征值或者所有可能存在的值写人这个新1
化中0
。然后使用?7
出《^
吾言原生的集合(北0
数据 类 型 。集合数据类型与列表类型相似,不同之处仅在于集合类型中的每个值互不相同。从列表中 创建集合是?7
也01^
吾言得到列表中唯一元素值的最快方法。遍历当前特征中的所有唯一属性值,对每个特征划分一次数据集©,然后计算数据集的新熵 值 ,并对所有唯一特征值得到的熵求和。信息增益是熵的减少或者是数据无序度的减少,大家肯 定对于将熵用于度量数据无序度的减少更容易理解。最 后 ,比较所有特征中的信息增益,返回最 好特征划分的索引值
0
。现在我们可以测试上面代码的实际输出结果,首先将程序清单3-3的内容输人到文件加% ?7 中 ,然后在?声匕00命令提示符下输人下列命令:
>>> r e l o a d (trees)
< m o d u l e ' t r e e s 1 f r o m 1 t r e e s . p y 1>
>>> m y D a t,l a b e l s = t r e e s .c r e a t e D a t a S e t ()
>>> t r e e s .c h o o s e B e s t F e a t u r e T o S p l i t (myDat) 0
>>> m y D a t
[[1, 1, 'yes'] , [1, 1, 'yes'] , [1, 0, ' n o ' ] , [0, 1, 1 n o ' ] , [0, 1, ' n o ']]
代码运行结果告诉我们,第
0 ^
特征是最好的用于划分数据集的特征。结果是否正确呢?这个 结果又有什么实际意义呢?数据集中的数据来源于表3-1
,让我们回头再看一下表1-
域 者 变 量 呵0
社 中的数据。如果我们按照第一个特征属性划分数据,也就是说第一个特征是1
的放在一个组,第一 个特征是0
的放在另一个组’
数据一致性如何?按照上述的方法划分数据集,第一个特征为1
的海洋 生物分组将有两个属于鱼类,一个属于非鱼类;另一个分组则全部属于非鱼类。如果按照第二个特 征分组,结果又是怎么样呢?第一个海洋动物分组将有两个属于鱼类,两个属于非鱼类;另一个分 组则只有一个非鱼类。如果不相信目测结果,读者可以使用程序清单3-1
的^ 1 0 3
匕31
瓜0
旭1
^ 叩 丫()
函数测试不同特征分组的输出结果。
本节我们学习了如何度量数据集的信息熵,如何有效地划分数据集,下一节我们将介绍如何 将这些函数功能放在一起,构建决策树。
3 . 1 . 3 递归构建决策树
目前我们已经学习了从数据集构造决策树算法所需要的子功能模块,其工作原理如下:得到
第一个结束条件使得算法可以终止,我们甚至可以设置算法可以划分的最大分组数目。后续 章节还会介绍其他决策树算法,如04.5和0六 虹 ,这些算法在运行时并不总是在每次划分分组时 都会消耗特征。由于特征数目并不是在每次划分数据分组时都减少,因此这些算法在实际使用时 可能弓1起一定的问题。目前我们并不需要考虑这个问题,只需要在算法开始运行前计算列的数目,
查看算法是否使用了所有属性即可。如果数据集已经处理了所有属性,但是类标签依然不是唯一 的 ,此时我们需要决定如何定义该叶子节点,在这种情况下,我们通常会采用多数表决的方法决 定该叶子节点的分类。
打 开 文 本 编 辑 器 ,在 增 加 下 面 的 函 数 之 前 ,在的⑵
^
乂 文 件 顶部 增加一行 代码:import o p e r a t o r ,
然后添加下面的代码到加68
仍 文 件 中 :def m a j o r i t y C n t ( c l a s s L i s t) : c l a s s C o u n t = { }
f o r v o t e in c l a s s L i s t :
if v o t e n o t in c l a s s C o u n t . k e y s ( ) : c l a s s C o u n t fvote] = 0 c l a s s C o u n t [vote] += 1
s o r t e d C l a s s C o u n t = s o r t e d ( c l a s s C o u n t .i t e r i t e m s (), k e y = o p e r a t o r .i t e m g e t t e r (1), r e v e r s e = T r u e )
r e t u r n s o r t e d C l a s s C o u n t [0][0]
40
第3
章 决 策 树原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于 两个分支的数据集划分。第一次划分之后,数据将被向下传递到树分支的下一个节点,在这个节 点 上 ,我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。
递归结束的条件是:程序遍历完所有划分数据集的属性,或者每个分支下的所有实例都具有 相同的分类。如果所有实例具有相同的分类,则得到一个叶子节点或者终止块。任何到达叶子节 点的数据必然属于叶子节点的分类,参见图3-2所示。
^
^ Y6 s N0 NO NO
NoYej Ye{Ye<
No No
3 . 1
决策树的构造41
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = s e t {featValues)
42
第3
章 决 策 树>>> r e l o a d (trees)
< m o d u l e 1t r e e s 1 f r o m 1 t r e e s . p y c 1>
>>> m y D a t , l a b e l s = t r e e s .c r e a t e D a t a S e t () '
>>> m y T r e e = t r e e s . c r e a t e T r e e (myDat,labels)
>>> m y T r e e
{■no s u r f a c i n g' :
{o:
'no',1:
{'flippers':{0: '
no 1,1: '
y e s'}}}}
变 量 卿
^^
拍 包 含 了 很 多 代 表 树 结 构 信 息 的 嵌 套 字 典 ,从 左 边 开 始 ,第 一 个 关 键 字^^
surfaCing
是第一个划分数据集的特征名称,该关键字的值也是另一个数据字典。第二个关键字 是卩0 3
虹£&0^
叩特 征划 分的数据集,这 些 关 键 字 的 值 是 如3
此£ 3 &
叩节点的子节点。这些值 可能是类标签,也可能是另一个数据字典。如果值是类标签,则该子节点是叶子节点;如果值是 另一个数据字典,则子节点是一个判断节点,这种格式结构不断重复就构成了整棵树。本节的例 子 中 ,这棵树包含了3
个叶子节点以及2
个判断节点。本节讲述了如何正确地构造树,下一节将介绍如何绘制图形,方便我们正确理解数据信息的 内在含义。