Press "Enter" to skip to content

sklearn专题一:决策树

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

目录

 

1.1 决策树是如何工作的

 

1.2 sklearn中的决策树

 

2  DecisionTreeClassifier与红酒数据集

 

2.1.2 random_state & splitter

 

3. DecisionTreeRegressor

 

3.1重要参数,属性及接口

 

3.2 实例:一维回归的图像绘制

 

4 实例:泰坦尼克号幸存者的预测

 

决策树

 

1 概述

 

1.1 决策树是如何工作的

 

决策树( Decision     Tree )是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。决策树算法容易理解,适用各种数据,在解决各   种问题时都有良好表现,尤其是以树模型为核心的各种集成算法,在各个行业和领域都有广泛的应用。

 

我们来简单了解一下决策树是如何工作的。决策树算法的本质是一种图结构,我们只需要问一系列问题就可以对数 据进行分类了。比如说,来看看下面这组数据集,这是一系列已知物种以及所属类别的数据:

 

 

我们现在的目标是,将动物们分为哺乳类和非哺乳类。那根据已经收集到的数据,决策树算法为我们算出了下面的 这棵决策树:

 

 

假如我们现在发现了一种新物种Python,它是冷血动物,体表带鳞片,并且不是胎生,我们就可以通过这棵决策 树来判断它的所属类别。

 

可以看出,在这个决策过程中,我们一直在对记录的特征进行提问。最初的问题所在的地方叫做 根节点 ,在得到结 论前的每一个问题都是 中间节点 ,而得到的每一个结论(动物的类别)都叫做 叶子节点 。

 

关键概念:节点

 

根节点:没有进边,有出边。包含最初的,针对特征的提问。

 

中间节点:既有进边也有出边,进边只有一条,出边可以有很多条。都是针对特征的提问。 叶子节点:有进边,没有出边, 每个叶子节点都是一个类别标签 。

 

* 子节点和父节点:在两个相连的节点中,更接近根节点的是父节点,另一个是子节点。

 

决策树算法的核心是要解决两个问题:

 

 

    1. 如何从数据表中找出最佳节点和最佳分枝?

 

    1. 如何让决策树停止生长,防止过拟合?

 

 

几乎所有决策树有关的模型调整方法,都围绕这两个问题展开。这两个问题背后的原理十分复杂,我们会在讲解模 型参数和属性的时候为大家简单解释涉及到的部分。在这门课中,我会尽量避免让大家太过深入到决策树复杂的原 理和数学公式中(尽管决策树的原理相比其他高级的算法来说是非常简单了), 这门课会专注于实践和应用。如果 大家希望理解更深入的细节,建议大家在听这门课之前还是先去阅读和学习一下决策树的原理。

 

1.2 sklearn 中的决策树

 

模块 sklearn.tree

 

sklearn 中决策树的类都在 ”tree“ 这个模块之下。这个模块总共包含五个类:

tree.DecisionTreeClassifier

分类树

tree.DecisionTreeRegressor

回归树

tree.export_graphviz

将生成的决策树导出为 DOT 格式,画图专用

tree.ExtraTreeClassifier

高随机版本的分类树

tree.ExtraTreeRegressor

高随机版本的回归树

 

我们会主要讲解分类树和回归树,并用图像呈现给大家。

 

sklearn 的基本建模流程

 

在那之前,我们先来了解一下 sklearn 建模的基本流程。

 

 

在这个流程下,分类树对应的代码是:

 

from sklearn import tree #导入需要的模块
clf = tree.DecisionTreeClassifier()     #实例化
clf = clf.fit(X_train,y_train) #用训练集数据训练模型
result = clf.score(X_test,y_test) #导入测试集,从接口中调用需要的信息

 

2  DecisionTreeClassifier 与红酒数据集

 

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 )

 

2.1 重要参数

 

criterion

 

为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法,对分类树来说,衡量这个 “ 最佳 ” 的指标    叫做 “ 不纯度 ” 。通常来说,不纯度越低,决策树对训练集的拟合越好。现在使用的决策树算法在分枝方法上的核心    大多是围绕在对某个不纯度相关指标的最优化上。

 

不纯度基于节点来计算,树中的每个节点都会有一个不纯度,并且子节点的不纯度一定是低于父节点的,也就是   说,在同一棵决策树上,叶子节点的不纯度一定是最低的。

 

Criterion 这个参数正是用来决定不纯度的计算方法的。 sklearn 提供了两种选择: 1 )输入 ”entropy“ ,使用 信息熵 ( Entropy )

 

 

    1. 输入 ”gini“ ,使用 基尼系数 ( Gini   Impurity )

 

    1. 输入 ”gini“ ,使用 基尼系数 ( Gini Impurity )

 

 

 

其中 t 代表给定的节点,i代表标签的任意分类, 代表标签分类i在节点 t 上所占的比例。注意,当使用信息熵 时, sklearn 实际计算的是基于信息熵的信息增益 (Information Gain) ,即父节点的信息熵和子节点的信息熵之差。

 

比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是 在实际使用中,信息熵和基尼系数的效果基   本相同。 信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏 感,所以信息熵作为指标时,决策树的生长会更加 “ 精细 ” ,因此对于高维数据或者噪音很多的数据,信息熵很容易    过拟合,基尼系数在这种情况下效果往往比较好。当模型拟合程度不足的时候,即当模型在训练集和测试集上都表 现不太好的时候,使用信息熵。当然,这些不是绝对的。

 

参数

criterion

如何影响模型 ?确定不纯度的计算方法,帮忙找出最佳节点和最佳分枝,不纯度越低,决策树对训练集 的拟合越好
可能的输入有哪 些?不填默认基尼系数,填写 gini 使用基尼系数,填写 entropy 使用信息增益
怎样选取参数?通常就使用基尼系数

数据维度很大,噪音很大时使用基尼系数

维度低,数据比较清晰的时候,信息熵和基尼系数没区别 当决策树的拟合程度不够的时候,使用信息熵

两个都试试,不好就换另外一个

 

到这里,决策树的基本流程其实可以简单概括如下:

 

 

直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。

 

建立一棵树

 

1. 导入需要的算法库和模块

 

# 导入需要的算法库和模块
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import graphviz

 

2. 探索数据

 

# 探索数据,也就是查看数据长什幺样子
wine = load_wine()
print(wine.data.shape)   #(178, 13)
print(wine.target)

 

输出

 

(178, 13)
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]

 

# 查看表长什幺样子
import pandas as pd
table=pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)
print(table)

 

 

#查看表头的名字
print(wine.feature_names)
#查看表的分类
print(wine.target_names)

 

['alcohol', 'malic_acid', 'ash', 'alcalinity_of_ash', 'magnesium', 'total_phenols', 'flavanoids', 'nonflavanoid_phenols', 'proanthocyanins', 'color_intensity', 'hue', 'od280/od315_of_diluted_wines', 'proline']
['class_0' 'class_1' 'class_2']

 

3.​​​​​​​ 分训练集和测试集

 

Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
print(Xtrain.shape)  #(124, 13)
print(Xtest.shape)   #(54, 13)

 

4.​​​​​​​ 建立模型

 

clf = tree.DecisionTreeClassifier(criterion="entropy")
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
print(score)

 

5.画出一棵树吧

 

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.replace("helvetica", "MicrosoftYaHei"))
graph.view()

 

 

​​​​​​​6. 探索决策树

 

#特征重要性
clf.feature_importances_

 

array([0.02089151, 0.01416599, 0.        , 0.03389895, 0.        ,
       0.        , 0.44769643, 0.        , 0.        , 0.17234392,
       0.        , 0.        , 0.3110032 ])

 

[*zip(feature_name,clf.feature_importances_)]

 

[('酒精', 0.020891507777503787),
 ('苹果酸', 0.014165989652962183),
 ('灰', 0.0),
 ('灰的碱性', 0.033898949274323104),
 ('镁', 0.0),
 ('总酚', 0.0),
 ('类黄酮', 0.4476964329287443),
 ('非黄烷类酚类', 0.0),
 ('花青素', 0.0),
 ('颜色强度', 0.17234391840479193),
 ('色调', 0.0),
 ('od280/od315稀释葡萄酒', 0.0),
 ('脯氨酸', 0.31100320196167475)]

 

我们已经在只了解一个参数的情况下,建立了一棵完整的决策树。但是回到步骤 4 建立模型, score 会在某个值附近    波动,引起步骤 5 中画出来的每一棵树都不一样。它为什幺会不稳定呢?如果使用其他数据集,它还会不稳定吗?

 

我们之前提到过,无论决策树模型如何进化,在分枝上的本质都还是追求某个不纯度相关的指标的优化,而正如我 们提到的,不纯度是基于节点来计算的,也就是说,决策树在建树时,是靠优化节点来追求一棵优化的树,但最优 的节点能够保证最优的树吗?集成算法被用来解决这个问题: sklearn 表示,既然一棵树不能保证最优,那就建更     多的不同的树,然后从中取最好的。怎样从一组数据集中建不同的树?在每次分枝时,不从使用全部特征,而是随 机选取一部分特征,从中选取不纯度相关指标最优的作为分枝用的节点。这样,每次生成的树也就不同了。

 

clf = tree.DecisionTreeClassifier(criterion="entropy"
                                    ,random_state=30
                                    )
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
score

 

2.1.2​​​​​​​​​​​​​​  random_state &   splitter

 

clf = tree.DecisionTreeClassifier(criterion="entropy"
                                    ,random_state=30
                                    ,splitter="random" 
                                    #splitter也是用来控制决策树中的随机选项,默认best
                                    )
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
score
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

 

2.1.3  剪枝参数

 

在不加限制的情况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止。这样的决策树 往往会过拟合,这就是说, 它会在训练集上表现很好,在测试集上却表现糟糕。 我们收集的样本数据不可能和整体 的状况完全一致,因此当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪 声,并使它对未知数据的拟合程度不足。

 

 

为了让决策树有更好的泛化性,我们要对决策树进行剪枝。 剪枝策略对决策树的影响巨大,正确的剪枝策略是优化   决策树算法的核心。 sklearn 为我们提供了不同的剪枝策略:

max_depth

限制树的最大深度,超过设定深度的树枝全部剪掉

 

这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所  以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。实际使用时,建议从 =3 开始尝试,看看拟合的效 果再决定是否增加设定深度。

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
                                ,out_file = None
                                ,feature_names= feature_name
                                ,class_names=["琴酒","雪莉","贝尔摩德"]
                                ,filled=True
                                ,rounded=True
                                )
graph = graphviz.Source(dot_data.replace("helvetica", "MicrosoftYaHei"))
graph.view()

 

max_features & min_impurity_decrease

一般 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
%matplotlib inline
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()

 

 

2.1.4 ​​​​​​​ 目标权重参数

 

class_weight & min_weight_fraction_leaf

 

完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。比如说,在银行要 判断 “ 一个办了信用卡的人是否会违约 ” ,就是是 vs 否( 1% : 99% )的比例。这种分类状况下,即便模型什幺也不     做,全把结果预测成 “ 否 ” ,正确率也能有 99% 。因此我们要使用 class_weight 参数对样本标签进行一定的均衡,给    少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认 None ,此模式表示自动给     与数据集中的所有标签相同的权重。

 

有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配 min_ weight_fraction_leaf 这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如 min_weight_ fraction_leaf ) 将比不知道样本权重的标准(比如 min_samples_leaf ) 更少偏向主导类。如果样本是加权的,则使     用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。

 

​​​​​​​2.2 重要属性和接口

 

属性是在模型训练之后,能够调用查看的模型的各种性质。对决策树来说,最重要的是 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)

 

 

至此,我们已经学完了分类树 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

 

3. DecisionTreeRegressor

 

class ( 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 这样的参数。

 

3.1重要参数,属性及接口

 

criterion

 

回归树衡量分枝质量的指标,支持的标准有三种:

 

 

    1. 输入 “mse” 使用均方误差 mean    squared    error(MSE) ,父节点和叶子节点之间的均方误差的差额将被用来作为 特征选择的标准,这种方法通过使用叶子节点的均值来最小化 L2 损失

 

    1. 输入 “friedman_mse” 使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差 3 )输入 “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 去掉负号的数字。

 

简单看看回归树是怎样工作的

 

from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score 
from sklearn.tree import DecisionTreeRegressor

 

boston = load_boston()
regressor = DecisionTreeRegressor(random_state=0)
cross_val_score(regressor, boston.data, boston.target, cv=10,
    scoring = "neg_mean_squared_error")
#交叉验证cross_val_score的用法

regressor:模型
boston.data:完整数据集
boston.target:完整标签
cv=10:交叉次数
scoring = “neg_mean_squared_error”  :得分,指定的是负均方误差

array([-16.41568627, -10.61843137, -18.30176471, -55.36803922,
       -16.01470588, -43.57745098, -12.2148    , -95.2186    ,
       -57.764     , -37.9534    ])

 

交叉验证是用来观察模型的稳定性的一种方法,我们将数据划分为 n 份,依次使用其中一份作为测试集,其他 n-1 份 作为训练集,多次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,因此   用交叉验证 n 次的结果求出的平均值,是对模型效果的一个更好的度量。

 

 

​​​​​​​3.2 实例:一维回归的图像绘制

 

接下来我们到二维平面上来观察决策树是怎样拟合一条曲线的。我们用回归树来拟合正弦曲线,并添加一些噪声来 观察回归树的表现。

 

1.导入需要的库

 

import numpy as np
from sklearn.tree import DecisionTreeRegressor 
import matplotlib.pyplot as plt

 

2.创建一条含有噪声的正弦曲线

 

在这一步,我们的基本思路是,先创建一组随机的,分布在 0~5 上的横坐标轴的取值 (x) ,然后将这一组值放到 sin 函 数中去生成纵坐标的值 (y) ,接着再到 y 上去添加噪声。全程我们会使用 numpy 库来为我们生成这个正弦曲线。

 

rng = np.random.RandomState(1)
X = np.sort(5 * rng.rand(80,1), axis=0) 
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - rng.rand(16))
#np.random.rand(数组结构),生成随机数组的函数
#了解降维函数ravel()的用法
np.random.random((2,1)) 
np.random.random((2,1)).ravel() 
np.random.random((2,1)).ravel().shape

 

3.实例化&训练模型

 

regr_1 = DecisionTreeRegressor(max_depth=2) 
regr_2 = DecisionTreeRegressor(max_depth=5) 
regr_1.fit(X, y)
regr_2.fit(X, y)

 

4. 测试集导入模型,预测结果

 

X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis] 
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)

 

plt.figure()
plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data") 
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 参数控制 )     设置得太高,则决策树学习得太精细,它从训练数据中学了很多细节,包括噪声得呈现,从而使模型偏离真实的正   弦曲线,形成过拟合。

 

4 实例:泰坦尼克号幸存者的预测

 

泰坦尼克号的沉没是世界上最严重的海难事故之一,今天我们通过分类树模型来预测一下哪些人可能成为幸存者。 数据集来源 Titanic – Machine Learning from Disaster | Kaggle

 

1.导入所需要的的库

 

#1.导入所需要的的库
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

 

2.导入数据集,探索数据

 

#2.导入数据集,探索数据
data=pd.read_csv(r"E:\数据分析师学习\jupyter notebook\泰坦尼克号数据.csv",engine='python',index_col=0)
data.head()

 

 

data.info()

 

​​​​​​​

 

3.对数据集进行预处理

 

3.1删除缺失值过多的列,和观察判断来说和预测的y没有关系的列

 

#删除缺失值过多的列,和观察判断来说和预测的y没有关系的列
data.drop(["Cabin","Name","Ticket"],inplace=True,axis=1)
data.head()

 

 

3.2处理缺失值,对缺失值较多的列进行填补,有一些特征只确实一两个值,可以采取直接删除记录的方法

 

#处理缺失值,对缺失值较多的列进行填补,有一些特征只确实一两个值,可以采取直接删除记录的方法
data["Age"]=data["Age"].fillna(data["Age"].mean())
data.info()

 

 

#对少量空值的行直接删掉
data=data.dropna() 
data.info()

 

 

3.2将分类变量转换成数值型变量

 

3.2.1将二分类变量转换成数字型变量

 

astype能够将一个pandas对象转换为某种类型,和apply(int(x))不同,astype可以将文本类转换为数字,用这    个方式可以很便捷地将二分类特征转换为0~1

 

data["Sex"]=(data["Sex"]=="male").astype("int")
data.head()

 

 

3.2.2将三分类变量转换成数值型变量

 

labels=data["Embarked"].unique().tolist()
data["Embarked"]=data["Embarked"].apply(lambda x:labels.index(x))
data.head(10)

 

 

4.提取标签和特征矩阵,分测试集和训练集

 

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.info()

 

 

5.导入模型,策略跑一下查看结果

 

clf = DecisionTreeClassifier(random_state=1) 
clf = clf.fit(Xtrain, Ytrain)
score1 = clf.score(Xtest, Ytest)
score1

 

结果:0.7640449438202247

 

用交叉验证:

 

score = cross_val_score(clf,x,y,cv=10).mean()
score

 

结果:0.7739402451481103

 

6.在不同max_depth下观察模型的拟合状况

 

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(Xtest, Ytest)
    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)) #指定横坐标
plt.legend()
plt.show()

 

 

7.用网格搜索调整参数

 

import numpy as np
gini_thresholds = np.linspace(0,0.5,20)
parameters = {'splitter':('best','random')
                        ,'criterion':("gini","entropy")
                        ,"max_depth":[*range(1,10)]
                        ,'min_samples_leaf':[*range(1,50,5)]
                        ,'min_impurity_decrease':[*np.linspace(0,0.5,20)]
            }
clf = DecisionTreeClassifier(random_state=25) 
GS = GridSearchCV(clf, parameters, cv=10) 
GS.fit(Xtrain,Ytrain)
GS.best_params_
GS.best_score

 

5.决策树的优缺点

 

决策树优点

 

 

    1. 易于理解和解释,因为树木可以画出来被看见

 

    1. 需要很少的数据准备。其他很多算法通常都需要数据规范化,需要创建虚拟变量并删除空值等。但请注意, sklearn 中的决策树模块不支持对缺失值的处理。

 

    1. 使用树的成本(比如说,在预测数据的时候)是用于训练树的数据点的数量的对数,相比于其他算法,这是  一个很低的成本。

 

    1. 能够同时处理数字和分类数据,既可以做回归又可以做分类。其他技术通常专门用于分析仅具有一种变量类  型的数据集。

 

    1. 能够处理多输出问题,即含有多个标签的问题,注意与一个标签中含有多种标签分类的问题区别开

 

    1. 是一个白盒模型,结果很容易能够被解释。如果在模型中可以观察到给定的情况,则可以通过布尔逻辑轻松  解释条件。相反,在黑盒模型中(例如,在人工神经网络中),结果可能更难以解释。

 

    1. 可以使用统计测试验证模型,这让我们可以考虑模型的可靠性。

 

    1. 即使其假设在某种程度上违反了生成数据的真实模型,也能够表现良好。

 

 

决策树的缺点

 

 

    1. 决策树学习者可能创建过于复杂的树,这些树不能很好地推广数据。 这称为过度拟合。修剪,设置叶节点所  需的最小样本数或设置树的最大深度等机制是避免此问题所必需的,而这些参数的整合和调整对初学者来说  会比较晦涩

 

    1. 决策树可能不稳定,数据中微小的变化可能导致生成完全不同的树,这个问题需要通过集成算法来解决。

 

    1. 决策树的学习是基于贪婪算法,它靠优化局部最优(每个节点的最优)来试图达到整体的最优,但这种做法  不能保证返回全局最优决策树。这个问题也可以由集成算法来解决,在随机森林中,特征和样本会在分枝过  程中被随机采样。

 

    1. 有些概念很难学习,因为决策树不容易表达它们,例如 XOR ,奇偶校验或多路复用器问题。

 

    1. 如果标签中的某些类占主导地位,决策树学习者会创建偏向主导类的树。因此,建议在拟合决策树之前平衡  数据集。

 

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注