1 概述html
1.1 决策树是如何工做的node
1.2 构建决策树
1.2.1 ID3算法构建决策树
1.2.2 简单实例
1.2.3 ID3的局限性
1.3 C4.5算法 & CART算法
1.3.1 修改局部最优化条件
1.3.2 连续变量处理手段python
1.4 sklearn中的决策树算法
2 DecisionTreeClassifier与红酒数据集数据库
2.1 重要参数数组
2.1.1 criterion网络
2.1.2 random_state & splitterapp
2.1.3 剪枝参数dom
2.1.4 目标权重参数机器学习
2.2 重要属性和接口
3 DecisionTreeRegressor
3.1 重要参数,属性及接口
criterion
3.2 实例:一维回归的图像绘制
4 实例:泰坦尼克号幸存者的预测
5 决策树的优缺点
6 附录
6.1 分类树参数列表
6.2 分类树属性列表
6.3 分类树接口列表
Bonus Chapter I 实例:分类树在合成数集上的表现
决策树(Decision Tree)是一种非参数的有监督学习方法,它可以从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。决策树算法容易理解,适用各类数据,在解决各类问题时都有良好表现,尤为是以树模型为核心的各类集成算法,在各个行业和领域都有普遍的应用。
咱们来简单了解一下决策树是如何工做的。决策树算法的本质是一种图结构,咱们只须要问一系列问题就能够对数据进行分类了。好比说,来看看下面这组数据集,这是一系列已知物种以及所属类别的数据:
咱们如今的目标是,将动物们分为哺乳类和非哺乳类。那根据已经收集到的数据,决策树算法为咱们算出了下面的这棵决策树:
假如咱们如今发现了一种新物种Python,它是冷血动物,体表带鳞片,而且不是胎生,咱们就能够经过这棵决策树来判断它的所属类别。
能够看出,在这个决策过程当中,咱们一直在对记录的特征进行提问。最初的问题所在的地方叫作根节点,在获得结论前的每个问题都是中间节点,而获得的每个结论(动物的类别)都叫作叶子节点。
关键概念:节点
根节点:没有进边,有出边。包含最初的,针对特征的提问。
中间节点:既有进边也有出边,进边只有一条,出边能够有不少条。都是针对特征的提问。
叶子节点:有进边,没有出边,每一个叶子节点都是一个类别标签。
*子节点和父节点:在两个相连的节点中,更接近根节点的是父节点,另外一个是子节点。
决策树算法的核心是要解决两个问题:
1)如何从数据表中找出最佳节点和最佳分枝?
2)如何让决策树中止生长,防止过拟合?
几乎全部决策树有关的模型调整方法,都围绕这两个问题展开。接下来,咱们就来了解一下决策树背后的原理。
接下来讨论如何根据已有的数据集来创建有效的决策树。原则上讲,任意一个数据集上的全部特征均可以被拿来分枝,特征上的任意节点又能够自由组合,因此一个数据集上能够发展出很是很是多棵决策树,其数量可达指数级。在这些树中,总有那么一棵树比其余的树分类效力都好,那样的树叫作”全局最优树"。
关键概念:全局最优,局部最优
全局最优:通过组合造成的,总体来讲分类效果最好的模型;
局部最优:每一次分枝的时候都向着更好的分类效果分枝,但没法确认如今生成的树在全局上是不是最优的。
要在这么多棵决策树中去一次性找到分类效果最佳的那一棵是不可能的,若是经过排列组合来进行筛选,计算量过于大并且低效,所以咱们不会这样作。相对的,机器学习研究者们开发了一些有效的算法,可以在合理的时间内构造出具备必定准确率的次最优决策树。这些算法基本都执行”贪心策略",即经过局部的最优来达到咱们相信是最接近全局最优的结果。
关键概念:贪心算法
经过实现局部最优来达到接近全局最优结果的算法,全部的树模型都是这样的算法。
最典型的决策树算法是Hunt算法,该算法是由Hunt等人提出的最先的决策树算法。现代,Hunt算法是许多决策树算法的基础,包括ID三、C4.5和CART等。Hunt算法诞生时间较早,且基础理论并不是特别完善,此处以应用较广、理论基础较为完善的ID3算法的基本原理开始,讨论如何利用局部最优化方法来建立决策模型。
ID3算法原型见于J.R Quinlan的博士论文,是基础理论较为完善,使用较为普遍的决策树模型,在此基础上J.RQuinlan进行优化后,陆续推出了C4.5和C5.0决策树算法,后两者现已称为当前最流行的决策树算法,咱们先从ID3开始讲起,再讨论如何从ID3逐渐优化至C4.5。
为了要将表格转化为一棵树,决策树须要找出最佳节点和最佳的分枝方法,而衡量这个“最佳”的指标叫作“不纯度”。不纯度基于叶子节点来计算的,因此树中的每一个节点都会有一个不纯度,而且子节点的不纯度必定是低于父节点的,也就是说,在同一棵决策树上,叶子节点的不纯度必定是最低的。
重要概念:不纯度
决策树的每一个叶子节点中都会包含一组数据,在这组数据中,若是有某一类标签占有较大的比例,咱们就说叶子节点“纯”,分枝分得好。某一类标签占的比例越大,叶子就越纯,不纯度就越低,分枝就越好。 若是没有哪一类标签的比例很大,各种标签都相对平均,则说叶子节点”不纯“,分枝很差,不纯度高。
这个其实很是容易理解。分类型决策树在叶子节点上的决策规则是少数服从多数,在一个叶子节点上,若是某一类标签所占的比例较大,那全部进入这个叶子节点的样本都回被认为是这一类别。具体来讲,若是90%根据规则进入叶子节点的样本都是类别0(叶子比较纯),那新进入叶子节点的测试样本的类别也颇有多是0。可是,若是51%的样本是0,49%的样本是1(极端状况),叶子节点仍是会被认为是0类叶子节点,但此时此刻进入这个叶子的测试样本点几乎有一半的可能性应该是类别1。从数学上来讲,类分布为(0,100%)的结点具备零不纯性,而均衡分布(50%,50%)的结点具备最高的不纯性。若是叶子自己不纯,那测试样本就颇有可能被判断错误,相对的叶子越纯,那样本被判断错误的可能性就越小。
一般来讲,不纯度越低,决策树对训练集的拟合越好。如今使用的决策树算法在分枝方法上的核心大可能是围绕在对某个不纯度相关指标的最优化上。若咱们定义 t 表明决策树的某节点, Dt 是 t 节点所对应的数据集,设 p(i|t) 表示给定结点 t 中属于类别 i 的样本所占的比例,这个比例越高,则表明叶子越纯。
【练习】从下面的图来看,哪一个不纯度最高?哪一个不纯度最低?
怎样计算不纯度?
对于节点不纯度的计算和表示方法因决策树模型而异,但无论不纯度的度量方法如何,都是由偏差率衍生而来,其计算公式以下:
偏差率越低,则纯度越高。由此还衍生出了其余两个经常使用指标,一个是ID3中Information gain(信息增益)的计算方法可用Entropy推导,即最为人熟知的信息熵,又叫作香农熵,其计算公式以下:
其中c表示叶子节点上标签类别的个数,c-1表示标签的索引。注意在这里,是从第0类标签开始计算,因此最后的标签类别应该是总共c个标签,c-1为最后一个标签的索引。在计算Entropy时设定log20 = 0。
另外一个指标则是Gini(基尼)指数,主要用于CART决策树的纯度断定中,其计算公式以下:
假设在二分类问题中各节点呈现以下分布,则可进一步计算上述三指数的结果
可以看出,三种方法本质上都相同,在类分布均衡时(即当p=0.5时)达到最大值,而当全部记录都属于同一个类时(p等于1或0)达到最小值。换而言之,在纯度较高时三个指数均较低,而当纯度较低时,三个指数都比较大,且能够计算得出,嫡在0-1区间内分布,而Gini指数和分类偏差均在0-0.5区间内分布,三个指数随某变量占比增长而变化的曲线以下所示:
决策树最终的优化目标是使得叶节点的总不纯度最低,即对应衡量不纯度的指标最低。
ID3采用信息熵来衡量不纯度,此处就先以信息嫡为例进行讨论。ID3最优条件是叶节点的总信息熵最小,所以ID3决策树在决定是否对某节点进行切分的时候,会尽量选取使得该节点对应的子节点信息熵最小的特征进行切分。换而言之,就是要求父节点信息熵和子节点总信息熵之差要最大。对于ID3而言,两者之差就是信息增益,即Information gain。
但这里须要注意,一个父节点下可能有多个子节点,而每一个子节点又有本身的信息熵,因此父节点信息熵和子节点信息熵之差,应该是父节点的信息熵-全部子节点信息熵的加权平均。其中,权重是使用单个叶子节点上所占的样本量比上父节点上的总样本量来肯定的一个权重。
而父节点和子节点的不纯度降低数可由下述公式进行计算:
I(.)是给定结点的不纯性度量(便是基尼系数或者信息上),N是父结点上的样本数,k是这一层上子节点的个数,NVj)是与子结点相关联的样本个数。决策树算法一般选择最大化增益△的测试条件,由于对任何分枝过程来讲,
(parent)都是一个不变的值(由于此时父节点已经存在而且不可修改),因此最大化增益等价于最小化子结点的不纯性衡量的加权平均。最后,当选择熵(entropy)做为公式的不纯性度量时,烯的差就是所谓信息增益(Information gain)△info。
接下来对此进行举例说明。
假设如今有以下数据集,是一个消费者我的属性和信用评分数据,标签是“是否会发生购买电脑行为",仍然是个而分类问题,在此数据集之上咱们使用ID3构建决策树模型,并提取有效的分类规则。
sklearn中决策树的类都在”tree“这个模块之下。这个模块总共包含五个类:
咱们会主要讲解分类树和回归树,并用图像呈现给你们。
在那以前,咱们先来了解一下sklearn建模的基本流程。
在这个流程下,分类树对应的代码是:
from sklearn import tree #导入须要的模块 clf = tree.DecisionTreeClassifier() #实例化 clf = clf.fit(X_train,y_train) #用训练集数据训练模型 result = clf.score(X_test,y_test) #导入测试集,从接口中调用须要的信息
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, min_impurity_split=None,class_weight=None, presort=False)
为了要将表格转化为一棵树,决策树须要找出最佳节点和最佳的分枝方法,对分类树来讲,衡量这个“最佳”的指标叫作“不纯度”。一般来讲,不纯度越低,决策树对训练集的拟合越好。如今使用的决策树算法在分枝方法上的核心大可能是围绕在对某个不纯度相关指标的最优化上。
不纯度基于节点来计算,树中的每一个节点都会有一个不纯度,而且子节点的不纯度必定是低于父节点的,也就是说,在同一棵决策树上,叶子节点的不纯度必定是最低的。
Criterion这个参数正是用来决定不纯度的计算方法的。sklearn提供了两种选择:
其中 t 表明给定的节点, i 表明标签的任意分类, p(i|t) 表明标签分类 i 在节点 t 上所占的比例。注意,当使用信息熵时,sklearn实际计算的是基于信息熵的信息增益(Information Gain),即父节点的信息熵和子节点的信息熵之差。
比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。可是在实际使用中,信息熵和基尼系数的效果基本相同。信息熵的计算比基尼系数缓慢一些,由于基尼系数的计算不涉及对数。另外,由于信息熵对不纯度更加敏感,因此信息熵做为指标时,决策树的生长会更加“精细”,所以对于高维数据或者噪音不少的数据,信息熵很容易过拟合,基尼系数在这种状况下效果每每比较好。当模型拟合程度不足的时候,即当模型在训练集和测试集上都表现不太好的时候,使用信息熵(欠拟合状况下使用多)。固然,这些不是绝对的。
到这里,决策树的基本流程其实能够简单归纳以下:
直到没有更多的特征可用,或总体的不纯度指标已经最优,决策树就会中止生长。
from sklearn import tree from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split
wine = load_wine() wine.data.shape#(178,13) wine.target #若是wine是一张表,应该长这样: 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) Xtrain.shape Xtest.shape
clf = tree.DecisionTreeClassifier(criterion="entropy")#实例化,criterion不写的话默认是基尼系数 clf = clf.fit(Xtrain, Ytrain) score = clf.score(Xtest, Ytest) #返回预测的准确度 score
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.render("Tree") graph# graph.view()
#特征重要性 clf.feature_importances_ [*zip(feature_name,clf.feature_importances_)]
咱们已经在只了解一个参数的状况下,创建了一棵完整的决策树。可是回到步骤4创建模型,score会在某个值附近波动,引发步骤5中画出来的每一棵树都不同。它为何会不稳定呢?若是使用其余数据集,它还会不稳定吗?
咱们以前提到过,不管决策树模型如何进化,在分枝上的本质都仍是追求某个不纯度相关的指标的优化,而正如咱们提到的,不纯度是基于节点来计算的,也就是说,决策树在建树时,是靠优化节点来追求一棵优化的树,但最优的节点可以保证最优的树吗?集成算法被用来解决这个问题:sklearn表示,既然一棵树不能保证最优,那就建更多的不一样的树,而后从中取最好的。怎样从一组数据集中建不一样的树?在每次分枝时,不从使用所有特征,而是随机选取一部分特征,从中选取不纯度相关指标最优的做为分枝用的节点。这样,每次生成的树也就不一样了。
clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30) clf = clf.fit(Xtrain, Ytrain) score = clf.score(Xtest, Ytest) #返回预测的准确度 score
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#0.9814814814814815 import graphviz dot_data = tree.export_graphviz(clf ,feature_names= feature_name ,class_names=["琴酒","雪莉","贝尔摩德"] ,filled=True ,rounded=True ) graph = graphviz.Source(dot_data) graph
在不加限制的状况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止。这样的决策树每每会过拟合,这就是说,它会在训练集上表现很好,在测试集上却表现糟糕。咱们收集的样本数据不可能和总体的情况彻底一致,所以当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪声,并使它对未知数据的拟合程度不。
#咱们的树对训练集的拟合程度如何? score_train = clf.score(Xtrain, Ytrain) score_train#1.0
为了让决策树有更好的泛化性,咱们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。sklearn为咱们提供了不一样的剪枝策略:
限制树的最大深度,超过设定深度的树枝所有剪掉。
这是用得最普遍的剪枝参数,在高维度低样本量时很是有效。决策树多生长一层,对样本量的需求会增长一倍,因此限制树深度可以有效地限制过拟合。在集成算法中也很是实用。实际使用时,建议从=3开始尝试,看看拟合的效果再决定是否增长设定深度。
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=25 ) 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 score = clf.score(Xtest, Ytest) score#0.9814814814814815
通常max_depth使用,用做树的”精修“。
max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。和max_depth殊途同归,max_features是用来限制高维度数据的过拟合的剪枝参数,但其方法比较暴力,是直接限制可使用的特征数量而强行使决策树停下的参数,在不知道决策树中的各个特征的重要性的状况下,强行设定这个参数可能会致使模型学习不足。若是但愿经过降维的方式防止过拟合,建议使用PCA,ICA或者特征选择模块中的降维算法。
min_impurity_decrease限制信息增益的大小,信息增益小于设定数值的分枝不会发生。这是在0.19版本中更新的功能,在0.19版本以前时使用min_impurity_split。
那具体怎么来肯定每一个参数填写什么值呢?这时候,咱们就要使用肯定超参数的曲线来进行判断了,继续使用咱们已经训练好的决策树模型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()
结果:
思考:
不管如何,剪枝参数的默认值会让树无尽地生长,这些树在某些数据集上可能很是巨大,对内存的消耗也很是巨大。因此若是你手中的数据集很是巨大,你已经预测到不管如何你都是要剪枝的,那提早设定这些参数来控制树的复杂性和大小会比较好。
完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。好比说,在银行要判断“一个办了信用卡的人是否会违约",就是是vs否(1%:99%)的比例。这种分类情况下,即使模型什么也不作,全把结果预测成“否”,正确率也能有99%。所以咱们要使用class_weight参数对样本标签进行必定的均衡,给少许的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认None,此模式表示自动给与数据集中的全部标签相同的权重。
有了权重以后,样本量就再也不是单纯地记录数目,而是受输入的权重影响了,所以这时候剪枝,就须要搭配min_weight_fraction_leaf这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如min_weight_fraction_leaf)将比不知道样本权重的标准(好比min_samples_leaf)更少偏向主导类。若是样本是加权的,则使用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。
属性是在模型训练以后,可以调用查看的模型的各类性质。对决策树来讲,最重要的是feature_importances_,可以查看各个特征对模型的重要性。sklearn中许多算法的接口都是类似的,好比说咱们以前已经用到的fit和score,几乎对每一个算法均可以使用。除了这两个接口以外,决策树最经常使用的接口还有apply和predict。apply中输入测试集返回每一个测试样本所在的叶子节点的索引,predict输入测试集返回每一个测试样本的标签。返回的内容一目了然而且很是容易,你们感兴趣能够本身下去试试看。
在这里不得不提的是,全部接口中要求输入X_train和X_test的部分,输入的特征矩阵必须至少是一个二维矩阵。sklearn不接受任何一维矩阵做为特征矩阵被输入。若是你的数据的确只有一个特征,那必须用reshape(-1,1)来给矩阵增维;若是你的数据只有一个特征和一个样本,使用reshape(1,-1)来给你的数据增维。
#apply返回每一个测试样本所在的叶子节点的索引 clf.apply(Xtest)
结果:
array([19, 27, 19, 27, 7, 7, 7, 27, 19, 27, 21, 21, 7, 18, 7, 21, 7, 10, 7, 19, 7, 27, 19, 19, 27, 21, 7, 21, 27, 7, 19, 7, 7, 27, 21, 27, 27, 7, 27, 7, 19, 27, 7, 27, 27, 19, 19, 10, 27, 27, 27, 10, 7, 21], dtype=int64)
#predict返回每一个测试样本的分类/回归结果 clf.predict(Xtest)
结果:
array([1, 0, 1, 0, 2, 2, 2, 0, 1, 0, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 1, 1, 0, 1, 2, 1, 0, 2, 1, 2, 2, 0, 1, 0, 0, 2, 0, 2, 1, 0, 2, 0, 0, 1, 1, 1, 0, 0, 0, 1, 2, 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
有了这些知识,基本上分类树的使用你们都可以掌握了,接下来再到实例中去磨练就好。
class sklearn.tree.DecisionTreeRegressor (criterion=’mse’, 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, min_impurity_split=None, presort=False)
几乎全部参数,属性及接口都和分类树如出一辙。须要注意的是,在回归树种,没有标签分布是否均衡的问题,所以没有class_weight这样的参数。
回归树衡量分枝质量的指标,支持的标准有三种:
属性中最重要的依然是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去掉负号的数字。
简单看看回归树是怎样工做的
from sklearn.datasets import load_boston from sklearn.model_selection import cross_val_score from sklearn.tree import DecisionTreeRegressor
boston = load_boston()
boston.data
结果:
array([[6.3200e-03, 1.8000e+01, 2.3100e+00, ..., 1.5300e+01, 3.9690e+02, 4.9800e+00], [2.7310e-02, 0.0000e+00, 7.0700e+00, ..., 1.7800e+01, 3.9690e+02, 9.1400e+00], [2.7290e-02, 0.0000e+00, 7.0700e+00, ..., 1.7800e+01, 3.9283e+02, 4.0300e+00], ..., [6.0760e-02, 0.0000e+00, 1.1930e+01, ..., 2.1000e+01, 3.9690e+02, 5.6400e+00], [1.0959e-01, 0.0000e+00, 1.1930e+01, ..., 2.1000e+01, 3.9345e+02, 6.4800e+00], [4.7410e-02, 0.0000e+00, 1.1930e+01, ..., 2.1000e+01, 3.9690e+02, 7.8800e+00]])
boston.target
结果:
array([24. , 21.6, 34.7, 33.4, 36.2, 28.7, 22.9, 27.1, 16.5, 18.9, 15. , 18.9, 21.7, 20.4, 18.2, 19.9, 23.1, 17.5, 20.2, 18.2, 13.6, 19.6, 15.2, 14.5, 15.6, 13.9, 16.6, 14.8, 18.4, 21. , 12.7, 14.5, 13.2, 13.1, 13.5, 18.9, 20. , 21. , 24.7, 30.8, 34.9, 26.6, 25.3, 24.7, 21.2, 19.3, 20. , 16.6, 14.4, 19.4, 19.7, 20.5, 25. , 23.4, 18.9, 35.4, 24.7, 31.6, 23.3, 19.6, 18.7, 16. , 22.2, 25. , 33. , 23.5, 19.4, 22. , 17.4, 20.9, 24.2, 21.7, 22.8, 23.4, 24.1, 21.4, 20. , 20.8, 21.2, 20.3, 28. , 23.9, 24.8, 22.9, 23.9, 26.6, 22.5, 22.2, 23.6, 28.7, 22.6, 22. , 22.9, 25. , 20.6, 28.4, 21.4, 38.7, 43.8, 33.2, 27.5, 26.5, 18.6, 19.3, 20.1, 19.5, 19.5, 20.4, 19.8, 19.4, 21.7, 22.8, 18.8, 18.7, 18.5, 18.3, 21.2, 19.2, 20.4, 19.3, 22. , 20.3, 20.5, 17.3, 18.8, 21.4, 15.7, 16.2, 18. , 14.3, 19.2, 19.6, 23. , 18.4, 15.6, 18.1, 17.4, 17.1, 13.3, 17.8, 14. , 14.4, 13.4, 15.6, 11.8, 13.8, 15.6, 14.6, 17.8, 15.4, 21.5, 19.6, 15.3, 19.4, 17. , 15.6, 13.1, 41.3, 24.3, 23.3, 27. , 50. , 50. , 50. , 22.7, 25. , 50. , 23.8, 23.8, 22.3, 17.4, 19.1, 23.1, 23.6, 22.6, 29.4, 23.2, 24.6, 29.9, 37.2, 39.8, 36.2, 37.9, 32.5, 26.4, 29.6, 50. , 32. , 29.8, 34.9, 37. , 30.5, 36.4, 31.1, 29.1, 50. , 33.3, 30.3, 34.6, 34.9, 32.9, 24.1, 42.3, 48.5, 50. , 22.6, 24.4, 22.5, 24.4, 20. , 21.7, 19.3, 22.4, 28.1, 23.7, 25. , 23.3, 28.7, 21.5, 23. , 26.7, 21.7, 27.5, 30.1, 44.8, 50. , 37.6, 31.6, 46.7, 31.5, 24.3, 31.7, 41.7, 48.3, 29. , 24. , 25.1, 31.5, 23.7, 23.3, 22. , 20.1, 22.2, 23.7, 17.6, 18.5, 24.3, 20.5, 24.5, 26.2, 24.4, 24.8, 29.6, 42.8, 21.9, 20.9, 44. , 50. , 36. , 30.1, 33.8, 43.1, 48.8, 31. , 36.5, 22.8, 30.7, 50. , 43.5, 20.7, 21.1, 25.2, 24.4, 35.2, 32.4, 32. , 33.2, 33.1, 29.1, 35.1, 45.4, 35.4, 46. , 50. , 32.2, 22. , 20.1, 23.2, 22.3, 24.8, 28.5, 37.3, 27.9, 23.9, 21.7, 28.6, 27.1, 20.3, 22.5, 29. , 24.8, 22. , 26.4, 33.1, 36.1, 28.4, 33.4, 28.2, 22.8, 20.3, 16.1, 22.1, 19.4, 21.6, 23.8, 16.2, 17.8, 19.8, 23.1, 21. , 23.8, 23.1, 20.4, 18.5, 25. , 24.6, 23. , 22.2, 19.3, 22.6, 19.8, 17.1, 19.4, 22.2, 20.7, 21.1, 19.5, 18.5, 20.6, 19. , 18.7, 32.7, 16.5, 23.9, 31.2, 17.5, 17.2, 23.1, 24.5, 26.6, 22.9, 24.1, 18.6, 30.1, 18.2, 20.6, 17.8, 21.7, 22.7, 22.6, 25. , 19.9, 20.8, 16.8, 21.9, 27.5, 21.9, 23.1, 50. , 50. , 50. , 50. , 50. , 13.8, 13.8, 15. , 13.9, 13.3, 13.1, 10.2, 10.4, 10.9, 11.3, 12.3, 8.8, 7.2, 10.5, 7.4, 10.2, 11.5, 15.1, 23.2, 9.7, 13.8, 12.7, 13.1, 12.5, 8.5, 5. , 6.3, 5.6, 7.2, 12.1, 8.3, 8.5, 5. , 11.9, 27.9, 17.2, 27.5, 15. , 17.2, 17.9, 16.3, 7. , 7.2, 7.5, 10.4, 8.8, 8.4, 16.7, 14.2, 20.8, 13.4, 11.7, 8.3, 10.2, 10.9, 11. , 9.5, 14.5, 14.1, 16.1, 14.3, 11.7, 13.4, 9.6, 8.7, 8.4, 12.8, 10.5, 17.1, 18.4, 15.4, 10.8, 11.8, 14.9, 12.6, 14.1, 13. , 13.4, 15.2, 16.1, 17.8, 14.9, 14.1, 12.7, 13.5, 14.9, 20. , 16.4, 17.7, 19.5, 20.2, 21.4, 19.9, 19. , 19.1, 19.1, 20.1, 19.9, 19.6, 23.2, 29.8, 13.8, 13.3, 16.7, 12. , 14.6, 21.4, 23. , 23.7, 25. , 21.8, 20.6, 21.2, 19.1, 20.6, 15.2, 7. , 8.1, 13.6, 20.1, 21.8, 24.5, 23.1, 19.7, 18.3, 21.2, 17.5, 16.8, 22.4, 20.6, 23.9, 22. , 11.9])
regressor = DecisionTreeRegressor(random_state=0)#实例化 cross_val_score(regressor, boston.data, boston.target, cv=10,#交叉验证会自动划分数据集为测试集与验证集,不须要本身单独划分,cv为划分的数量,默认是5 scoring = "neg_mean_squared_error"#scoring指的是返回的是均方偏差,若是不写返回的是R的平方 )
结果:
array([-16.41568627, -10.61843137, -18.30176471, -55.36803922, -16.01470588, -44.70117647, -12.2148 , -91.3888 , -57.764 , -36.8134 ])
cross_val_score(regressor, boston.data, boston.target, cv=10).mean()#返回的是R方的均值:-0.1253505322812249
交叉验证是用来观察模型的稳定性的一种方法,咱们将数据划分为n份,依次使用其中一份做为测试集,其余n-1份做为训练集,屡次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,所以用交叉验证n次的结果求出的平均值,是对模型效果的一个更好的度量。
接下来咱们到二维平面上来观察决策树是怎样拟合一条曲线的。咱们用回归树来拟合正弦曲线,并添加一些噪声来观察回归树的表现。
import numpy as np from sklearn.tree import DecisionTreeRegressor import matplotlib.pyplot as plt
在这一步,咱们的基本思路是,先建立一组随机的,分布在0~5上的横坐标轴的取值(x),而后将这一组值放到sin函数中去生成纵坐标的值(y),接着再到y上去添加噪声。全程咱们会使用numpy库来为咱们生成这个正弦曲线。
rng = np.random.RandomState(1) #随机数种子 #np.random.rand(数组结构),生成随机数组的函数 X = np.sort(5 * rng.rand(80,1), axis=0) #生成0~5之间随机的x的取值,80行1列,按照axis = 0(行)进行从小到大排序 y = np.sin(X).ravel() #生成正弦曲线 np.sin(X)生成的是80行1列的数组,经过.ravel()降为1维,.ravel()能够将n维数组降为n-1维,屡次容许n-1次能够降为1维 y[::5] += 3 * (0.5 - rng.rand(16)) #在正弦曲线上加噪声, rng.rand(16)指的是生成16个0~1之间的随机数
plt.figure() plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")#散点图
结果:<matplotlib.collections.PathCollection at 0xb04a2e8>
#了解降维函数ravel()的用法 np.random.random((2,1)) np.random.random((2,1)).ravel() np.random.random((2,1)).ravel().shape
regr_1 = DecisionTreeRegressor(max_depth=2) regr_2 = DecisionTreeRegressor(max_depth=5) regr_1.fit(X, y) regr_2.fit(X, y)
结果:
DecisionTreeRegressor(criterion='mse', max_depth=5, 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=False, random_state=None, splitter='best')
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]#np.newaxis做用是增长1个维度 y_1 = regr_1.predict(X_test) y_2 = regr_2.predict(X_test)
#了解增维切片np.newaxis的用法 l = np.array([1,2,3,4]) l#array([1, 2, 3, 4]) l.shape#(4,) l[:,np.newaxis] # array([[1], # [2], # [3], # [4]]) l[:,np.newaxis].shape#(4, 1) l[np.newaxis,:].shape#(1, 4) l[np.newaxis,:]#array([[1, 2, 3, 4]])
plt.figure() plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")#s指的是点的大小 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()
结果:
可见,回归树学习了近似正弦曲线的局部线性回归。咱们能够看到,若是树的最大深度(由max_depth参数控制)设置得过高,则决策树学习得太精细,它从训练数据中学了不少细节,包括噪声得呈现,从而使模型偏离真实的正弦曲线,造成过拟合。
泰坦尼克号的沉没是世界上最严重的海难事故之一,今天咱们经过分类树模型来预测一下哪些人可能成为幸存者。数据集来着https://www.kaggle.com/c/titanic,数据集会随着代码一块儿提供给你们,你们能够在下载页面拿到,或者到群中询问。数据集包含两个csv格式文件,data为咱们接下来要使用的数据,test为kaggle提供的测试集。接下来咱们就来执行咱们的代码。
import pandas as pd from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split from sklearn.model_selection import GridSearchCV from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt
data = pd.read_csv(r"C:\work\learnbetter\micro-class\week 1 DT\data\data.csv",index_col = 0) data.head() data.info() #object属于文本类型,并不属于数值类型! #查看缺失值,为预处理作准备 ''' <class 'pandas.core.frame.DataFrame'> Int64Index: 891 entries, 1 to 891 Data columns (total 11 columns): Survived 891 non-null int64 Pclass 891 non-null int64 Name 891 non-null object Sex 891 non-null object Age 714 non-null float64 SibSp 891 non-null int64 Parch 891 non-null int64 Ticket 891 non-null object Fare 891 non-null float64 Cabin 204 non-null object Embarked 889 non-null object dtypes: float64(2), int64(4), object(5) memory usage: 83.5+ KB '''
#筛选特征 #删除缺失值过多的列,和观察判断来讲和预测的y没有关系的列 data.drop(["Cabin","Name","Ticket"],inplace=True,axis=1)#inplace=True指的是覆盖原表,False则会生成新表 #处理缺失值,对缺失值较多的列进行填补,有一些特征只缺失一两个值,能够采起直接删除记录的方法 data["Age"] = data["Age"].fillna(data["Age"].mean()) data = data.dropna()#默认axis = 0 #将分类变量(如object类型)转换为数值型变量 #将二分类变量转换为数值型变量 #astype可以将一个pandas对象转换为某种类型,和apply(int(x))不一样,astype能够将文本类转换为数字,用这个方式能够很便捷地将二分类特征转换为0~1 data["Sex"] = (data["Sex"]== "male").astype("int")#.astype("int")将bool值转换为int类型 #将三分类变量转换为数值型变量 labels = data["Embarked"].unique().tolist()#tolist()将数组array变为列表list data["Embarked"] = data["Embarked"].apply(lambda x: labels.index(x)) #查看处理后的数据集 data.head()
X = data.iloc[:,data.columns != "Survived"] y = data.iloc[:,data.columns == "Survived"] from sklearn.model_selection import train_test_split Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3) #修正测试集和训练集的索引 for i in [Xtrain, Xtest, Ytrain, Ytest]: i.index = range(i.shape[0]) #查看分好的训练集和测试集 Xtrain.head()
clf = DecisionTreeClassifier(random_state=25) clf = clf.fit(Xtrain, Ytrain) score_ = clf.score(Xtest, Ytest) score_ score = cross_val_score(clf,X,y,cv=10).mean()#使用交叉验证 score
tr = [] te = [] for i in range(10): clf = DecisionTreeClassifier(random_state=25 ,max_depth=i+1 ,criterion="entropy"#尝试调参,让结果更好 ) clf = clf.fit(Xtrain, Ytrain) score_tr = clf.score(Xtrain,Ytrain)#训练集分数 score_te = cross_val_score(clf,X,y,cv=10).mean()#测试集分数 tr.append(score_tr) te.append(score_te) print(max(te)) plt.plot(range(1,11),tr,color="red",label="train") plt.plot(range(1,11),te,color="blue",label="test") plt.xticks(range(1,11))#横坐标标尺,只显示1-10。 plt.legend() plt.show()
结果:0.8177860061287026
注意:这里为何使用“entropy”?由于咱们注意到,在最大深度=3的时候,模型拟合不足,在训练集和测试集上的表现接近,但却都不是很是理想,只可以达到83%左右,因此咱们要使用entropy。
#网格搜索:可以帮助咱们同时调整多个参数的技术,枚举技术 import numpy as np gini_thresholds = np.linspace(0,0.5,20)#基尼系数的边界 #entropy_thresholds = np.linespace(0, 1, 50) #一串参数和这些参数对应的,咱们但愿网格搜索来搜索的参数的取值范围 parameters = {'splitter':('best','random') ,'criterion':("gini","entropy") ,"max_depth":[*range(1,10)] ,'min_samples_leaf':[*range(1,50,5)] ,'min_impurity_decrease':[*gini_thresholds] } clf = DecisionTreeClassifier(random_state=25)#实例化决策树 GS = GridSearchCV(clf, parameters, cv=10)#实例化网格搜索,cv指的是交叉验证 GS.fit(Xtrain,Ytrain) GS.best_params_#从咱们输入的参数和参数取值的列表中,返回最佳组合 GS.best_score_#网格搜索后的模型的评判标准
1. 易于理解和解释,由于树木能够画出来被看见
2. 须要不多的数据准备。其余不少算法一般都须要数据规范化,须要建立虚拟变量并删除空值等。但请注意,sklearn中的决策树模块不支持对缺失值的处理。
3. 使用树的成本(好比说,在预测数据的时候)是用于训练树的数据点的数量的对数,相比于其余算法,这是一个很低的成本。
4. 可以同时处理数字和分类数据,既能够作回归又能够作分类。其余技术一般专门用于分析仅具备一种变量类型的数据集。
5. 可以处理多输出问题,即含有多个标签的问题,注意与一个标签中含有多种标签分类的问题区别开
6. 是一个白盒模型,结果很容易可以被解释。若是在模型中能够观察到给定的状况,则能够经过布尔逻辑轻松解释条件。相反,在黑盒模型中(例如,在人工神经网络中),结果可能更难以解释。
7. 可使用统计测试验证模型,这让咱们能够考虑模型的可靠性。
8. 即便其假设在某种程度上违反了生成数据的真实模型,也可以表现良好。
1. 决策树学习者可能建立过于复杂的树,这些树不能很好地推广数据。这称为过分拟合。修剪,设置叶节点所需的最小样本数或设置树的最大深度等机制是避免此问题所必需的,而这些参数的整合和调整对初学者来讲会比较晦涩
2. 决策树可能不稳定,数据中微小的变化可能致使生成彻底不一样的树,这个问题须要经过集成算法来解决。
3. 决策树的学习是基于贪婪算法,它靠优化局部最优(每一个节点的最优)来试图达到总体的最优,但这种作法不能保证返回全局最优决策树。这个问题也能够由集成算法来解决,在随机森林中,特征和样本会在分枝过程当中被随机采样。
4. 有些概念很难学习,由于决策树不容易表达它们,例如XOR,奇偶校验或多路复用器问题。
5. 若是标签中的某些类占主导地位,决策树学习者会建立偏向主导类的树。所以,建议在拟合决策树以前平衡数据集。
咱们在红酒数据集上画出了一棵树,而且展现了多个参数会对树造成这样的影响,接下来,咱们将在不一样结构的数据集上测试一下决策树的效果,让你们更好地理解决策树。
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.datasets import make_moons, make_circles, make_classification from sklearn.tree import DecisionTreeClassifier
咱们先从sklearn自带的数据库中生成三种类型的数据集:1)月亮型数据,2)环形数据,3)二分型数据
#make_classification库生成随机的二分型数据 X, y = make_classification(n_samples=100, #生成100个样本 n_features=2, #包含2个特征,即生成二维数据 n_redundant=0, #添加冗余特征0个 n_informative=2, #包含信息的特征是2个 random_state=1, #随机模式1 n_clusters_per_class=1 #每一个簇内包含的标签类别有1个 ) #在这里能够查看一下X和y,其中X是100行带有两个2特征的数据,y是二分类标签 #也能够画出散点图来观察一下X中特征的分布 #plt.scatter(X[:,0],X[:,1]) #从图上能够看出,生成的二分型数据的两个簇离彼此很远,这样不利于咱们测试分类器的效果,所以咱们使用np生成 # 随机数组,经过让已经生成的二分型数据点加减0~1之间的随机数,使数据分布变得更散更稀疏 #注意,这个过程只可以运行一次,由于屡次运行以后X会变得很是稀疏,两个簇的数据会混合在一块儿,分类器的效应会 # 继续降低 rng = np.random.RandomState(2) #生成一种随机模式 X += 2 * rng.uniform(size=X.shape) #加减0~1之间的随机数 linearly_separable = (X, y) #生成了新的X,依然能够画散点图来观察一下特征的分布 #plt.scatter(X[:,0],X[:,1]) #用make_moons建立月亮型数据,make_circles建立环形数据,并将三组数据打包起来放在列表datasets中 datasets = [make_moons(noise=0.3, random_state=0), make_circles(noise=0.2, factor=0.5, random_state=1), linearly_separable]
#建立画布,宽高比为6*9 figure = plt.figure(figsize=(6, 9)) #设置用来安排图像显示位置的全局变量i i = 1 #开始迭代数据,对datasets中的数据进行for循环 for ds_index, ds in enumerate(datasets): #对X中的数据进行标准化处理,而后分训练集和测试集 X, y = ds X = StandardScaler().fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4, random_state=42) #找出数据集中两个特征的最大值和最小值,让最大值+0.5,最小值-0.5,创造一个比两个特征的区间自己更大 # 一点的区间 x1_min, x1_max = X[:, 0].min() - .5, X[:, 0].max() + .5 x2_min, x2_max = X[:, 1].min() - .5, X[:, 1].max() + .5 #用特征向量生成网格数据,网格数据,其实就至关于坐标轴上无数个点 #函数np.arange在给定的两个数之间返回均匀间隔的值,0.2为步长 #函数meshgrid用以生成网格数据,可以将两个一维数组生成两个二维矩阵。 #若是第一个数组是narray,维度是n,第二个参数是marray,维度是m。那么生成的第一个二维数组是以 # narray为行,m行的矩阵,而第二个二维数组是以marray的转置为列,n列的矩阵 #生成的网格数据,是用来绘制决策边界的,由于绘制决策边界的函数contourf要求输入的两个特征都必须是二 # 维的 array1,array2 = np.meshgrid(np.arange(x1_min, x1_max, 0.2), np.arange(x2_min, x2_max, 0.2)) #接下来生成彩色画布 #用ListedColormap为画布建立颜色,#FF0000正红,#0000FF正蓝 cm = plt.cm.RdBu cm_bright = ListedColormap(['#FF0000', '#0000FF']) #在画布上加上一个子图,数据为len(datasets)行,2列,放在位置i上 ax = plt.subplot(len(datasets), 2, i) #到这里为止,已经生成了0~1之间的坐标系3个了,接下来为咱们的坐标系放上标题 #咱们有三个坐标系,但咱们只须要在第一个坐标系上有标题,所以设定if ds_index==0这个条件 if ds_index == 0: ax.set_title("Input data") #将数据集的分布放到咱们的坐标系上 #先放训练集 ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright,edgecolors='k') #放测试集 ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6,edgecolors='k') #为图设置坐标轴的最大值和最小值,并设定没有坐标轴 ax.set_xlim(array1.min(), array1.max()) ax.set_ylim(array2.min(), array2.max()) ax.set_xticks(()) ax.set_yticks(()) #每次循环以后,改变i的取值让图每次位列不一样的位置 i += 1 #至此为止,数据集自己的图像已经布置完毕,运行以上的代码,能够看见三个已经处理好的数据集 #############################从这里开始是决策树模型########################## #迭代决策树,首先用subplot增长子图,subplot(行,列,索引)这样的结构,并使用索引i定义图的位置 #在这里,len(datasets)其实就是3,2是两列 #在函数最开始,咱们定义了i=1,而且在上边创建数据集的图像的时候,已经让i+1,因此i在每次循环中的取值 # 是2,4,6 ax = plt.subplot(len(datasets),2,i) #决策树的建模过程:实例化 → fit训练 → score接口获得预测的准确率 clf = DecisionTreeClassifier(max_depth=5) clf.fit(X_train, y_train) score = clf.score(X_test, y_test) #绘制决策边界,为此,咱们将为网格中的每一个点指定一种颜色[x1_min,x1_max] x [x2_min,x2_max] #分类树的接口,predict_proba,返回每个输入的数据点所对应的标签类几率 #类几率是数据点所在的叶节点中相同类的样本数量/叶节点中的样本总数量 #因为决策树在训练的时候导入的训练集X_train里面包含两个特征,因此咱们在计算类几率的时候,也必须导入 # 结构相同的数组,便是说,必须有两个特征 #ravel()可以将一个多维数组转换成一维数组 #np.c_是可以将两个数组组合起来的函数 #在这里,咱们先将两个网格数据降维降维成一维数组,再将两个数组连接变成含有两个特征的数据,再带入决策 # 树模型,生成的Z包含数据的索引和每一个样本点对应的类几率,再切片,切出类几率 Z = clf.predict_proba(np.c_[array1.ravel(),array2.ravel()])[:, 1] #np.c_[np.array([1,2,3]), np.array([4,5,6])] #将返回的类几率做为数据,放到contourf里面绘制去绘制轮廓 Z = Z.reshape(array1.shape) ax.contourf(array1, array2, Z, cmap=cm, alpha=.8) #将数据集的分布放到咱们的坐标系上 # 将训练集放到图中去 ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright, edgecolors='k') # 将测试集放到图中去 ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, edgecolors='k', alpha=0.6) #为图设置坐标轴的最大值和最小值 ax.set_xlim(array1.min(), array1.max()) ax.set_ylim(array2.min(), array2.max()) #设定坐标轴不显示标尺也不显示数字 ax.set_xticks(()) ax.set_yticks(()) #咱们有三个坐标系,但咱们只须要在第一个坐标系上有标题,所以设定if ds_index==0这个条件 if ds_index == 0: ax.set_title("Decision Tree") #写在右下角的数字 ax.text(array1.max() - .3, array2.min() + .3, ('{:.1f}%'.format(score*100)), size=15, horizontalalignment='right') #让i继续加一 i += 1 plt.tight_layout() plt.show()
结果:
从图上来看,每一条线都是决策树在二维平面上画出的一条决策边界,每当决策树分枝一次,就有一条线出现。当数据的维度更高的时候,这条决策边界就会由线变成面,甚至变成咱们想象不出的多维图形。
同时,很容易看得出,分类树天生不擅长环形数据。每一个模型都有本身的决策上限,因此一个怎样调整都没法提高表现的可能性也是有的。当一个模型怎么调整都不行的时候,咱们能够选择换其余的模型使用,不要在一棵树上吊死。顺便一说,最擅长月亮型数据的是最近邻算法,RBF支持向量机和高斯过程;最擅长环形数据的是最近邻算法和高斯过程;最擅长对半分的数据的是朴素贝叶斯,神经网络和随机森林。