机器学习_决策树
分类是机器学习中的一类重要问题;分类算法是利用训练样本集获得分类函数即分类模型(分类器),从而实现将数据集中的样本划分到各个类中;分类模型是学习训练样本中属性集与类别之间的潜在关系,并以此为依据对新样本属于哪一类进行预测。
决策树是一种基于规则的方法,它用一组嵌套的规则进行预测,可用于分类问题和回归问题。在树的每个决策节点处,根据判断结果进入一个分支,反复执行这种操作直到叶子节点,得到预测结果。
文章目录
1. 树形决策过程
如上图,此过程就是一个决策树(通过机器训练得到)。从树的根节点(“年收入>20万元”)开始,在内部节点(“有房产”)处需要做判断,直到到达一个叶子节点(“可以贷款”or“不可以贷款”)处,得到决策结果。
决策树主要有以下四类(区分于树的结构与构造算法):
- ID3:
- 由罗斯.昆布提出,用来从数据集中生成决策树
- 在每个节点处选取能获得最高信息增益的分支属性进行分裂
- C4.5:
- 总体思路与ID3类似,其区别在于分支的处理:ID3使用信息增益作为度量,C4.5引入了信息增益率作为度量
- 与ID3算法相比,C4.5算法主要的改进是使用信息增益率作为分裂的度量标准;此外,针对ID3算法只能处理离散数据、容易出现过拟合等问题也提出了相应的改进
- C5.0:与C4.5相比具有以下优势:
- 决策树构建时间要比C4.5算法快上数倍,同时生成的决策树规模也更小,拥有更少的叶子节点数
- 使用了提升法boosting,组合多个决策树来做出分类,使准确率大大提高
- 提供可选项由使用者视情况来定
- CART:
- 二级循环分隔
2. 训练算法
建立决策树面临的问题:每个决策节点应该选择哪个分量做判定?选定特征后,判定的规则是什么?何时停止分裂?如何为叶节点赋予类别标签/回归值?
2.1 寻找最佳分裂
对于分类问题,要保证分裂之后左右子树地样本尽可能纯(它们的样本尽可能属于不相交的某一类或者几类),为此我们定义不纯度的指标(样本都属于某一类时不纯度为0;当样本均匀地属于每一类时不纯度最大);可通过下面三个指标判定不纯度:
-
熵不纯度:
E ( D ) = − Σ p i l o g 2 p i E(D)=-\Sigma p_i log_2 p_i E(D)=−Σpilog2pip i = N i N p_i=\frac {N_i}{N} pi=NNi
其中,N_i是第i类样本数,N为总样本数
熵用来度量一组数据包含的信息量的大小。当样本只属于某一类时熵最小,当样本均匀地分布于所有类时熵最大,因此,熵最小的分裂就是最佳分裂
缺陷:当分支属性取值非常多的时候,该分支属性的信息增益就会比较大,在ID3算法中,就会选择取值较多的分支属性,但是实际上,分支多的属性不一定是最优的,可能相比之下这种分支属性无法提供太多的可用信息
-
gini不纯度:
G ( D ) = 1 − Σ p i 2 = 1 − Σ N i 2 N 2 G(D)=1-\Sigma p_i^2=1-\frac {\Sigma N_i^2}{N^2} G(D)=1−Σpi2=1−N2ΣNi2p i = N i N p_i=\frac {N_i}{N} pi=NNi
其中,N_i是第i类样本数,N为总样本数
当样本只属于某一类时gini不纯度的值最小,为0,当样本均匀地分布于所有类时gini不纯度的值最大
-
误分类不纯度:
E ( D ) = 1 − m a x ( p i ) E(D)=1-max(p_i) E(D)=1−max(pi)p i = N i N p_i=\frac {N_i}{N} pi=NNi
其中,N_i是第i类样本数,N为总样本数
当样本只属于某一类时该值有最小值0,当样本均匀地分布于所有类时该值最大
以上为样本集的不纯度,我们要将其转换为分裂的不纯度:
G
=
N
L
N
G
(
D
L
)
+
N
R
N
G
(
D
R
)
G=\frac {N_L}{N}G(D_L)+\frac {N_R}{N}G(D_R)
G=NNLG(DL)+NNRG(DR)
其中,G(D_L)是左子集的不纯度,G(D_R)是右子集的不纯度,N是总样本数,N_L是左子集的样本数,N_R是右子集的样本数。
寻找最佳分裂时,需要计算用每个阈值对样本集进行分裂后的该值,其最小时对应的分裂就是最佳分裂。
2.2 叶子节点值的设定
如果不能继续分裂,则将该节点设置为子叶节点。
对于分类树,将叶子节点的值设置成本节点的训练样本集中出现概率最大的那个类。
2.3 属性缺失问题
属性缺失,即在某些情况下,样本特征向量中一些分量没有值。若出现属性缺失问题,可以:
- 剔除掉缺失该属性的样本,照常训练
- 替代分裂规则
- 对于每个决策树节点,除了计算出一个最佳的主分裂规则外,还会生成一个/多个替代分裂规则;若主分裂规则对应的属性缺失,则使用替代分裂规则进行判定
- 替代分裂规则应和主分裂规则尽可能相似,即,主分裂规则分到左边的样本使用替代分裂规则应尽可能分到左边,主分裂规则分到右边的样本使用替代分裂规则应尽可能分到右边
2.4 剪枝算法
如果决策树的结构过于复杂,可能会导致过拟合问题(详情见下3. 过拟合问题),需要对树进行剪枝,消除掉某些节点让它变得简单。决策树的剪枝算法可以分为两类:
- 预剪枝(在树的训练过程中通过停止分裂对书的规模进行限制):限制树的高度、节点的训练样本数、分裂所带来的纯度提升的最小值
- 后剪枝(先构造出一颗完整的树,再通过某种规则消除掉部分节点,用叶子节点代替):降低错误剪枝、悲观错误剪枝、代价-复杂度剪枝等等
2.5 训练算法的流程
def TrainDecisionTree(D): # D为本节点的训练样本集
if(样本集无法再分裂 or 达到最大树深度 or D的样本数小于指定阈值):
leafNode = CalcLeafValue(D) # 无法再分裂,设置为叶子节点,计算其值
return leafNode # 返回创建的叶子节点
else
(split, D1, D2) = FindBestSplit(D) # 寻找最佳分裂split,将训练集D分为D1和D2
node = CreateTreeNode() # 创建当前节点
node->split = split # 设置节点的分裂规则
FindSurrogateSplit(D) # 寻找替代分裂,加入到节点的分裂规则列表
node->leftChild = TrainDecisionTree(D1) # 递归训练左子树
node->rightChild = TrainDecisionTree(D2) # 递归训练右子树
return node # 泛化训练的树节点
如果需要做后剪枝处理,训练结束之后还要调用剪枝函数
2.6 计算变量的重要性
决策树可以输出特征分量的重要性,即每个特征分量对分类或回归的作用大小。
计算方法为:对每个特征分量在决策树中的分裂质量累加求和;这样做的依据是:如果一个变量在训练时被选来进行分裂则说明它对分类或者回归很重要,如果它用于分裂时的分裂质量很大,说明其对分类或者回归的贡献很大
3. 过拟合问题
通常,对于分类算法可能产生两种类型的误差:
- 训练误差/欠拟合:
- 代表此分类方法对于现有训练样本集的拟合程度
- 对于训练样本的拟合程度不够
- 可以通过增加分类属性的数量、选取合适的分类属性等方法,提高模型对于训练样本的拟合程度
- 泛化误差/过拟合:
- 代表此方法的泛化能力,即对于新的样本数据的分类能力如何
- 过度拟合训练数据,导致模型的泛化能力反而随着模型与训练数据的拟合程度增高而下降
- 在大量训练样本中难免会出现特例/噪音,如果在决策树构建过程中过度追求对于训练样本集的拟合程度,就会导致分类的泛化误差增大;另外,缺乏具有代表性的样本也会导致过拟合现象
过拟合:
- 泛化误差估计方法:
- 训练误差估计/再代入估计:估计效果不佳
- 结合模型复杂度估计:模型越复杂,其过拟合的可能性就越高
- 估计统计上限:依据多个训练误差形成地分布,选取统计结果的上限值来作为模型的泛化误差
- 使用检验集
- 解决方法(剪枝):
- 预剪枝(提前终止决策树的增长):
- 设置一个阈值,决策树层数大于阈值时停止生长
- 设置一个阈值,决策树节点中样本数小于阈值时停止生长
- 设置一个阈值,当决策算法中不纯度度量的增益低于阈值时,说明决策树的继续增长对于分类准确度提升已有限,此时停止增长
- 使用卡方检验,检验叶子节点中样本是否与剩余未使用特征的相互独立,若相互独立,则停止分支
- 后剪枝(思路更加复杂,也更为有效;先让决策树完全生长,之后针对子树判断,用叶子节点或者子树中最常用的分支替换子树,以此方式不断改进决策树,直至无法改进为止):
- 降低错误剪枝:思路清晰,简单快速;数据集较小时,效果有所下降
- 悲观错误剪枝:与上者相比,不需要构建一个单独的测试集
- 代价-复杂度剪枝:决策树常用
- 预剪枝(提前终止决策树的增长):
4. 案例
鸢尾花分类:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from pydotplus import graph_from_dot_data
from sklearn.model_selection import GridSearchCV
def iris_classify():
"""
对鸢尾花进行分类
:return:
"""
# 1. 获取数据
iris = load_iris()
iris_data = iris.data
data_list = []
for i in iris_data:
data_list.append([i[0], i[1]])
# 2. 划分数据集
x_train, x_test, y_train, y_test = train_test_split(data_list, iris.target, test_size=0.3, random_state=10)
# 3. 初始化决策树分类器
decisionTree = DecisionTreeClassifier(random_state=10, max_depth=3)
# 4. 训练决策树模型
decisionTree.fit(x_train, y_train)
# 5. 在测试集上进行预测
y_pred = decisionTree.predict(x_test)
# 6. 计算模型的准确率
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)
print(precision_score(y_test, y_pred, average='macro'))
print(recall_score(y_test, y_pred, average='macro'))
print(f1_score(y_test, y_pred, average='macro'))
# 决策树可视化
dot_data = export_graphviz(decisionTree, filled=True, rounded=True,
class_names=['Iris-Setosa', 'Iris-Versicolour', 'Iris-Virginica'],
feature_names=['sepal length', 'sepal width', 'petal length', 'petal width'],
out_file=None )
graph = graph_from_dot_data(dot_data)
graph.write_png('d:/tree.png')
return None
5. 应用
-
决策树实现简单、计算量小,具有很强的可解释性
-
训练得到的决策树模型能够可视化地显示出来,便于理解,这对某些数据的分析非常重要
-
它被成功地应用于经济和管理数据分析、疾病诊断、模式识别等各类问题
-
除单独使用外,决策树还作为弱分类器用于随机森林和Boosting等集成学习算法
6. 参考书目
[1] 赵卫东, 董亮. 机器学习. 北京: 人民邮电出版社, 2018.
[2] 雷明. 机器学习:原理、算法与应用. 北京: 清华大学出版社, 2019.
[3] 丁毓峰. 图解机器学习:算法原理与Python语言实现. 北京: 中国水利水电出版社, 2020.
[4] 刘袁缘, 李圣文, 方芳, 等. 机器学习应用实战. 北京: 清华大学出版社, 2022.
[5] 周志华. 机器学习. 北京: 清华大学出版社, 2016.