前言
在上一篇文章中我们已经详细介绍基于ID3算法进行改良的C4.5算法以及决策树拟合度的优化问题,那这篇文章呢,则是介绍如何使用sklearn实现决策树。
当然,如果只是简单实现决策树的话,我是不可能单独拿出来写成一篇文章的,我会在本篇文章中详细地介绍到各种具体功能的代码实现,如剪枝等,同时重要的参数也一个都不会放过(hhh),而且文末也介绍了决策树模型的优缺点有哪些方面,真的是干货满满。
目录
- 前言
- 一、使用SK-LEARN实现决策树
- 1 参数CRITERION
- 2 初步建模
- 3 探索数据
- 4 画出一棵树
- 5 探索决策树属性
- 5.1 clf.feature_importances_
- 5.2 clf.apply
- 5.3 clf.tree_.node_count
- 5.4 clf.tree_.feature
- 6 防止过拟合
- 6.1 random_state & splitter
- 6.2 剪枝参数
- 6.2.1 max_depth
- 6.2.2 min_samples_leaf
- 6.2.3 min_samples_split
- 6.2.4 max_features
- 6.2.5 min_impurity_decrease
- 6.2.6 确认最优的剪枝参数
- 7 总结
- 二、决策树的算法评价
- 1 决策树优点
- 2 决策树缺点
- 结束语
一、使用SK-LEARN实现决策树
1 参数CRITERION
criterion 这个参数是用来决定不纯度的计算方法。sklearn 提供了两种选择:
- 输入 “entropy”,使用信息熵(Entropy)
- 输入 “gini”,使用基尼系数(Gini Impurity)
比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。
信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。
另外,因为信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长会更加 ”精细”,因 此对于高纬数据或者噪声很多的数据,信息熵很容易过拟合,基尼系数在这种情况下效果往往比较好。
当模型拟合程度不足时,即当模型在训练集和测试集上都表现不太好的时候,使用信息熵。当然,这些不是绝对的。
参数 | criterion |
---|---|
如何影响模型? | 确定不纯度的计算最佳结点和最佳分支,不纯度越低,决策树对训练集的拟合越好 |
可能的输入有哪些? | 不填默认为系数,填写gini使用基尼系数,填写entropy使用信息增益 |
怎样选取参数? | 通常就使用基尼系数;数据维度很大、噪音很大时使用基尼系数;维度低、数据比较清晰的时候,两者没区别;当决策树的拟合程度不够时,使用信息熵;两个都试试,不好就换另外一个 |
2 初步建模
# 导入需要的算法库和模块
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
plt.rcParams['font.sans-serif']=['Simhei']
plt.rcParams['axes.unicode_minus']=False
3 探索数据
wine = load_wine()
wine.data.shape
wine.target
这一部分是显示数据的标签,其中这些数据就是来源于sklearn.datasets。
wine_pd=pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1).head() # 合并特征和标签
wine.feature_names.append("result")
wine_pd.columns=wine.feature_names
wine_pd
在开始建模前,我们先划分一下数据集:
Xtrain, Xtest, Ytrain, ytest = train_test_split(wine.data,wine.target,test_size=0.3, random_state=420)
Xtrain.shape
Xtest.shape
(124, 13)
(54, 13)
接下来开始建模:
clf = tree.DecisionTreeClassifier(criterion="gini")
clf = clf.fit(Xtrain, Ytrain)
clf.score(Xtest, ytest) #返回预测的准确度
0.9444444444444444
(换成entropy的结果是0.9629629629629629)
4 画出一棵树
同时,我们可以利用 Graphviz 模块导出决策树模型。
第一次使用 Graphviz 之前需要对其进行安装:
- 先从官网下载msi文件进行安装;
- 安装完记得将安装好的目录下的bin目录添加到环境变量中;
- 在命令行界面使用下述指令进行安装:
pip install graphviz
接下来开始画图:
import matplotlib.pyplot as plt
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青 素','颜色强度','色调','od280/od315 稀释葡萄酒','脯氨酸']
import graphviz
dot_data = tree.export_graphviz(clf,
out_file = None,
feature_names= feature_name,
class_names=["琴酒","雪莉","贝尔摩德"],
filled=True,
rounded=True)
graph = graphviz.Source(dot_data)
graph
export_graphviz生成一个DOT格式的决策树:
- feature_names:每个属性的名字
- class_names:每个因变量类别的名字
- label:是否显示不纯度信息的标签,默认为"all"表都显示,可以是"root"或"none"
- filled:是否给每个结点的主分类绘制不同的颜色,默认为False
- out_file:输出的dot文件的名字,默认为None表示不输出文件,可以是自定义名字如"tree.dot"
- rounded:默认为Ture,表示对每个结点的边框加圆角,并使用Helvetica字体
5 探索决策树属性
5.1 clf.feature_importances_
显示每个特征重要性:
#显示每个特征的重要程度
clf.feature_importances_
想更好地显示可以用以下方式:
[*zip(feature_names,clf.feature_importances_)] # 这里使用[*]是因为jupyter上才显示得出来
5.2 clf.apply
返回每个预测样本的叶子索引:
clf.apply(xtrain)
5.3 clf.tree_.node_count
树的节点个数:
clf.tree_.node_count
13
5.4 clf.tree_.feature
每个节点对应的属性索引值,-2 表示叶节点:
clf.tree_.feature
array([ 9, 12, -2, -2, 6, 10, -2, -2, 12, 0, -2, -2, -2], dtype=int64)
6 防止过拟合
在不加限制的情况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止。这样的决策树往往会过拟合,这就是说,它会在训练集上表现很好,在测试集上却表现糟糕。我们收集的样本数据不可能和整体的状况完全一致,因此当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪声,并使它对未知数据的拟合程度不足。
#我们的树对训练集的拟合程度如何?
score_train = clf.score(Xtrain, Ytrain)
score_train
1.0
这个1.0是真的离谱对吧,绝对的过拟合。
所以为了让决策树有更好的泛化性,我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。
6.1 random_state & splitter
random_state
如果我们改动 random_state,画出来的每一棵树都不一样。它为什么会不稳定呢?如果使用其他数据集,它还会不稳定吗?
我们之前提到过,无论决策树模型如何进化,在分支上的本质都还是追求某个不纯度相关的指标的优化,而正如我们提到的,不纯度是基于节点来计算的,也就是说,决策树在建树时,是靠优化节点来追求一棵优化的树,但最优的节点能够保证最优的树吗?
集成算法被用来解决这个问题:sklearn 表示,既然一棵树不能保证最优,那就建更多的不同的树,然后从中取最好的。怎样从一组数据集中建不同的树?在每次分支时,不使用全部特征,而是随机选取一部分特征,从中选取不纯度相关指标最优的作为分支用的节点。这样,每次生成的树也就不同了。
random_state 用来设置分支中的随机模式的参数,默认 None,在高维度时随机性会表现更明显,低维度的数据(比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。
splitter
splitter 也是用来控制决策树中的随机选项的,有两种输入值:
- 输入”best",决策树在分支时虽然随机,但是还是会优先选择更重要的特征进行分支(重要性可以通过属性 feature_importances_查看);
- 输入“random",决策树在分支时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这也是防止过拟合的一种方式。
当你预测到你的模型会过拟合,用这两个参数来帮你降低树建立之后过拟合的可能性。当然,树一旦建成,我们依然是使用剪枝参数来防止过拟合。
clf = tree.DecisionTreeClassifier(criterion="entropy" ,
random_state=30 ,
splitter="random" )
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, ytest) score
plt.rcParams['font.sans-serif']=['Simhei']
plt.rcParams['axes.unicode_minus']=False
大家可以自行比较一下有设置和没设置参数模型的区别。
6.2 剪枝参数
6.2.1 max_depth
max_depth 限制树的最大深度,超过设定深度的树枝全部剪掉,一般用作树的”精修“ 。
这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。
实际使用时,建议从=3 开始尝试,看看拟合的效果再决定是否增加设定深度。
6.2.2 min_samples_leaf
一个节点在分支后的每个子节点都必须包含至少 min_samples_leaf 个训练样本,否则分支就不会发生, 或者,分支会朝着满足每个子节点都包min_samples_leaf 个样本的方向去发生。
一般搭配 max_depth 使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。
一般来说,建议从=5 开始使用。
如果叶节点中含有的样本量变化很大,建议输入浮点数作为样本量的百分比来使用。同时,这个参数可以保证每个叶子的最小尺寸,避免低方差,过拟合的叶子节点出现。
6.2.3 min_samples_split
一个节点必须要包含至少 min_samples_split 个训练样本,这个节点才允许被分支,否则分支就不会发生。
6.2.4 max_features
max_features 限制分支时考虑的特征个数,超过限制个数的特征都会被舍弃。 和 max_depth 异曲同工, max_features 是用来限制高维度数据的过拟合的剪枝参数,但其方法比较暴力,是直接限制可以使用的特征数量而强行使决策树停下的参数,在不知道决策树中的各个特征的重要性的情况下,强行设定这个参数可能会导致模型学习不足。
如果希望通过降维的方式防止过拟合,建议使用 PCA,ICA 或者特征选择模块中的降维算法。
6.2.5 min_impurity_decrease
min_impurity_decrease 限制信息增益的大小,信息增益小于设定数值的分支不会发生。这是在 0.19 版本中更新的功能,在 0.19 版本之前时使用 min_impurity_split。
6.2.6 确认最优的剪枝参数
那具体怎么来确定每个参数填写什么值呢?这时候,我们就要使用确定超参数的曲线来进行判断了,继续使用我们已经训练好的决策树模型 clf。
超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是 score。
test= []
for i in range(10):
clf = tree.DecisionTreeClassifier(criterion='entropy'
,max_depth=i+1 #最大深度
#,min_samples_leaf=5 #子节点包含样本最小个数(父节点)
#,min_samples_split=20
,random_state=30
,splitter='random'
) #生成决策树分类器 entropy
clf = clf.fit(Xtrain,Ytrain)
score = clf.score(Xtest,Ytest)
test.append(score)
plt.plot(range(1,11),test,color='red')
plt.ylabel('score')
plt.xlabel('max_depth')
plt.xticks(range(1,11))
plt.show()
思考:
- 剪枝参数一定能够提升模型在测试集上的表现吗? - 调参没有绝对的答案,一切都是看数据本身。
- 这么多参数,一个个画学习曲线? - 这个在以后的案例中会解决。
无论如何,剪枝参数的默认值会让树无尽地生长,这些树在某些数据集上可能非常巨大,对内存的消耗也非常巨大。
所以如果你手中的数据集非常巨大,你已经预测到无论如何你都是要剪枝的,那提前设定这些参数来控制树的复杂性和大小会比较好。
7 总结
属性是在模型训练之后,能够调用查看的模型的各种性质 。对决策树来说,最重要的是feature_importances_,能够查看各个特征对模型的重要性。
sklearn 中许多算法的接口都是相似的,比如说我们之前已经用到的 fit 和 score,几乎对每个算法都可以使用。除了这两个接口之外,决策树最常用的接口还有 apply 和 predict。
apply 中输入测试集返回每个测试样本所在的叶子节点的索引。
predict 输入测试集返回每个测试样本的标签。返回的内容一目了然并且非常容易,大家感兴趣可以自己下去试试看。
在这里不得不提的是,所有接口中要求输入 Xtrain 和 Xtest 的部分,输入的特征矩阵必须至少是一个二维矩阵。 sklearn 不接受任何一维矩阵作为特征矩阵被输入。如果你的数据的确只有一个特征,那必须用 reshape(-1,1)来给矩阵增维。
我们已经学完了分类树 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
二、决策树的算法评价
1 决策树优点
- 易于理解和解释,因为树木可以画出来被看见。
- 需要很少的数据准备。其他很多算法通常都需要数据规范化,需要创建虚拟变量并删除空值等。但请注意,sklearn 中的决策树模块不支持对缺失值的处理。
- 使用树的成本(比如说,在预测数据的时候)是用于训练树的数据点的数量的对数,相比于其他算法,这是一个很低的成本。
- 能够同时处理数字和分类数据,既可以做回归又可以做分类。其他技术通常专门用于分析仅具有一种变量类型的数据集。
- 即使其假设在某种程度上违反了生成数据的真实模型,也能够表现良好。
2 决策树缺点
- 使用决策树可能创建过于复杂的树,这些树不能很好地推广数据。这称为过度拟合。修剪,设置 叶节点所需的最小样本数或设置树的最大深度等机制是避免此问题所必需的,而这些参数的整合和调整对 初学者来说会比较晦涩。
- 决策树可能不稳定,数据中微小的变化可能导致生成完全不同的树,这个问题需要通过集成算法来解决。
- 决策树的学习是基于贪婪算法,它靠优化局部最优(每个节点的最优)来试图达到整体的最优,但这种做法不能保证返回全局最优决策树。这个问题也可以由集成算法来解决,在随机森林中,特征和样本会在分枝过程中被随机采样。
- 如果标签中的某些类占主导地位,决策树学习者会创建偏向主导类的树。因此,建议在拟合决策树之前平衡数据集。
结束语
学到这里,决策树相关的知识基本也就完了。
后续我会再出一期模型评估的内容,然后可能会再介绍一下线性回归和逻辑回归,或者是关于决策树的项目实战。
推荐关注的专栏
👨👩👦👦 机器学习:分享机器学习实战项目和常用模型讲解
👨👩👦👦 数据分析:分享数据分析实战项目和常用技能整理
机器学习系列往期回顾
🧡 开始学习机器学习时你必须要了解的模型有哪些?机器学习系列之决策树进阶篇
💚 开始学习机器学习时你必须要了解的模型有哪些?机器学习系列之决策树基础篇
❤️ 以❤️简单易懂❤️的语言带你搞懂有监督学习算法【附Python代码详解】机器学习系列之KNN篇
💜 开始学习机器学习之前你必须要了解的知识有哪些?机器学习系列入门篇
往期内容回顾
🖤 我和关注我的前1000个粉丝“合影”啦!收集前1000个粉丝进行了一系列数据分析,收获满满
❤️ 分享一个超nice的数据分析实战案例 ⭐ “手把手”教学,收藏等于学会
💙 数据分析必须掌握的RFM模型是什么?一文搞懂如何利用RFM对用户进行分类【附实战讲解】
💚 MySQL必须掌握的技能有哪些?超细长文带你掌握MySQL【建议收藏】
💜 Hive必须了解的技能有哪些?万字博客带你掌握Hive❤️【建议收藏】
🧡 一文带你了解Hive【详细介绍】Hive与传统数据库有什么区别?
CSDN@报告,今天也有好好学习