4.3 试编程实现基于信息熵进行划分选择的决策树算法,并为表4.3中的数据生成一颗决策树。
刚开始看到这一章时感觉这些内容都很好理解,算法也很直观,然而真到编程的时候发现有点编不下去,所以一直看到了集成学习这一章才发现真是到了不得不编的时候了,说实话,我感觉这一章的算法实现起来真的很麻烦。
(1)首先就是怎么分出连续属性和离散属性来计算信息熵,这个我只能先对数据进行预处理:让离散属性的取值转换为整数(1,2,3),而把全部连续属性放在离散属性最后面;
(2)然后,就是对所有属性进行遍历,计算相应的信息熵;
(3)接着选取最大信息熵对应的属性(在做到快完工时突然发现我的决策树的划分节点有一个和书上的不一样,就是触感那个节点,我当时的节点是连续属性里面的一个(具体是含糖率还是密度,我忘了),排查发现,理论上,这里选取这两个属性都可以达到最大信息增益(松了一口气,我还以为前面算法实现出错了),为了强行和书上一样,我加了一条属性选取规则,即离散属性优于连续属性(数据较少的时候连续属性的划分点不够精确,不如离散属性可靠,不知道这样强行解释有没有错。。。),并获取在此属性下当前数据集合中各个属性取值对应的数据子集;
(4)接下来,利用书上的递归算法,用字典的形式存储决策树的内容;
(5)最后,根据输出的决策树,绘图表示出来(要是看决策树只能看到一个字典,那真是太反人类了,然而这个时候发现我的水平貌似还不能用matplotlib轻易搞定,而且看网上大神们的答案,貌似matplotlib弄出来的也比较丑XD。于是我用了igraph来画这个决策树)。
下面附上相应代码和出来的图(虽然还是有不美观,不过已经能看了):
# -*- coding: utf-8 -*-
# exercise 4.3: 基于信息熵的决策树算法
import numpy as np
import igraph as ig
from collections import Counter
def all_class(D): # 判断D中类的个数
return len(np.unique(D[:,-1])) # np.unique用以生成具有不重复元素的数组
def diff_in_attr(D,A_code): # 判断D中样本在当前A_code上是否存在属性取值不同,即各属性只有一个取值
cond = False
for i in A_code[:-2]: # continuous args are excluded
if len(np.unique(D[:,i])) != 1:
cond = True