这是一篇《机器学习实战:基于Scikit-learn和TensorFlow》的学习笔记,如果有时间的话会考虑连课后题一起做一下。
决策树的训练与可视化
训练
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
iris = load_iris()
X = iris.data[:,2:]
y = iris.target
tree_clf = DecisionTreeClassifier(max_depth=2)
tree_clf.fit(X, y)
可视化
使用export_graphviz()方法输出一个图形定义文件
from sklearn.tree import export_graphviz
export_graphviz(
tree_clf,
out_file = image_path("iris_tree.dot"),
feature_name = iris.target_names[2:],
class_names = iris.target_names,
rounded = True,
failed = True
)
后续可以使用graphviz包的dot命令行工具将文件转为PDF或者PNG等格式。
$ dot -Tpng iris_tree.dot -o iris_tree.png
节点的samples属性统计它应用的训练实例数量,
value属性说明该节点上每个类别训练实例的数量,
gini属性衡量不纯度,又称基尼系数。
G
i
=
1
−
∑
k
=
1
n
p
i
,
k
2
G_{i}=1-\sum^{n}_{k=1}p_{i,k}^{2}
Gi=1−∑k=1npi,k2
上图深度2左侧节点的基尼不纯度等于
1
−
(
0
54
)
2
−
(
49
54
)
2
−
(
5
54
)
2
=
0.168
1-(\frac{0}{54})^{2}-(\frac{49}{54})^{2}-(\frac{5}{54})^{2}=0.168
1−(540)2−(5449)2−(545)2=0.168
scikit-learn用的是CART算法,仅生成二叉树,即问题的答案只有是和否两种。
CART
CART, Classification And Regression Tree, 分类与回归树。
基本思想:使用单个特征k和阈值
t
k
t_{k}
tk将训练集分成两个子集(如花瓣长度<=2.45厘米)
- k和
t
k
t_{k}
tk应该怎么选择?
产生出最纯子集的k和 t k t_{k} tk就是经算法搜索得到的最优解。 - 成本函数
J ( k , t k ) = m l e f t m G l e f t + m r i g h t m G r i g h t J(k,t_{k})=\frac{m_{left}}{m}G_{left}+\frac{m_{right}}{m}G_{right} J(k,tk)=mmleftGleft+mmrightGright
其中 G l e f t / r i g h t G_{left/right} Gleft/right衡量左/右子集的不纯度, m l e f t / r i g h t m_{left/right} mleft/right是左/右子集的实例数量。
一旦成功将训练集一分为二,它将使用相同的逻辑,继续分裂子集,以此循环,直到抵达最大深度(由超参数max_depth控制),或者是再也找不到能够降低不纯度的分裂,它才会停止。
还有一些超参数也用于控制停止条件:
min_samples_split, min_samples_leaf, min_weight_fraction_leaf, max_leaf_nodes)
- CART是一种贪婪算法:从顶层开始搜索最优分裂,然后每层重复这个过程。几层分裂之后,它并不会检视这个分裂的不纯度是否为可能的最低值。贪婪算法通常会产生一个相当不错的解,但是不能保证是最优解。
基尼不纯度与信息熵
算法默认使用基尼不纯度来进行测量,但也可以通过设置超参数criterion=entropy来选择信息熵作为不纯度的测量方法。
熵的概念源于热力学,是一种分子混乱程度的测量:如果分子保持静止和良序,则熵接近于0。后来这个概念传播到各个领域,其中包括香农的信息理论,它衡量的是一条信息的平均内容:如果所有的信息都相同,则信息熵为0。在机器学习中,它也经常被用作一种不纯度的测量方式:如果数据集中包含一个类别的实例,其熵为0。
信息熵的计算
H
i
=
−
∑
k
=
1
,
p
i
,
k
!
=
0
n
p
i
,
k
l
o
g
(
p
i
,
k
)
H_{i}=-\sum^{n}_{k=1,p_{i,k}!=0}p_{i,k}log(p_{i,k})
Hi=−∑k=1,pi,k!=0npi,klog(pi,k)
同样以上图深度2左侧节点为例,它的信息熵为
−
49
54
l
o
g
(
49
54
)
−
5
54
l
o
g
(
5
54
)
=
0.31
-\frac{49}{54} log(\frac{49}{54})-\frac{5}{54} log(\frac{5}{54})=0.31
−5449log(5449)−545log(545)=0.31
至于选择基尼不纯度还是信息熵,其实大多数情况下这二者差异并不大,生成的树十分相似。基尼不纯度的计算速度相对快一些,所以作为默认配置。它们的不同处在于,基尼不纯度倾向于从树枝中分裂出最常见的类别,而信息熵则倾向于生产更平衡的树。
正则化超参数
决策树极少对训练数据做出假设,如果不加以限制,树的结构将跟随训练集变化,严密拟合,并且很可能过度拟合。这种模型通常被称为非参数模型,这不是说它不包含任何参数,而是指在训练之前没有确定参数的数量,导致模型结构自由而紧密地贴近数据。
为了避免过度拟合,需要在训练过程中降低决策树的自由度。这个过程被称为正则化。
正则化超参数的选择取决于所使用的模型,在这里,至少能够通过最大深度max_depth来使模型正则化,降低过度拟合的风险。
其他超参数:
- min_samples_split:分裂前节点必须有的最小样本数
- min_samples_leaf:也节点必须有的最小样本数
- min_weight_fraction_leaf:最小加权实例总数
- max_leaf_nodes:最大叶节点数量
- max_features:分裂每个节点评估的最大特征数量
还可以:
先不加约束地训练模型,然后再对不必要的节点进行减枝。如果一个节点的子节点全部为叶节点,则该节点可被认为不必要,除非它所表示的纯度提升有重要的统计意义。
标准统计测试,比如
X
2
X^{2}
X2测试,是用来估算“提升纯粹是出于偶然”(虚假设)的概率。如果这个概率(p)高于一个给定的阈值(通常为5%,由超参数控制),那么这个节点可被认为不必要,其子节点可被删除。直到所有不必要的节点都被删除,剪枝过程结束。
不稳定性
决策树青睐正交的决策边界,这导致它们对训练集的旋转非常敏感。如下图先是了一个简单的先行可分离数据集:左图中决策树可以轻松分裂,右图,数据集旋转45度后,决策边界产生了不必要的卷曲。虽然这两个模型都看似完美拟合,但是右侧模型很可能泛化不佳。限制这种问题的方法之一是PCA,让训练数据定位在一个更好的方向上。
决策树的主要问题是,它们对训练数据中的小变化非常敏感。
事实上scikit-learn使用的算法是随机的,也就是说,即使在相同的训练数据上,也可能会得到不同的模型(除非对random_state进行设置)
随机森林通过对许多树的预测进行平均来限制了这种不稳定性。