概述
决策什么是决策树
决策树(Decision Tree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。
![决策树样例](https://raw.githubusercontent.com/cocotwp/cocotwp.github.io/master/assets/images/决策树/决策树样例.png)
决策树算法的两个核心问题:
- 如何从数据表中找出最佳节点和最佳分枝?
- 如何让决策树停止胜场,防止过拟合?
sklearn 中的决策树
sklearn.tree
模块包含以下类:
tree.BaseDecisionTree | 基本决策树 |
tree.DecisionTreeClassifier | 分类树 |
tree.DecisionTreeRegressor | 回归树 |
tree.ExtraTreeClassifier | 高随机版本的分类树 |
tree.ExtraTreeRegressor | 高随机版本的回归树 |
tree.export_text 、 tree.export_graphviz 、 tree.plot_tree | 绘图 |
基本建模流程
from sklearn import tree
# 1. 实例化模型对象
clf = tree.DecisionTreeClassifier()
# 2. 用训练集数据训练模型
clf = clf.fit(x_train, y_train)
# 3. 验证测试集
result = clf.score(x_test, y_test)
建模案例
DecisionTreeClassifier
class sklearn.tree.DecisionTreeClassifier(*, criterion=’gini’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, class_weight=None, ccp_alpha=0.0)
重要参数
criterion
criterion:{"gini", "entropy"}, default="gini"
为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法,对分类树来说,衡量这个“最佳”的指标叫做“不纯度”。现在使用的决策树算法在分枝方法上的核心大多是围绕在某个不纯度相关指标的最优化上。
sklearn 提供了两种选择:信息熵(Entropy)、基尼系数(Gini Impurity)
\[Entropy(t)=-\sum_{i=0}^{c-1}p(i|t)log_2p(i|t)\] \[Gini(t)=1-\sum_{i=0}^{c-1}p(i|t)^2\]其中 t 代表给定的节点,i 代表标签的任意分类,\(p(i\|t)\) 代表标签分类 i 在节点 t 上所占的比例。注意,当使用信息熵时,sklearn 实际计算的是基于信息熵的信息增益(Information Gain),即父节点的信息熵和子节点的信息熵之差。
比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。
random_state
random_state{int, RandomState instance or None}, default=None
random_state
用来设置分枝中的随机模式的参数,默认 None,对高维度数据随机性会表现更明显,而对低维度数据(比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。
splitter
splitter:{"best", "random"}, default="best"
splitter
也是用来控制决策树中的随机选项的,有两种选项,选择“best”时,决策树在分枝时虽然随机,但是还是会优先选择更重要的的特征进行分枝;选择“randon”时,决策树在分枝时会更加随机。
树会因为含有更多的不必要信息而降低对训练集的拟合,这也是防止过拟合的一种方式。
剪枝参数
在不加限制的情况下,一颗决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止,这样的决策树往往会过拟合。
为了让决策树有更好的泛化性,我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。
max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉。
min_samples_leaf & min_samples_split
min_samples_leaf
限制,一个节点在分枝后的每个子节点都必须包含至少 min_samples_leaf 个训练样本,否则分枝就不会产生,或者,分枝会朝着满足每个子节点都包含 min_samples_leaf 个样本的方向去发生。
min_samples_split
限制,一个节点必须包含至少 min_samples_split 个训练样本,这个节点才允许被分枝,否则分枝就不会发生。
max_features & min_impurity_decrease
max_featrues
限制分枝时考虑的特征个数,超过限制的个数的特征都会被舍弃。在不知道决策树中的各个特征的重要性的情况下,强行设定可能会导致模型学习不足。
min_impurity_decrease
限制信息增益的大小,信息增益小于设定值的分枝不会发生。(替代旧版本的 min_impurity_split
)
思考:
- 剪枝参数一定能够提升模型在测试集上的表现吗? 调参没有绝对的答案,一切都是看数据本身。
- 这么多参数,一个个画学习曲线? 在泰坦尼克号的案例中,我们会解答这个问题。
目标权重参数
在样本不平衡的情况下, 我们要使用 class_weight
参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。这时,还需要搭配 min_weight_fraction_leaf
这个基于权重的剪枝参数来使用。
其他重要接口
apply
中输入测试集中返回每个测试样本所在的叶子节点的索引。
predict
输入测试集返回每个测试样本的标签。
小结
至此,我们已经学完了分类树 DecisionTreeClassifier
和用决策树绘图(export_graphviz)的所有基础。
- 八个参数:
Criterion
,随机参数(random_state
,splitter
),剪枝参数(max_depth
,min_samples_split
,min_samples_leaf
,max_feature
,min_impurity_decrease
) - 一个属性:
feature_importances_
- 四个接口:
fit
,score
,apply
,predict
DecisionTreeRegressor
class sklearn.tree.DecisionTreeRegressor(*, criterion=’squared_error’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, ccp_alpha=0.0)
几乎所有参数、属性及接口都和 [[2022-02-14-决策树#DecisionTreeClassifier|分类树]] 一致。需要注意的是,在回归树中,没有标签分布是否均衡的问题,因此没有 class_weight 这样的参数。
重要参数、属性和接口
criterion
回归树计算不纯度的方法有三种:
- squared_error,使用均方误差 mean squared error(MSE),父节点和叶节点之间的均方误差的差额将被用来作为特征选择,这种方法通过使用叶节点的均值来最小化 L2 损失。
- friedman_mse,使用费尔德曼均方误差,这种指标使用费尔德曼针对潜在分枝种的问题改进后的均方误差。
- absolute_error,使用绝对平均误差 mean absolute error,这种指标使用叶节点的中值来最小化 L1 损失。
- poisson,使用泊松偏差 Poisson deviance。
属性中最重要的依然是 feature_importances_
,接口依然是 apply
,fit
,predict
,score
最核心。
其中 N 是样本数量,i 是样本序号,\(f_i\) 是模型回归出的数值,\(y_i\) 是样本点 i 实际的数值标签。在回归树中,MSE 不只是我们的分枝质量衡量标准,也是我们最常用的衡量回归树质量的指标。
然而,回归树的接口 score
返回的是 R平方,并不是 MSE。R平方的定义如下:
其中 u 是残差平方和(MSE*N),v 是总平方和,\(f_i\) 是模型回归出的数值,\(y_i\) 是样本点 i 实际的数值标签,\(\hat{y}\) 是实际数值标签的平均数。
交叉验证
我们讲数据划分为 n 份,依次使用其中一份作为测试集,其他 n-1 份作为训练集,多次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,因此用交叉验证 n 次的结果求出的平均值,是对模型效果的一个更好的度量。
实例:一维回归树的绘制
# 导入库
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
# 创建一条含有噪声的正弦曲线
rng = np.random.RandomState(1)
X = np.sort(5 * rng.rand(80,1), axis=0)
y = np.sin(x).ravel()
y[::5] += 3 * (0.5 - rng.rand(16))
# 实例化&训练模型
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)
# 测试集导入模型,预测结果
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
# 绘图
plt.figure()
plt.scatter(X, y, s=20, edgecolors="black", c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()
结果图像:
![一维回归树的绘制](https://raw.githubusercontent.com/cocotwp/cocotwp.github.io/master/assets/images/决策树/一维回归树的绘制.png)
分析:
可见,如果树的深度(max_depth)过大,决策树可能会从训练数据中学到过多细节(包括噪声),从而使模型偏离真实的正弦曲线,形成过拟合。
实例:泰坦尼克号幸存者的预测
泰坦尼克号的沉没是世界上最严重的海难事故之一,今天我们通过分类树模型来预测一下哪些人可能成为幸存者。 数据集来自 kaggle
决策树的优缺点
优点
- 易于理解和解释
- 需要很少的数据准备(但请注意,sklearn 中的决策树模块不支持对缺失值的处理)
- 使用决策树的成本是用于训练树的样本点的数量的对数(相对其他算法,成本很低)
- 能够同时处理分类和数值数据,既可以做分类树又可以做回归树
- 能够处理多输出问题,即含有多个标签的问题
- 是一个白盒模型,结果很容易能够被解释
- 即使其假设在某种程度上违反了生成数据的真实模型,也能够表现良好
缺点
- 决策树学习者可能创建过于复杂的树,这些树不能很好地推广数据,称为过拟合。修剪是避免此问题所必需的,而参数的整合和调整对初学者来说会比较晦涩。
- 决策树可能不确定,数据中微小的变化可能导致生成完全不同的树,这个问题需要集成算法来解决。
- 决策树的学习是基于贪婪算法,它靠优化局部最优来试图达到整体的最优,但这种做法不能保证返回全局最优决策树。这个问题也可以由算法来解决,在随机森林中,特征和样本会在分枝过程中被随机采样。
- 有些特征很难学习,因为决策树不容易表达它们,例如 XOR,奇偶校验或多路复用器问题。
- 如果标签中的某些类占主导地位,决策树学习者会创建偏向主导类的树。因此,建议在拟合决策树之前平衡数据集。