实验原理
决策树 (decision tree) 是一种应用广泛的机器学习方法。顾名思义,决策树算法的表现形式可以直观理解为一棵树(可以是二叉树或非二叉树)。
一棵决策树一般包含一个根节点、一系列内部节点和叶节点,一个叶节点对应一个决策结果,一个内部节点则对应一个属性测试。
算法的目标是根据训练集中的样本和标签,自动生成一棵具有泛化能力的决策树。它反映了人对分类问题的判断过程,即类别的判断由对一系列特征的区分(属性测试)组成。
以二分类问题为例:我们在判断一间餐馆是不是好餐馆时,我们将会从它的某些特征来进行判断决定: 餐馆的菜品是否好吃?价格是否合理?服务态度是否良好?根据这些问题,我们可以构建一棵决策树,用以判断最终的问题:是不是一间好餐馆?但是,只考虑某个单一的属性进行提问并不能很好地对正类与负类进行划分,例如服务员态度好的餐馆不一定就好,也存在部分不好的餐馆符合这一判断。因此需要与其它特征一同进行综合判断。
决策树的算法在自动构建之后,能还原出每一项特征的具体划分标准。因此,决策树具有解释性较好的特点。
决策树算法的目标是根据由特征和标签组成的训练数据,自动生成一棵能对未见数据进行分类的决策树。
决策树算法学习的关键在于如何在每一次进行决策判断时选取到最优划分属性,其中一个基本的准则是:决策树按照某个属性进行划分后,得到的分支节点所包含的样本应该尽可能属于同一类别,相当于分类后同个分支节点所包含的样本类别”越纯“。而要达到这一点,我们需要一个衡量节点“纯度”的函数。 当某一属性划分的“纯度”最高时,我们选择对这一属性进行划分来建立下一个分支。理想的,通过对更多的属性进行划分,结点的 “纯度”会越来越高。现有的计算“纯度”的主流方法有:信息增益、增益率、基尼指数。
1.信息增益
信息增益的诞生基于“信息熵”的思想。“信息熵”(Information Entropy) 概念是由克劳德·香农(Claude Shannon) 于1948年提出,是一个以变量的不确定性来量化信息的指标。而在决策树算法的语境下,“信息熵”则可以看作是分类的不确定性,即进行某个属性进行划分之后,对叶节点中的样本类别的不确定程度。
信息熵的值越小,则样本的纯度越高。
当我们准备选择新的属性来建立分支时,就需要计算信息增益,即信息熵的变化。信息增益可以作为选择用以测试的属性,著名的 ID3 便是采用的是信息增益。
2.增益率
信息增益的最大缺点就是分叉越多,信息增益就越大,换句话说,它倾向于选择属性值比较多的特征来分叉。但是,有时这样的属性对分类器的泛化性是有害的。例如,假如我们将样本的“编号”也作为一种属性,即假如有
v
v
v个样本,这个属性就有
v
v
v个可能值。使用该属性进行测试则产生
v
v
v个分支,此时根据信息增益公式,得到的纯度提升非常大,但是却对分类模型性能没有实质提升,导致过拟合训练样本泛化性能低。因此另一个著名的决策树算法 C4.5 提出了“增益率”概念。
但是,增益率指标偏好于可能值较少的属性,因此有时也无法取得最佳效果。较好的方法可以将信息增益与增益率两种指标结合使用,例如先找出信息增益高于一定阈值的那些属性,再根据增益率的高低来筛选剩下的属性。
3.基尼指数
基尼指数是另一衡量经过划分的数据集纯度的指标,最先被 CART 决策树算法使用。由于其优异的性能及计算效率,这一指标被 sklearn 等实现作为默认的决策树属性选择指标。
直观上理解,基尼指数代表着从数据集中随机抽取的两个样本类别标记不一致的概率。因此基尼指数越小,则划分后的数据集纯度越高。因此与其它之前介绍的指标不同,我们选取基尼指数最小的属性作为最优划分属性。
4.剪枝处理
在决策树算法的训练中,往往可能会发生“过拟合”。也就是决策树为了提高划分数据集的纯度,生成过多的分支,但是每个分支下的叶节点仅有相当少的样本。符合该分支情况的样本可能并不会出现在实际测试数据中,而仅仅出现在训练集中。为了避免这种把训练集自身的一些特点当作所有数据都具有的普遍性质的有害做法,决策树需要进行“剪枝”操作。
决策树的剪枝操作可以分为两种——“预剪枝”和“后剪枝”:
(1)预剪枝:设定一些规则来避免树的过度生长。
信息增益(率)少于阈值就不再生长。
节点的样本数少于阈值(例如1%)就不再生长。
不允许叶子节点的样本数少于某个阈值(例如0.5%)。
不允许树的深度超过阈值(例如8层)。
(2)后剪枝:先让决策树无限的生长成一棵很大的树(这个时候肯定过拟合了),然后再剪枝。
从下往上依次判断:如果剪掉子树(把父节点作为叶子节点)能否让验证集的误差下降,如果可以,那么就减掉,不断重复此操作。
这里的关键问题就变成了:如何判断性能是否可以得到提升?这时就需要验证集的帮助。在进行是否要进行剪枝操作的判断时,使用一组没有出现在训练集中的数据,分别测试剪枝前后的决策树性能。
sklern中使用sklearn.tree.DecisionTreeClassifier类来实现决策树分类算法。其实几个典型的参数解释如下:
一、加载数据集
from sklearn.datasets import load_iris # 导入鸢尾花数据集
iris = load_iris() # 载入数据集
print('iris数据集特征')
print(iris.data[:10])
print('iris数据集标签')
print(iris.target[:10])
iris数据集特征
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
[4.6 3.1 1.5 0.2]
[5. 3.6 1.4 0.2]
[5.4 3.9 1.7 0.4]
[4.6 3.4 1.4 0.3]
[5. 3.4 1.5 0.2]
[4.4 2.9 1.4 0.2]
[4.9 3.1 1.5 0.1]]
iris数据集标签
[0 0 0 0 0 0 0 0 0 0]
二、配置模型
from sklearn import tree # 导入决策树包
clf = tree.DecisionTreeClassifier() #加载决策树模型
三、训练模型
将五分之四的数据集作为训练集对加载进来的决策树模型进行训练
clf.fit(iris.data[:120], iris.target[:120]) # 模型训练,取前五分之四作训练集
DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
max_depth=None, max_features=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort='deprecated',
random_state=None, splitter='best')
四、模型预测
将五分之一的数据集作为预测集,采用训练好的决策树模型对其进行预测
predictions = clf.predict(iris.data[120:]) # 模型测试,取后五分之一作测试集
predictions[:10]
array([2, 1, 2, 2, 2, 2, 1, 1, 2, 1])
五、模型评估
TP: 将正类预测为正类数 (预测正确) (正类)
FN: 将正类预测为负类数(预测错误)(正类)
FP: 将负类预测为正类数(预测错误)(负类)
TN: 将负类预测为负类数(预测正确)(负类)
TP+TN:预测结果正确的数量
TP+FP:预测结果为正类的数量
TP+FN:样本中所有的正类的数量
TP+TN+FP+FN:样本总数
我们采用准确率(accuracy)作为我们的评估函数:预测结果正确的数量占样本总数,(TP+TN)/(TP+TN+FP+FN)
from sklearn.metrics import accuracy_score # 导入准确率评价指标
print('Accuracy:%s'% accuracy_score(iris.target[120:], predictions))
Accuracy:0.7666666666666667
六、决策树调参
调参的这个参数一般指的是超参数。
简单来说,机器学习的目的是在一个假设空间中学到在损失意义下最接近真实函数的那个假设。
而超参数决定的是你在哪个假设空间进行学习。调参其实就是在选假设空间。
其中决策树可进行调整的超参数下图所示。
sklearn中的决策树包括若干个参数,其中每个参数对应的取值如注释所示。
接下来我们对几个参数进行调整作演示,以便大家对调参过程有一定的理解。接下来我们将对以下参数进行调整:criterion、max_depth。
1.criterion
该参数对应的三个函数对应我们上文讲过的信息增益,增益率和基尼系数,每个函数对应的评价指标有所不同,有各自的特点。接下来我们尝试将该参数进行更换为信息增益–entropy。
from sklearn.datasets import load_iris # 导入鸢尾花数据集
from sklearn import tree # 导入决策树包
from sklearn.metrics import accuracy_score # 导入准确率评价指标
iris = load_iris() # 载入数据集
clf = tree.DecisionTreeClassifier(criterion = 'entropy') #更换criterion参数
clf.fit(iris.data[:120], iris.target[:120]) # 模型训练,取前五分之四作训练集
predictions = clf.predict(iris.data[120:]) # 模型测试,取后五分之一作测试集
print('Accuracy:%s'% accuracy_score(iris.target[120:], predictions))
Accuracy:0.8
2.max_depth
该参数为树的最大深度,当样本中的特征较多时,设置适当的最大深度可以防止模型过拟合。接下来我们将尝试调整max_depth这个参数以达到模型更好的效果。
from sklearn.datasets import load_iris # 导入鸢尾花数据集
from sklearn import tree # 导入决策树包
from sklearn.metrics import accuracy_score # 导入准确率评价指标
iris = load_iris() # 载入数据集
clf = tree.DecisionTreeClassifier(max_depth=2) #更换max_depth参数
clf.fit(iris.data[:120], iris.target[:120]) # 模型训练,取前五分之四作训练集
predictions = clf.predict(iris.data[120:]) # 模型测试,取后五分之一作测试集
print('Accuracy:%s'% accuracy_score(iris.target[120:], predictions))
Accuracy:0.9