概述
机器学习–决策树理论与实战
这篇文章是关于决策树在sklearn中的实现和调参,里面穿插着关于本人对决策树的一些理解。
开发环境用的是jupyter notebook
一、决策树的工作原理:
决策树(Decision Tree)是一种非参数的有监督的机器学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。决策树算法容易理解,适用各种数据,在解决各种问题时都有良好表现,尤其是以树模型为核心的各种集成算法,在各个行业和领域都有广泛的应用。
决策树算法的本质是一种图结构,我们只需要问一系列问题就可以对数据进行分类了。比如说,来看看下面这组数据集,这是一系列已知物种以及所属类别的数据:
名字 | 体温 | 表皮覆盖 | 胎生 | 水生 | 飞行动物 | 有腿 | 冬眠 | 类标号 |
---|---|---|---|---|---|---|---|---|
人类 | 恒温 | 毛发 | 是 | 否 | 否 | 是 | 否 | 哺乳类 |
鲑鱼 | 冷血 | 鳞片 | 否 | 是 | 否 | 否 | 否 | 鱼类 |
鲸鱼 | 恒温 | 毛发 | 是 | 是 | 否 | 否 | 否 | 哺乳类 |
青蛙 | 冷血 | 无 | 否 | 半 | 否 | 是 | 是 | 两栖类 |
巨蜥 | 冷血 | 鳞片 | 否 | 否 | 否 | 是 | 否 | 爬行类 |
蝙蝠 | 恒温 | 毛发 | 是 | 否 | 是 | 是 | 是 | 哺乳类 |
通过以上的数据将动物分为哺乳类和非哺乳类
那根据已经收集到的数据,决策树算法为我们算出了下面的这棵决策树:
假如我们现在发现了一种新物种Python,它是冷血动物,体表带鳞片,并且不是胎生,我们就可以通过这棵决策
树来判断它的所属类别。
可以看出,在这个决策过程中,我们一直在对记录的特征进行提问。最初的问题所在的地方叫做根节点,在得到结
论前的每一个问题都是中间节点,而得到的每一个结论(动物的类别)都叫做叶子节点。
二、决策树的基本流程如下:
1.计算全部特征的不纯度指标
2.选取不纯度指标最优的特征来分枝
3.在第一个特征的分枝下,计算全部特征的不纯度指标
4.选取不纯度指标最优的特征继续分枝
5.直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长
三、建决策树-以sklearn.datasets中自带的红酒数据集为例
- 导入需要的算法库和模块
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
2.探索数据
wine = load_wine()
wine.data.shape
wine.target#可以看出是三分类的数据集
import pandas as pd
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)
wine.feature_names#查看数据特征的名字
wine.target_names#查看标签的名字
- 分训练集和测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)#0.7的数据做训练集,0.3的数据做测试集
Xtrain.shape
Xtest.shape
- 建立模型
clf = tree.DecisionTreeClassifier(criterion="entropy")
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score
- 画决策树
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
import graphviz
dot_data=tree.export_graphviz(clf,feature_names=feature_name,class_names=["琴酒","雪莉","贝尔摩德"],filled=True,rounded=True)
graph=graphviz.Source(dot_data)
graph
- 探索决策树
#特征重要性
clf.feature_importances_
[*zip(feature_name,clf.feature_importances_)]
clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30)#random_state=30控制随机性
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score
6.1random_state & splitter比较
random_state用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显,低维度的数据
(比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。
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
import graphviz
dot_data = tree.export_graphviz(clf
,feature_names= feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True
,rounded=True
)
graph = graphviz.Source(dot_data)
graph
6.2剪枝处理
剪枝是决策树学习算法对付“过拟合”的主要手段,在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多,这时就可能导致过拟合,因此,可通过主动去掉一些分枝来降低过拟合的风险。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。
剪枝处理又包括预剪枝和后剪枝。预剪枝是要对划分前后泛化性能进行评估。对比决策树某节点生成前与生成后的泛化性能。后剪枝表示先从训练集中生成一颗完整决策树。
首先看一下决策树对训练集的拟合程度
#我们的树对训练集的拟合程度如何?
score_train = clf.score(Xtrain, Ytrain)
score_train
其中剪枝处理的重要参数如下:
①max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉
②min_samples_leaf & min_samples_split
min_samples_leaf限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生一般搭配max_depth使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。一般来说,建议从=5开始使用。如果叶节点中含有的样本量变化很大,建议输入浮点数作为样本量的百分比来使用。同时,这个参数可以保证每个叶子的最小尺寸,可以在回归问题中避免低方差,过拟合的叶子节点出现。对于类别不多的分类问题,=1通常就是最佳选择。min_samples_split限定,一个节点必须要包含至min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生。
clf = tree.DecisionTreeClassifier(criterion="entropy"
,random_state=30
,splitter="random"
,max_depth=3
,min_samples_leaf=10
,min_samples_split=10
)
clf = clf.fit(Xtrain, Ytrain)
dot_data = tree.export_graphviz(clf
,feature_names= feature_name
,class_names=["琴酒","雪莉","贝尔摩德"]
,filled=True
,rounded=True
)
graph = graphviz.Source(dot_data)
graph
clf.score(Xtrain,Ytrain)
clf.score(Xtest,Ytest)
③max_features & min_impurity_decrease
一般max_depth使用,用作树的“精修”
max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。和max_depth异曲同工,max_features是用来限制高维度数据的过拟合的剪枝参数,但其方法比较暴力,是直接限制可以使用的特征数量而强行使决策树停下的参数,在不知道决策树中的各个特征的重要性的情况下,强行设定这个参数可能会导致模型学习不足。如果希望通过降维的方式防止过拟合,建议使用PCA,ICA或者特征选择模块中的降维算法。
确认最优的剪枝参数
确定每个参数的取值需要用到超参数曲线判断,继续使用我们
已经训练好的决策树模型clf。超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲
线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是score。
import matplotlib.pyplot as plt
test = []
for i in range(10):
clf = tree.DecisionTreeClassifier(max_depth=i+1
,criterion="entropy"
,random_state=30
,splitter="random"
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
test.append(score)
plt.plot(range(1,11),test,color="red",label="max_depth")
plt.legend()
plt.show()
④目标权重参数class_weight & min_weight_fraction_leaf
有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_
weight_fraction_leaf这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如min_weight_
fraction_leaf)将比不知道样本权重的标准(比如min_samples_leaf)更少偏向主导类。如果样本是加权的,则使
用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。
6.3重要属性和接口
属性是在模型训练之后,能够调用查看的模型的各种性质。对决策树来说,最重要的是feature_importances_,能
够查看各个特征对模型的重要性。
sklearn中许多算法的接口都是相似的,比如说我们之前已经用到的fit和score,几乎对每个算法都可以使用。除了
这两个接口之外,决策树最常用的接口还有apply和predict。apply中输入测试集返回每个测试样本所在的叶子节
点的索引,predict输入测试集返回每个测试样本的标签。返回的内容一目了然并且非常容易,大家感兴趣可以自己
下去试试看。
在这里不得不提的是,所有接口中要求输入X_train和X_test的部分,输入的特征矩阵必须至少是一个二维矩阵。
sklearn不接受任何一维矩阵作为特征矩阵被输入。如果你的数据的确只有一个特征,那必须用reshape(-1,1)来给
矩阵增维;如果你的数据只有一个特征和一个样本,使用reshape(1,-1)来给你的数据增维。
#apply返回每个测试样本所在的叶子节点的索引
clf.apply(Xtest)
#predict返回每个测试样本的分类/回归结果
clf.predict(Xtest)
7.DecisionTreeRegressor
7.1重要参数,属性和接口
criterion
回归树衡量分枝质量的指标,支持的标准有三种:
①输入"mse"使用均方误差mean squared error(MSE),父节点和叶子节点之间的均方误差的差额将被用来作为
特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失
②输入“friedman_mse”使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差
③输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用叶节点的中值来最小化L1损失
属性中最重要的依然是feature_importances_,接口依然是apply, fit, predict, score最核心。
其中N是样本数量,i是每一个数据样本,fi是模型回归出的数值,yi是样本点i实际的数值标签。所以MSE的本质,
其实是样本真实数据与回归结果的差异。在回归树中,MSE不只是我们的分枝质量衡量指标,也是我们最常用的衡
量回归树回归质量的指标,当我们在使用交叉验证,或者其他方式获取回归树的结果时,我们往往选择均方误差作
为我们的评估(在分类树中这个指标是score代表的预测准确率)。在回归中,我们追求的是,MSE越小越好。
然而,回归树的接口score返回的是R平方,并不是MSE。R平方被定义如下:
其中u是残差平方和(MSE * N),v是总平方和,N是样本数量,i是每一个数据样本,fi是模型回归出的数值,yi
是样本点i实际的数值标签。y帽是真实数值标签的平均数。R平方可以为正为负(如果模型的残差平方和远远大于
模型的总平方和,模型非常糟糕,R平方就会为负),而均方误差永远为正。
值得一提的是,虽然均方误差永远为正,但是sklearn当中使用均方误差作为评判标准时,却是计算”负均方误
差“(neg_mean_squared_error)。这是因为sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均
方误差本身是一种误差,所以被sklearn划分为模型的一种损失(loss),因此在sklearn当中,都以负数表示。真正的
均方误差MSE的数值,其实就是neg_mean_squared_error去掉负号的数字。
8.决策树的优缺点
优点:
- 易于理解和解释,因为树木可以画出来被看见
- 需要很少的数据准备。其他很多算法通常都需要数据规范化,需要创建虚拟变量并删除空值等。但请注意,
sklearn中的决策树模块不支持对缺失值的处理。 - 使用树的成本(比如说,在预测数据的时候)是用于训练树的数据点的数量的对数,相比于其他算法,这是
一个很低的成本。 - 能够同时处理数字和分类数据,既可以做回归又可以做分类。其他技术通常专门用于分析仅具有一种变量类
型的数据集。 - 能够处理多输出问题,即含有多个标签的问题,注意与一个标签中含有多种标签分类的问题区别开
- 是一个白盒模型,结果很容易能够被解释。如果在模型中可以观察到给定的情况,则可以通过布尔逻辑轻松
解释条件。相反,在黑盒模型中(例如,在人工神经网络中),结果可能更难以解释。 - 可以使用统计测试验证模型,这让我们可以考虑模型的可靠性。
- 即使其假设在某种程度上违反了生成数据的真实模型,也能够表现良好。
缺点:
- 决策树学习者可能创建过于复杂的树,这些树不能很好地推广数据。这称为过度拟合。修剪,设置叶节点所
需的最小样本数或设置树的最大深度等机制是避免此问题所必需的,而这些参数的整合和调整对初学者来说
会比较晦涩 - 决策树可能不稳定,数据中微小的变化可能导致生成完全不同的树,这个问题需要通过集成算法来解决。
- 决策树的学习是基于贪婪算法,它靠优化局部最优(每个节点的最优)来试图达到整体的最优,但这种做法
不能保证返回全局最优决策树。这个问题也可以由集成算法来解决,在随机森林中,特征和样本会在分枝过
程中被随机采样。 - 有些概念很难学习,因为决策树不容易表达它们,例如XOR,奇偶校验或多路复用器问题。
- 如果标签中的某些类占主导地位,决策树学习者会创建偏向主导类的树。因此,建议在拟合决策树之前平衡
数据集。
最后
以上就是俊逸路人为你收集整理的机器学习--决策树理论与实战机器学习–决策树理论与实战的全部内容,希望文章能够帮你解决机器学习--决策树理论与实战机器学习–决策树理论与实战所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复