200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 机器学习笔记(通俗易懂)---决策树算法介绍(6)---附完整代码

机器学习笔记(通俗易懂)---决策树算法介绍(6)---附完整代码

时间:2021-10-20 18:53:40

相关推荐

机器学习笔记(通俗易懂)---决策树算法介绍(6)---附完整代码

机器学习笔记—决策树算法介绍(6)—附完整代码

以下都是本人在学习机器学习过程中的一些心得和笔记,仅供参考。

文章目录

机器学习笔记---决策树算法介绍(6)---附完整代码1.构造决策树2.控制决策树的复杂度3.分析决策树4.树的特征重要性5.优缺点和参数5.优缺点和参数决策树是广泛用于分类和回归任务的模型。本质上,它从一层层的if/else问题中进行学习,并且得出结论!

如果你要区分四种动物:熊、鹰、企鹅和海豚,可以转换成一颗决策树来表示。

mglearn.plots.plot_animal_tree()

图为 区分几种动物的决策树

在这张图中,树的每个节点代表一个问题或者一个包含答案的终结点(叶结点)。树的边将问题的答案与将问的下一个问题连接起来。

用机器学习的语言来说就是,为了区分四类动物(熊、鹰、企鹅和海豚),我们利用三个特征(“有没有羽毛”,“会不会飞”,“有没有鳍”)来构建一个模型。

1.构造决策树

我们在下面的二维分类数据集上构造决策树,这个two_moons数据集由2个半月组成,每个类别都包含50个数据点。

在机器学习中,用于分类的方法叫做测试。数据通常不是像动物分类的例子那样具有二元特征(是/否)的形式,而是表示为连续特征。用于连续数据的测试形式是:“特征i的值是否大于a?”

mglearn.plots.plot_tree_progressive()

图为 two_moos数据集

图为 深度为1的树的决策边界为了构造决策树,算法搜遍所有可能的测试,找出对目标变量来说信息量最大的那一个。

上图选出了第一个测试,将数据集在x[1]=0.0596处垂直划分可以得到最多信息,它在最大程度上将类别 0 中的点与类别 1 中的点进行区分。

右侧的决策树,通过测试x[1] <=0.0596的真假来对数据集进行划分,在图中表示为一条黑线。

如果测试结果为真,那么将这个点分配给左结点,左结点里包含属于类别 0 的 2 个点和属于类别 1 的 32 个点。否则将这个点分配给右结点,右结点里包含属于类别 0 的 48 个点和属于类别 1 的 18 个点。

图为 深度为2的树的决策边界

尽管第一次划分已经对两个类别做了很好的区分,但底部区域仍包含属于类别 0 的点,顶部区域也仍包含属于类别 1 的点。我们可以在两个区域中重复寻找最佳测试的过程,从而构建出更准确的模型。

上图展示了信息量最大的下一次划分,这次划分是基于x[0]做出的,分为左右两个区域。

这一递归过程生成一棵二元决策树,其中每个结点都包含一个测试。或者你可以将每个测试看成沿着一条轴对当前数据进行划分。这是一种将算法看作分层划分的观点。由于每个测试仅关注一个特征,所以划分后的区域边界始终与坐标轴平行。

对数据反复进行递归划分,直到划分后的每个区域(决策树的每个叶结点)只包含单一目标值(单一类别或单一回归值)。如果树中某个叶结点所包含数据点的目标值都相同,那么这个叶结点就是纯的(pure)。这个数据集的最终划分结果见下图。

图为 深度为9的树的决策边界想要对新数据点进行预测,首先要查看这个点位于特征空间划分的哪个区域,然后将该区域的多数目标值(如果是纯的叶结点,就是单一目标值)作为预测结果。从根结点开始对树进行遍历就可以找到这一区域,每一步向左还是向右取决于是否满足相应的测试。决策树也可以用于回归任务,使用的方法完全相同。预测的方法是,基于每个结点的测试对树进行遍历,最终找到新数据点所属的叶结点。这一数据点的输出即为此叶结点中所有训练点的平均目标值

2.控制决策树的复杂度

为什么要控制决策树的复杂度,就是防止过拟合。

通常来说,构造决策树直到所有叶结点都是纯的叶结点,这会导致模型非常复杂,并且对训练数据高度过拟合。纯叶结点的存在说明这棵树在训练集上的精度是 100%。训练集中的每个数据点都位于分类正确的叶结点中。有的决策边界过于关注远离同类别其他点的单个异常点。

防止过拟合有两种常见的策略:

预剪枝pre-pruning),及早停止树的生长后剪枝post-pruning)或剪枝pruning),先构造树,但随后删除或折叠信息量很少的结点

预剪枝的限制条件可能包括限制树的最大深度、限制叶结点的最大数目,或者规定一个结点中数据点的最小数目来防止继续划分。

scikit-learn的决策树在DecisionTreeRegressor类和DecisionTreeClassifier类中实现。D但是scikit-learn只实现了预剪枝,没有实现后剪枝。

下面我们在乳腺癌数据集上更详细地看一下预剪枝的效果。运行代码如下:

In

from sklearn.tree import DecisionTreeClassifierfrom sklearn.datasets import load_breast_cancerfrom sklearn.model_selection import train_test_split#加载数据cancer = load_breast_cancer()#分离数据,stratify作用为以分层方式分割数据,保持测试集与整个数据集里cancer.target的数据分类比例一致#随机数种子为42X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)#调用函数tree = DecisionTreeClassifier(random_state=0)#训练模型tree.fit(X_train, y_train)print("Accuracy on training set: {:.3f}".format(tree.score(X_train, y_train)))print("Accuracy on test set: {:.3f}".format(tree.score(X_test, y_test)))

Out

Accuracy on training set: 1.000Accuracy on test set: 0.937

不出所料,训练集上的精度是 100%,这是因为叶结点都是纯的,树的深度很大,足以完美地记住训练数据的所有标签。测试集精度比之前讲过的线性模型略低,线性模型的精度约为95%。

如果我们不限制决策树的深度,它的深度和复杂度都可以变得特别大。因此,未剪枝的树容易过拟合,对新数据的泛化性能不佳

现在我们将预剪枝应用在决策树上,这样可以在完美拟合训练数据之前阻止树的展开

这里我们设置max_depth=4,这意味着只可以连续问4个问题,限制树的深度可以减少过拟合,会降低训练集的精度,但可以提高测试集的精度

In

from sklearn.tree import DecisionTreeClassifierfrom sklearn.datasets import load_breast_cancerfrom sklearn.model_selection import train_test_split#加载数据cancer = load_breast_cancer()#分离数据,stratify作用为以分层方式分割数据,保持测试集与整个数据集里cancer.target的数据分类比例一致#随机数种子为42X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)#调用函数tree = DecisionTreeClassifier(max_depth=4, random_state=0)tree.fit(X_train, y_train)print("Accuracy on training set: {:.3f}".format(tree.score(X_train, y_train)))print("Accuracy on test set: {:.3f}".format(tree.score(X_test, y_test)))

Out

Accuracy on training set: 0.988Accuracy on test set: 0.951

3.分析决策树

我们可以利用tree模块的export_graphviz函数来将树可视化。

这个函数会生成一个.dot格式的文件,这是一种用于保存图形的文本文件格式。

from sklearn.tree import export_graphvizexport_graphviz(tree, out_file="tree.dot", class_names=["malignant", "benign"],feature_names=cancer.feature_names, impurity=False, filled=True)

我们可以利用graphviz模块读取这个文件并将其可视化:

import graphvizwith open("tree.dot") as f:dot_graph = f.read()display(graphviz.Source(dot_graph))

图为 机器乳腺癌数据集构造的决策树的可视化

4.树的特征重要性

查看整个树可能非常费劲,除此之外,我还可以利用一些有用的属性来总结树的工作原理。

其中最常用的是特征重要性(feature importance),它为每个特征对树的决策的重要性进行排序。对于每个特征来说,它都是一个介于0和1之间的数字,其中0表示“根本没有用到”,1表示“完美预测目标”。特征重要性之和始终为1。

In

from sklearn.tree import DecisionTreeClassifierfrom sklearn.datasets import load_breast_cancerfrom sklearn.model_selection import train_test_splitcancer = load_breast_cancer()#分离数据,stratify作用为以分层方式分割数据,保持测试集与整个数据集里cancer.target的数据分类比例一致#随机数种子为42X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)#调用函数,max_depth参数代表深度tree = DecisionTreeClassifier(max_depth=4,random_state=0)#训练模型tree.fit(X_train, y_train)print("Feature importances:\n{}".format(tree.feature_importances_))

Out

Feature importances:[0. 0. 0. 0. 0. 0.0. 0. 0. 0. 0.01019737 0.048398250. 0. 0.0024156 0. 0. 0.0. 0. 0.72682851 0.0458159 0. 0.0.0141577 0. 0.018188 0.1221132 0.01188548 0. ]

将特征重要性可视化:

from sklearn.tree import DecisionTreeClassifierfrom sklearn.datasets import load_breast_cancerfrom sklearn.model_selection import train_test_splitimport matplotlib.pyplot as pltimport numpy as npcancer = load_breast_cancer()#分离数据,stratify作用为以分层方式分割数据,保持测试集与整个数据集里cancer.target的数据分类比例一致#随机数种子为42X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)#调用函数,max_depth参数代表深度tree = DecisionTreeClassifier(max_depth=4,random_state=0)#训练模型tree.fit(X_train, y_train)def plot_feature_importance_cancer(model):#.shape[1]表示矩阵的第二维的长度,在这里就是特征的长度n_features = cancer.data.shape[1]plt.barh(range(n_features), model.feature_importances_, align='center')#前者代表y坐标轴的各个刻度,后者代表各个刻度位置的显示的lableplt.yticks(np.arange(n_features), cancer.feature_names)plt.xlabel("Feature importance")plt.ylabel("Feature")plt.show() plot_feature_importance_cancer(tree)

图为 在乳腺癌数据集上学到的决策树的特征重要性从图中我们可以看到,顶部划分用到的特征worst radius是最重要的特征。这也证实了我们在分析树时的观察结论,即第一层划分已经将两个类别区分得很好。但是,如果某个特征的feature_importance_并不能说明这个特征没有提供任何信息。这只能说明该特征没有被树选中,可能是因为另一个特征也包含了同样的信息。与线性模型的系数不同特征重要性始终为正数,也不能说明该特征对应哪个类别。特征重要性告诉我们worst radius最大半径)特征很重要,但并没有告诉我们半径大表示样本是良性还是恶性。事实上,在特征和类别之间可能没有这样简单的关系,可以在下面的图片中可以看出这一点。

图为 一个二维数据集与决策树给出的决策边界

图为 学习得到的决策树

虽然我们主要讨论的是用于分类的决策树,但对用于回归的决策树来说,所有内容都是类似的,在DecisionTreeRegressor中实现。

回归树的用法和分析与分类树非常类似。但在将基于树的模型用于回归时,我们想要指出它的一个特殊性质。DecisionTreeRegressor(以及其他所有基于树的回归模型)不能外推加粗样式(extrapolate),也不能在训练数据范围之外进行预测。

5.优缺点和参数

参数:控制决策树模型复杂度的参数是预剪枝参数,它在树完全展开之前停止树的构造。通常来说,选择一种预剪枝策略(设置max_depthmax_leaf_nodesmin_samples_leaf)足以防止过拟合。优点:是得到的模型很容易可视化,非专家也很容易理解(至少对于较小的树而言);是算法完全不受数据缩放的影响,不需要特征预处理。缺点:即使做了预剪枝,它也经常会过拟合,泛化性能很差。因此,在大多数应用中,往往使用决策树集成代替单颗决策树。

5.优缺点和参数

参数:控制决策树模型复杂度的参数是预剪枝参数,它在树完全展开之前停止树的构造。通常来说,选择一种预剪枝策略(设置max_depthmax_leaf_nodesmin_samples_leaf)足以防止过拟合。优点:是得到的模型很容易可视化,非专家也很容易理解(至少对于较小的树而言);是算法完全不受数据缩放的影响,不需要特征预处理。缺点:即使做了预剪枝,它也经常会过拟合,泛化性能很差。因此,在大多数应用中,往往使用决策树集成代替单颗决策树。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。