前面三天推送了决策树的基本原理和选择最佳分裂特征的几种公式,用到决策树一般都会出现过拟合问题,因此需要对决策树进行剪枝,阐述了常用的几种剪枝的方法(这些方法都出现在了sklearn的决策树构造函数的参数中),后面总结了sklearn调包分析用决策树做分类和回归的几个例子,下面通过一个简单的例子,提炼出构建一棵分类决策树的算法思想,进一步体会下决策树的分类原理。
有一堆苹果,现在要分析下哪些苹果是好的,哪些是坏的,主要根据三个特征:大小,颜色,和形状进行区分。其中大小这个特征的取值:大和小;颜色特征的取值为:红色和青色;形状的取值有:圆形和非规则。现在拿到一批已检验的数据:
编号 大小 颜色 形状 好果
1 大 红色 圆形 是
2 大 红色 非规则 是
3 大 红色 圆形 是
4 大 青色 圆形 否
5 大 青色 非规则 否
6 小 红色 圆形 是
7 大 青色 非规则 否
8 小 红色 非规则 否
9 小 青色 圆形 否
10 小 青色 非规则 否
调用sklearn的API直接对上述结果分类,编写代码如下:
import numpy as np
from sklearn import tree
import graphviz
#大为1,红为1,圆形为1, 好果为1
data = np.array([[1,1,1,1],
[1,1,0,1],
[1,1,1,1],
[1,0,1,0],
[1,0,1,0],
[0,1,1,1],
[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,0]])
clf = tree.DecisionTreeClassifier()
clf.fit(data[:,0:3],data[:,3])
dot_data = tree.export_graphviz(clf, out_file=None,
feature_names=["magnitude","color","shape"],
class_names=["bad","good"],
filled=True, rounded=True,
special_characters=True)
graph = graphviz.Source(dot_data)
graph
得的的决策树如下所示,根节点选择的特征为颜色,并且判断条件为小于0.5,可以看出它是取值[0,1]的中间值作为不等式的判断条件,基尼系数为0.48,也就是说鱼龙混杂度还是挺大的,可以看到此时value有6个坏果>4个好果,所以这个根节点的类别被标记为坏果。
接下来根据属性的取值,分裂根节点,如果颜色是青色的,则得到一个叶节点,此时的基尼系数为0,说明得到的这类别是纯的,都为坏果,样本个数为5个。如果颜色是红色的,得到一个非叶节点,此时的基尼系数变小了一点,说明获得了一些信息增益。
第二步,我们去掉一个颜色特征,从大小和形状中选择一个最佳的特征进行分裂,结果选择形状作为第二个分裂特征,这个节点对应的样本中:1个坏果,4个好果,所以此节点标记为好果,然后根据其取值:如果形状为圆形,则获得一个叶节点,其所有3个果子都是好果,如果形状不规则,则
第三步,又得到一个非叶节点,它的基尼系数变为0.5,但是数量只有2个,则此时拿掉上一个用过的形状特征后,目前只剩下一个特征:大小,小的为坏果,对应的样本数为1的左叶节点,右叶节点为大的果子,则为好果。
至此,决策树根据基尼系数判断最佳特征的构建过程结束。
设数据集为T,属性集为 A,则生成决策树的过程可以标记为 treeBuilder(T,A):
-
生成节点node
-
如果T中样本属于同一类别,则将node标记为叶节点,递归返回。
-
如果A为空,将其标记为叶节点,并且此叶节点的类型为T中类型做多的样本(这种情况:应该只有一种类型了吧,如第2节的最深一层的两个叶节点,此时的属性都已用完,各自都只剩下自己那一类了),递归返回。
-
从属性集A中选择最优化分属性A*,sklearn选择最优的划分属性所用的算法是优化的CART算法。
-
对A*的最优划分属性的几个取值依次遍历:
如果 A*j(第j个取值)对应的在T中的子集合T_Sub个数大于0,则:
A = A-A*
递归调用 treeBuilder(T_Sub, A)
如果 T_Sub个数等于0,我们还需要添加一个节点吗?需要的,虽然在当前数据集上这个属性的样本点为空,并不代表在未来的测试集上这个属性对应的样本点还为空,这也是提高决策树的泛化能力的一个方法。
将这个节点为叶节点,并且这个叶节点的类型标记为T中样本点最多的那个类型,递归返回。
调用上述算法后,最终得到一个以node为根节点的决策树。
算法说明:
1. 递归返回的条件有3个:
-
T中样本属于同一类别;
-
可用属性为0
-
某个特征的第 j 个取值在T上的样本点个数为0
2. 需要理解递归返回的第3个条件,为什么训练集上出现个数为0时,还要构造一个叶节点,这是为了提高其泛化能力,并且此叶节点的类型标记为父节点的类型,这是把父节点的样本分布作为当前叶节点的先验分布。
让我们看一下远边优美的风景,放松一下吧!
4 总结
好了以上就是决策树的用于分类的总结,关于决策树做回归的问题,等以后对其更深刻地认识后再专门总结这块吧。
您知道先验概率和后验概率到底是怎么回事吗? 贝叶斯公式是怎么得来的? 它为什么能做分类呢?
明天通过2个易懂的来自于生活的小例子来阐述以上问题,欢迎您的关注!
谢谢您的阅读!
欢迎关注《算法channel》
交流思想,注重分析,看重过程,包含但不限于:经典算法,机器学习,深度学习,LeetCode 题解,Kaggle 实战,英语沙龙,定期邀请专家发推。期待您的到来!