决策树可视化 库的下载和安装
https://www.jianshu.com/p/4f28335ee269
1.安装GraphViz
2.安装graphviz的python库
决策树简介
计算机中树的数据结构,第一层的节点又叫根节点,最后最下面的一层叫叶节点,其他的是属性节点(内部节点)
直观理解(决策树和KNN算法非常相似,所以也是能进行处理分类和回归的问题):
决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支(上级分支到下级分支的过程)代表一个测试输出,每个叶节点代表一种类别。决策树是一种十分常用的分类回归方法。
注:如果一些分支在分类的时候分出一个子节点能继续往下分,而另一个就已经到头得到答案了,那么这另一个节点就叫叶节点,而不是属性节点。
实际案例:
分类的情况下:
凯特想在某征婚网站上寻找自己的另一半,但她发现在海量的信息中筛选出值得见面的人比较繁琐。因此,凯特想建立一个模型,让模型帮自己从众多候选者中筛选出自己有意愿见面的对象。
做法:从网站里随机挑选了100个人,主要观察4个特征,并给出标记(是否见面)。然后凯特训练了一个决策树模型,通过模型对征婚网站上的人进行筛选
回归的情况下(外标签换成了一定的分值形式,而不是分类标签):
凯特想在某征婚网站上寻找自己的另一半,但她发现在海量的信息中筛选出值得见面的人比较繁琐。因此,凯特想建立一个模型,让模型帮自己从众多候选者中筛选出自己有意愿见面的对象。
做法:从网站里随机挑选了100个人,主要观察4个特征,并给出标记(这个男生在自己心里的打分)。然后凯特训练了一个决策树模型,通过模型对征婚网站上的人进行筛选
概述:
决策树结构
结点(node):内部结点和叶结点。内部结点=》特征;叶结点=》标签
有向边
分类决策树
叶结点=》类别
回归决策树
叶结点=》实数
使用:
决策树的预测
根结点开始,对实例的某一特征进行测试,根据测试结果将实例分配到其子结点,如此递归地对实例进
行判断并分配,直至达到叶结点。
叶结点对应什么?
分类:输出得票最多的类(K选择一定样本后,把每个样本分到指定的叶节点中,出现概率最大的那类叶节点就是预测数据的结果)
回归:输出样本标签的均值
注:可以将决策树看成一个if-else规则的集合。每一个实例只被一条路径所覆盖
起源介绍:
从历史上来说,决策树的起源非常早,甚至在有机器学习之前就有决策树了,因为决策树模仿的是人类在做决策的过程。在医药、商业的应用里,如何让电脑模仿人类做决策是一个很早的人工智能问题
决策树的构建包含了很多前人的巧思(启发式),但是为什么要这样做并没有什么理论保证,决策树的构建算法有上百种,没有人能说哪个好哪个不好,某些决策树算法流行起来,这些都是历史的选择。在Spark中实现了ID3算法和CART算法的决策树。
创建策略
构建方式:
第一步:确定评价决策树好坏的指标
第二步:列举出所有可能的决策树,然后计算各自的指标,从而选出最优的一棵树
注:决策树的根节点不同于KNN算法的根节点用来分界,而是要提前把大量不必要考量的数据给剔除,优化计算才是目的,从而需要有一种贪心策略
贪心策略:
贪心策略举例
思想:确定贪心指标,在候选方案集合中执行一个让贪心指标最大的方案。不会从全局最优的角度思考问题,近似求解,这个解可能是次优解(sub-optimal)
决策树的贪心指标
信息增益
候选方案集合(连续特征,离散特征)
连续特征:比如年龄中<10岁,<20岁,<30岁等等都可以是划分点。假设:5种方案
离散特征:
多叉树:直接按照不同特征值划分即可,比如长相里的丑,中等,帅。1种方案
二叉树:丑/中等帅,丑中等/帅,丑帅/中等,都是划分点。3种方案
连续特征和离散特征划分点取并集,5+1或5+3种方案
贪心指标设计:
注:在每个结点上去选择最优划分点
建树的方法论
让叶结点尽早变得更纯(如分类标签中1占比非常高)
不纯度指标:衡量不纯度的指标(纯度不能衡量时,可以衡量不纯的叶节点)
树结点内样本标签不一致的程度(比如样本在根节点时大部分都能满足要求用1表示,不能满足的用0表示,如果再进行下一级节点筛选的时候,不能满足的样本增多了,所有样本未被多层节点筛选剔除的用1表示,这时每一层级的节点的总样本满足程度就不同,如果都是1所有样本都能通过最后一层筛选,那么就是最高的纯度了)
纯度指标:衡量变纯程度的指标(信息增益)
划分前的不纯度为a,比如划分后产生两个结点,它们的不纯度分别为b和c,可以对其加权为B和C,那信息增益=a-(B+C)
建树过程
遍历全体划分点候选集,选择信息增益最大的划分点构建决策树,递归执行
度量指标(基尼指数和香农熵是度量分类的指标,均方误差是度量回归的指标):
基尼指数(分类):
两次抽取,拿到两个不同类别实例的概率,如果结点中实例是纯的,那么基尼指数=0(越小越纯,如二分类中正反类型一样是达到阈值,在比例二分类两个类型比例一样都是0.5时,基尼指数也到最高值)
香农熵(分类):
刻画不确定程度,如果结点中实例是纯的,那么香农熵=0
均方误差(回归):
结点内的均方误差(图像最小值表示最纯)
信息增益(增益越大,通过两层间不纯度的差值比较越大,纯度也就越大,表示纯度的提升程度):
信息增益 = 原来结点的不纯度 – 子结点不纯度的和
衡量结点不纯的指标(在度量指标的基础上的扩展出来的算法):
**ID3算法:**基于香农熵增益,缺点:会偏爱取值较多的特征(偏重特征某取值出现次数较多的那个值)
香农熵增益 = 结点的香农熵 – 子结点香农熵的带权和
**C4.5算法:**基于香农熵增益比,缺点:计算复杂度高
香农熵增益比 = 参数*香农熵增益 ps:某特征的特征值种类越多,那么参数越小。
**CART(分类和回归树的缩写)分类算法:**基于基尼指数增益
基尼指数增益 = 结点的基尼指数 – 子结点的基尼指数的带权和
**CART回归算法:**基于方差增益
方差增益 = 结点的方差 – 子结点的方差的带权和
注:ID3和C4.5只能用来分类,CART能做分类和回归
ID3、C4.5、CART分类树算法总结
ID3和C4.5算法均只适合在小规模数据集上使用
ID3和C4.5算法都是单变量决策树(只能用来分类)
当属性值取值比较多的时候,最好考虑C4.5算法,ID3得出的效果会比较差
决策树分类一般情况只适合小数据量的情况(数据可以放内存)
CART算法是三种算法中最常用的一种决策树构建算法。
三种算法的区别仅仅只是对于当前树的评价标准不同而已,ID3使用信息增益、C4.5使用信息增益率、CART使用基尼系数
CART算法构建的一定是二叉树,ID3和C4.5构建的不一定是二叉树(可能是多叉树)
这个贪心指标怎么设计?
第一步:设计衡量结点不纯度的指标
第二步:设计衡量变纯程度的指标(信息增益,贪心指标)
第三步:遍历全体划分点候选集,使用能让信息增益最大的划分点构建决策树。递归构建树,直到达到停止条件,完成整棵决策树的构建
候选集划分(选择怎样的分叉输出条件过程和选多少个分叉)
注:选择分叉输出条件,往往都是通过信息提纯,看上级节点到下级节点不纯度的最大值来筛选的,选最大不纯度就是要在通过分叉来最大化的剔除样本,这样才能更具代表性的通过分叉来分出各种类型的下层节点
划分类型:
连续特征F1有10种取值:1、2、3、4、5、6、7、8、9、10
离散特征F2有 4 种取值:A、B、C、D
连续特征:
如果是处理回归问题的话,候选集划分只能通过二叉树的形式分叉
离散特征——多叉树:
ID3算法采用的是多叉树分法(应用的是逻辑回归的交叉熵)
离散特征——二叉树:
CART树采用的二叉树分法(也是通过交叉熵和信息损失最少的时候,就是最优的候选集划分方式,这里用逆向思维理解,就是反例信息损失最少,肯定要正例概率最小,那么就可以理解正例保留的样本最少,传递到下一个层级的节点肯定是要最少的正例样本,那么这就是建立最优方式的过程)
划分过程会把所有的可能类型都计算一遍,损失最少的就是最优的
构建流程(连续型的属性只能做成二叉树形式)
演示建树过程:
现有训练集如下,请使用ID3算法训练一个决策树模型,对未来的西瓜的优劣做预测
在决策树开始学习时,根结点包含D中所有样例,|Y|=2,其中正例占p1=8/17,反例占p2=9/17。于是根节点的香农熵(算式和交叉熵相似)为:
全体划分点候选集:{色泽=?,根蒂=?…,触感=?}
思考:len(全体划分点候选集)=?
先计算“色泽”,根据色泽可以将数据集D分为3个子集(由于色泽中不是以数值做属性的,所以分叉个数为不同属性的类型数目):
D1:{1,4,6,10,13,17}(正例p1=3/6,反例占p2=3/6)
D2:{2,3,7,8,9,15} (正例p1=4/6,反例占p2=2/6)
D3:{5,11,12,14,16}(正例p1=1/5,反例占p2=4/5)
x1 x2 x3 label score
0 青绿 0.697 0.460 0 71
1 乌黑 0.774 0.376 0 92
2 乌黑 0.634 0.264 0 86
3 青绿 0.608 0.318 0 79
4 浅白 0.556 0.215 0 91
5 青绿 0.403 0.237 0 88
6 乌黑 0.481 0.149 0 85
7 乌黑 0.437 0.211 0 94
8 乌黑 0.666 0.091 1 31
9 青绿 0.243 0.267 1 22
先求得根节点的不纯度(这里的香农熵增益可以用不纯度来理解,和交叉熵有相似)
#计算根结点中label=0的占比 f1好瓜概率
f1 = 1.0*df[df["label"]==0].shape[0]/df.shape[0]
##计算根结点中label=1的占比
f2 = 1 - f1
##计算根结点香农熵
ent = -1 * f1*log_safe(f1) - f2*log_safe(f2)
print('ent:', ent)
计算x1=青绿的样本集合下香农熵
##获取x1=青绿的样本集合
df1 = df[df["x1"]=="青绿"]
##计算x1=青绿的样本集合下label=0的占比
f1 = 1.0*df1[df1["label"]==0].shape[0]/df1.shape[0]
##计算x1=青绿的样本集合下label=1的占比
f2 = 1 - f1
ent1 = -1 * f1*log_safe(f1) - f2*log_safe(f2)
print('ent1:', ent1)
计算香农熵增益
需要用根节点减去子节点的左右分叉的增益(即父节点减所属的所有子节点)
IG = ent - 1.0*df1.shape[0]/df.shape[0] * ent1 - 1.0*df2.shape[0]/df.shape[0] * ent2 - 1.0*df3.shape[0]/df.shape[0] * ent3
print(IG)
计算使用“色泽”划分数据集后的信息增益(根节点减去子节点的不纯度)
Gain(色泽)=Ent(D)—Ent(D)
类似地,计算出使用其他属性划分数据集后的信息增益
显然,选择“纹理”划分后信息增益最大,于是,通过“纹理”划分数据集
注:这里定义反例为纯度的标准,反例越多越纯,所以信息增益越大,证明在分叉过程引入的建树集合划分是越优的,同样是剔除最大的原理,不仅是单层的候选集划分要应用,多层的根节点或上级节点的选择都是要应用,都是要在前一步就要把能剔除的尽量都剔除掉。
每次建树之后,按照特征值将样本分配到对应结点,重复,便可得到完整的决策树
from sklearn.tree import DecisionTreeRegressor
#回归决策树,最大深度只有1层,因为是连续型的属性
model = DecisionTreeRegressor(max_depth=1)
#只针对x2数据和score进行拟合处理
print(model.fit(df[["x2"]], df["score"]))
构建伪代码(用代码来假设构建流程):
def buildTree:
初始化根结点
确定全体划分点候选集
for //反复建树
for (i<-splits){ //试探性结点分裂
按照特征将样本转移到对应子结点
记录划分点和对应的信息增益
}
选择信息增益最大的划分点
进行结点分裂
if 满足停止构造的条件
break
return 树
可视化实现决策树
from sklearn import tree
import pydotplus
# 输出图像, filled对旁边区域进行填充, rounded 环绕 , 节点中属性的显示special_characters
dot_data = tree.export_graphviz(model, out_file=None,
filled=True, rounded=True,
special_characters=True)
#通过节点方式,生成图像
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf('1.pdf')
graph.write_png('1.png')
剪枝处理
决策树的剪枝:
宽泛来讲:机器学习模型都会有过拟合风险,在训练集上表现的过于优秀,而泛化能力差,因此机器学习模型都有对应的防止过拟合的策略,决策树的策略就是剪枝
具体来讲:决策树生成算法会递归地建造决策树的分支,直到结点都很纯为止。这样产生的决策树往往对训练数据的分类很准确,但失去泛化能力,即发生过拟合了,因此,可通过主动去掉一些分支来降低过拟合的风险,提高模型泛化能力
过拟合处理:
如何判断模型是否过拟合?
可以看训练误差和测试误差的关系,测试误差越小,说明模型泛化能力越强
剪枝方法:
预剪枝(使用的较多):在决策树生成过程中,考察该轮划分是否会提高泛化性能,如果不能提高泛化性能就不划分
优点:性能开销小、速度快
缺点:可能会欠拟合,错过最优解
后剪枝:先训练一棵完整的树,然后自底向上地进行考察,如果删除该划分能提高泛化性能就删除
优点:欠拟合风险小
缺点:性能开销大、速度慢
Spark & sklearn
①树的深度等于超参数maxDepth (根节点以下的层数,maxDepth是一层层的剪到剩下多少层的方式)
②没有分裂点能带来大于minInfoGain的信息增益(minInfoGain不代表剪到某一层数,而是分叉不能达到指定增益就不能分叉出来)
③没有分裂点能让划分后的结点上至少有minInstances个实例(minInstances方式规定了分叉点分类数不能少于指定类型数目,否则就被剪掉)
效果:类似于剪枝
优点:性能开销小,求解速度快
缺点:可能会欠拟合
决策树模型优缺点:
优点(相当高级的算法):
易于解释
处理类别特征,其他的技术往往要求数据属性的单一
延展到多分类
不需要特征放缩(也不需要独热编码的操作,还可以不单独使用决策树,用于集成模型进行集成学习,构造随机森林)
能捕获非线性关系和特征间的交互关系
缺点:
寻找最优的决策树是一个NP-hard的问题,只能通过启发式方法求次优解
决策树会因为样本发生一点点的改动,就会导致树结构的剧烈改变
如果某些离散特征的特征值种类多,生成决策树容易偏向于这些特征 ID3
有些比较复杂的关系,决策树很难学习,比如异或
补充:from math import log2的2是以2为底,不带2要自行添加参数作底数
#方差var和协方差cov,在特征中的属性为连续值时,var用于CART回归算法
for i in range(1, df.shape[0]): # 遍历所有划分点
df1 = df.iloc[:i, :] # 获取左子树的样本
impurity1 = np.var(df1["score"]) # 计算左子树的不纯度(方差)
df2 = df.iloc[i:, :] # 获取右子树的样本
impurity2 = np.var(df2["score"]) # 计算右子树的不纯度(方差)
# 计算方差增益
a = impurity - (df1.shape[0] / df.shape[0] * impurity1 + df2.shape[0] / df.shape[0] * impurity2)
#max_depth 最大深度 过拟合
#min_samples_split 最小分支节点数量 过拟合
#min_samples_leaf 叶节点最小样本数 过拟合
导包:from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor