一 决策树
原理:分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node)和有向边(directed edge)组成。结点有两种类型:内部结点(internal node)和叶结点(leaf node)。内部结点表示一个特征或属性,叶结点表示一个类。而最上面的结点就是决策树的根结点(root node)。
决策树(decision tree)是一种基本的分类与回归方法,上图就是一个决策树。
长方形:decision block 判断模块
椭圆:terminating block 终止模块(表示已经得出结论,可以终止运行)
左右箭头:branch 分支
我们可以把决策树看成一个if-then规则的集合,由(root node)到(leaf node)的每一条路径构建一条规则;路径上内部结点的特征对应着规则的条件,而叶结点的类对应着规则的结论。决策树的路径:互斥并且完备。每一个实例都被一条路径或一条规则所覆盖,而且只被一条路径或一条规则所覆盖。
决策树过程:
- 收集数据:可以使用任何方法。比如想构建一个相亲系统,我们可以从媒婆那里,或者通过参访相亲对象获取数据。根据他们考虑的因素和最终的选择结果,就可以得到一些供我们利用的数据了。
- 准备数据:收集完的数据,我们要进行整理,将这些所有收集的信息按照一定规则整理出来,并排版,方便我们进行后续处理。
- 分析数据:可以使用任何方法,决策树构造完成之后,我们可以检查决策树图形是否符合预期。
- 训练算法:这个过程也就是构造决策树,同样也可以说是决策树学习,就是构造一个决策树的数据结构。
- 测试算法:使用经验树计算错误率。当错误率达到了可接收范围,这个决策树就可以投放使用了。
- 使用算法:此步骤可以使用适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。
二 构建决策树
这一过程可以概括为3个步骤:特征选择、决策树的生成和决策树的修剪。
2.1 最优特征选择
ID | 年龄 | 有工作 | 有自己的房子 | 信贷情况 | 类别(是否个给贷款) |
---|---|---|---|---|---|
1 | 青年 | 否 | 否 | 一般 | 否 |
2 | 青年 | 否 | 否 | 好 | 否 |
3 | 青年 | 是 | 否 | 好 | 是 |
4 | 青年 | 是 | 是 | 一般 | 是 |
5 | 青年 | 否 | 否 | 一般 | 否 |
6 | 中年 | 否 | 否 | 一般 | 否 |
7 | 中年 | 否 | 否 | 好 | 否 |
8 | 中年 | 是 | 是 | 好 | 是 |
9 | 中年 | 否 | 是 | 非常好 | 是 |
10 | 中年 | 否 | 是 | 非常好 | 是 |
11 | 老年 | 否 | 是 | 非常好 | 是 |
12 | 老年 | 否 | 是 | 好 | 是 |
13 | 老年 | 是 | 否 | 好 | 是 |
14 | 老年 | 是 | 否 | 非常好 | 是 |
15 | 老年 | 否 | 否 | 一般 | 否 |
特征选择就是决定用哪个特征来划分特征空间。选取对训练数据具有分类能力的特征。如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的。经验上扔掉这样的特征对决策树学习的精度影响不大。
通常特征选择的标准是信息增益(information gain)或信息增益比。
熵定义为信息的期望值。在信息论与概率统计中,熵是表示随机变量不确定性的度量。
Xi信息量:
熵: (熵越大,随机变量的不确定性就越大。)
训练数据集D的经验熵为H(D)(empirical entropy):
( 当熵中的概率由数据估计(特别是最大似然估计)得到时,称为经验熵。|D|表示其样本容量,及样本个数。设有K个类Ck,k = 1,2,3,···,K,|Ck|为属于类Ck的样本个数)
2.1.1 编写代码计算熵
1 from math import log #要用log函数需要import 2 '''创建数据集 3 dataset 数据集 4 labels 分类属性''' 5 def createdataset(): 6 dataset = [[0, 0, 0, 0, 'no'], #数据集 7 [0, 0, 0, 1, 'no'], 8 [0, 1, 0, 1, 'yes'], 9 [0, 1, 1, 0, 'yes'], 10 [0, 0, 0, 0, 'no'], 11 [1, 0, 0, 0, 'no'], 12 [1, 0, 0, 1, 'no'], 13 [1, 1, 1, 1, 'yes'], 14 [1, 0, 1, 2, 'yes'], 15 [1, 0, 1, 2, 'yes'], 16 [2, 0, 1, 2, 'yes'], 17 [2, 0, 1, 1, 'yes'], 18 [2, 1, 0, 1, 'yes'], 19 [2, 1, 0, 2, 'yes'], 20 [2, 0, 0, 0, 'no']] 21 labels = ['年龄', '有工作', '有自己的房子', '信贷情况','类别(是否给贷款)'] #分类属性 22 return dataset, labels #返回数据集和分类属性 23 '''计算熵''' 24 def shannon(dataset): 25 numlines = len(dataset) #返回数据的行数 样本数量 26 labelcount = {} #保存每个标签出现次数的字典 27 for feature in dataset: 28 currentlabel = feature[-1] 29 if currentlabel not in labelcount.keys(): 30 labelcount[currentlabel] = 0 31 labelcount[currentlabel] += 1 32 shannonent = 0.0 33 for key in labelcount: 34 prob = float(labelcount[key])/numlines 35 shannonent -= prob *log(prob,2) #log(pro,2) log以2为底,pro的对数 36 return shannonent 37 38 if __name__ == '__main__': 39 dataset,features = createdataset() 40 print(dataset) 41 print(shannon(dataset))
2.1.2 信息增益
条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性
同理,当条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的条件熵成为条件经验熵(empirical conditional entropy)。
信息增益是相对于特征而言的,信息增益越大,特征对最终的分类结果影响也就越大,我们就应该选择对最终分类结果影响最大的那个特征作为我们的分类特征。所以,特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即
(H(D|A)就是针对某一特征来计算的熵)
熵H(D)与条件熵H(D|A)之差称为互信息(mutual information)。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。
最后,比较特征的信息增益,由于特征A3(有自己的房子)的信息增益值最大,所以选择A3作为最优特征。
2.1.3 编写代码计算信息增益
1 from math import log 2 3 '''计算经验熵 4 dataset 数据集 5 shannonent 经验熵''' 6 7 def shannon(dataset): 8 samplesnumber = len(dataset) 9 labelcounts = {} 10 for feature in dataset: 11 currentlabel = feature[-1] 12 if currentlabel not in labelcounts: 13 labelcounts[currentlabel] = 0 14 labelcounts[currentlabel] += 1 15 shannonent = 0.0 16 for key in labelcounts: 17 prob = float(labelcounts[key])/samplesnumber 18 shannonent -= prob * log(prob,2) 19 return shannonent 20 21 '''创建测试数据集 22 dataset 数据集 23 labels 分类属性''' 24 25 def creatdataset(): 26 dataSet = [[0, 0, 0, 0, 'no'], # 数据集 27 [0, 0, 0, 1, 'no'], 28 [0, 1, 0, 1, 'yes'], 29 [0, 1, 1, 0, 'yes'], 30 [0, 0, 0, 0, 'no'], 31 [1, 0, 0, 0, 'no'], 32 [1, 0, 0, 1, 'no'], 33 [1, 1, 1, 1, 'yes'], 34 [1, 0, 1, 2, 'yes'], 35 [1, 0, 1, 2, 'yes'], 36 [2, 0, 1, 2, 'yes'], 37 [2, 0, 1, 1, 'yes'], 38 [2, 1, 0, 1, 'yes'], 39 [2, 1, 0, 2, 'yes'], 40 [2, 0, 0, 0, 'no']] 41 labels = ['年龄', '有工作', '有自己的房子', '信贷情况'] # 分类属性 42 return dataSet, labels # 返回数据集和分类属性 43 44 '''按照给定的特征进行划分数据集 45 dataset 待划分的数据集 46 axis 划分数据集的特征 47 value 需要返回的特征的值 48 ''' 49 def splitdataset(dataset,axis,value): 50 retdataset = [] 51 for featvec in dataset: 52 if featvec[axis] == value: 53 reducedfeatvec = featvec[:axis] #去掉axis特征 54 reducedfeatvec.extend(featvec[axis+1:]) #list.extend(anotherlist) 函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。 55 retdataset.append(reducedfeatvec) #定义了一个空列表,然后用append的方式,参数可以是列表(表中表)可以是元素对象 56 return retdataset #返回的是在 ==value时,去掉了特征值得列表 57 58 '''选择最优特征 59 dataset 数据集 60 bestfeature 信息增益最大的特征的索引值 61 ''' 62 def choosebestfeature(dataset): 63 numfeatures = len(dataset[0]) -1 #特征的数量 64 baseentropy = shannon(dataset) #计算数据集的熵 65 bestinfogain = 0.0 #信息增益 66 bestfeature = -1 67 for i in range(numfeatures): 68 #获取dataset的第i个所有的特征 69 featlist = [example[i] for example in dataset] #函数展开式 70 uniquevals = set(featlist) #创建set集合,元素不可重复 71 newentropy = 0.0 #计算信息增益 72 for value in uniquevals: #计算信息增益 73 subdataset = splitdataset(dataset,i,value) #筛选出的是等于value的列表,并去掉了该特征 74 prob = len(subdataset)/float(len(dataset)) #计算出的是该特征值出现的概率 75 newentropy += prob * shannon(subdataset) #pro *(在特定特征下的熵,即是否给予贷款的熵) 76 infogain = baseentropy - newentropy #信息增益 77 print('第%d个特征的增益为%.3f'%(i,infogain)) 78 if (infogain > bestinfogain): 79 bestinfogain = infogain 80 bestfeature = i 81 return bestinfogain,bestfeature 82 83 if __name__ =='__main__': 84 dataset,features = creatdataset() 85 print('最优特征索引值:' + str(choosebestfeature(dataset)))
三 决策树的生成和修剪
我们已经学习了从数据集构造决策树算法所需要的子功能模块,包括经验熵的计算和最优特征的选择,其工作原理如下:得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分。第一次划分之后,数据集被向下传递到树的分支的下一个结点。在这个结点上,我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。
构建决策树的算法有很多,比如C4.5、ID3和CART,这些算法在运行时并不总是在每次划分数据分组时都会消耗特征。由于特征数目并不是每次划分数据分组时都减少,因此这些算法在实际使用时可能引起一定的问题。目前我们并不需要考虑这个问题,只需要在算法开始运行前计算列的数目,查看算法是否使用了所有属性即可。
决策树生成算法递归地产生决策树,直到不能继续下去未为止。这样产生的树往往对训练数据的分类很准确,但对未知的测试数据的分类却没有那么准确,即出现过拟合现象。过拟合的原因在于学习时过多地考虑如何提高对训练数据的正确分类,从而构建出过于复杂的决策树。解决这个问题的办法是考虑决策树的复杂度,对已生成的决策树进行简化。