决策树的原理与实践

目录

学习目标

决策树的简介

决策树的应用

决策树构建的伪代码

决策树生成算法:ID3、C4.5、CART

1.ID3

简介:

特征选择(属性划分)方式:

缺点:

C4.5

简介:

特征选择(属性划分)方式:

剪枝策略:

缺点:

CART

简介:

特征选择(属性划分)方式:

缺失值处理:

剪枝策略:

类别不平衡:

回归树:

用自己的理解讲讲决策树算法?

决策树如何防止过拟合?

Demo实践

基于企鹅数据集的决策树实战

sklearn.tree.DecisionTreeClassifier类的参数说明


学习目标

  • 了解 决策树 的理论知识
  • 掌握 决策树sklearn 函数调用使用并将其运用到企鹅数据集预测

决策树的简介

决策树是一种常见的分类模型,在金融分控、医疗辅助诊断等诸多行业具有较为广泛的应用。决策树的核心思想是基于树结构对数据进行划分,这种思想是人类处理问题时的本能方法。例如在婚恋市场中,女方通常会先看男方是否有房产,如果有房产再看是否有车产,如果有车产再看是否有稳定工作……最后得出是否要深入了解的判断。

决策树的主要优点:

  • 便于理解和解释。树的结构可以可视化出来;
  • 训练需要的数据少。其他机器学习模型通常需要数据规范化,比如构建虚拟变量和移除缺失值,不过请注意,这种模型不支持缺失值;
  • 由于训练决策树的数据点的数量导致了决策树的使用开销呈指数分布(训练树模型的时间复杂度是参与训练数据点的对数值);
  • 能够处理数值型数据类别型数据。其他的技术通常只能用来专门分析某一种变量类型的数据集;
  • 能够处理多路输出的问题;
  • 使用白盒模型。如果某种给定的情况在该模型中是可以观察的,那么就可以轻易的通过布尔逻辑来解释这种情况。相比之下,在黑盒模型中的结果就是很难说明清楚;
  • 可以通过数值统计测试来验证该模型。这对解释验证该模型的可靠性成为可能;
  • 即使该模型假设的结果与真实模型所提供的数据有些违反,其表现依旧良好。

决策树的主要缺点:

  • 决策树模型容易生成一个过于复杂的模型,这样的模型对数据的泛化性能会很差。这就是所谓的过拟合。一些策略像剪枝、设置叶节点所需的最小样本数或设置树的最大深度是避免出现该问题最为有效地方法;
  • 决策树可能是不稳定的,因为数据中的微小变化可能会导致完全不同的树生成。这个问题可以通过决策树的集成来得到缓解;
  • 在多方面性能最优和简单化概念的要求下,学习一棵最优决策树通常是一个NP难问题。因此,实际的决策树学习算法是基于启发式算法,例如在每个结点进行局部最优决策的贪心算法。这样的算法不能保证返回全局最优决策树。这个问题可以通过集成学习来训练多棵决策树来缓解,这多棵决策树一般通过对特征和样本有放回的随机采样来生成;
  • 有些概念很难被决策树学习到,因为决策树很难清楚的表述这些概念。例如XOR,奇偶或者复用器的问题;
  • 如果某些类在问题中占主导地位会使得创建的决策树有偏差。因此,我们建议在拟合前先对数据集进行平衡

决策树的应用

由于决策树模型中自变量与因变量的非线性关系以及决策树简单的计算方法,使得它成为集成学习中最为广泛使用的基模型。梯度提升树(GBDT),XGBoost以及LightGBM等先进的集成模型都采用了决策树作为基模型,在广告计算、CTR预估、金融风控等领域大放异彩,成为当今与神经网络相提并论的复杂模型,更是数据挖掘比赛中的常客。在新的研究中,南京大学周志华老师提出一种多粒度级联森林模型,创造了一种全新的基于决策树的深度集成方法,为我们提供了决策树发展的另一种可能。

同时决策树在一些需要明确可解释甚至提取分类规则的场景中被广泛应用,而其他机器学习模型在这一点很难做到。例如在医疗辅助系统中,为了方便专业人员发现错误,常常将决策树算法用于辅助病症检测。例如在一个预测哮喘患者的模型中,医生发现测试的许多高级模型的效果非常差。所以他们在数据上运行了一个决策树的模型,发现算法认为剧烈咳嗽的病人患哮喘的风险很小。但医生非常清楚剧烈咳嗽一般都会被立刻检查治疗,这意味着患有剧烈咳嗽的哮喘病人都会马上得到收治。用于建模的数据认为这类病人风险很小,是因为所有这类病人都得到了及时治疗,所以极少有人在此之后患病或死亡。

决策树构建的伪代码

决策树的构建过程是一个递归过程。函数存在三种返回状态:

  1. 当前节点包含的样本全部属于同一类别,无需继续划分;
  2. 当前属性集为空或者所有样本在某个属性上的取值相同,无法继续划分;
  3. 当前节点包含的样本集合为空,无法划分。

决策树生成算法:ID3、C4.5、CART

1.ID3

ID3 算法是建立在奥卡姆剃刀(用较少的东西,同样可以做好事情)的基础上:越是小型的决策树越优于大的决策树。

简介:

从信息论的知识中我们知道:信息熵越大,样本纯度越低。ID3 算法的核心思想就是以信息增益来度量特征选择,选择信息增益最大的特征进行分裂。算法采用自顶向下的贪婪搜索遍历可能的决策树空间(C4.5 也是贪婪搜索)。 其大致步骤为:

  1. 初始化特征集合和数据集合;
  2. 计算数据集合信息熵和所有特征的条件熵,选择信息增益最大的特征作为当前决策节点;
  3. 更新数据集合和特征集合(删除上一步使用的特征,并按照特征值来划分不同分支的数据集合);
  4. 重复 2,3 两步,若子集值包含单一特征,则为分支叶子节点。

特征选择(属性划分)方式:

ID3 使用的分类标准是信息增益,它表示得知特征 A 的信息而使得样本集合不确定性减少的程度。

数据集的信息熵:

H\left ( D \right ) =-\sum_{k=1}^{K} \frac{\left | C_{k} \right | }{\left | D \right | } \log_{2}{\frac{\left | C_{k} \right | }{\left | D \right | }}

其中C_{k}表示集合 D 中属于第 k 类样本的样本子集。

针对某个特征 A,对于数据集 D 的条件熵H\left ( D \mid A \right )为:

\begin{align*} H\left ( D \mid A \right )&=\sum_{i=1}^{n} \frac{\left | D_{i} \right | }{\left | D \right | } H\left ( D_{i} \right ) \\ &=-\sum_{i=1}^{n}\frac{\left | D_{i} \right | }{\left | D \right | }\left ( \sum_{k=1}^{K} \frac{\left | D_{ik} \right | }{\left | D_{i} \right | }\log_{2}{\frac{\left | D_{ik} \right | }{\left | D_{i} \right | }} \right ) \end{align*}

其中D_{i}表示 D 中特征 A 取第 i 个值的样本子集,D_{ik}表示D_{i}中属于第 k 类的样本子集。

信息增益 = 信息熵 - 条件熵:

Gain\left ( D,A \right ) =H\left ( D \right ) -H\left ( D\mid A \right )

信息增益越大表示使用特征 A 来划分所获得的“纯度提升越大”。

缺点:

  • ID3 没有剪枝策略,容易过拟合
  • 信息增益准则对可取值数目较多的特征有所偏好,类似“编号”的特征其信息增益接近于 1;
  • 只能用于处理离散分布的特征;
  • 没有考虑缺失值

C4.5

C4.5 算法最大的特点是克服了 ID3 对特征数目的偏重这一缺点,引入信息增益率来作为分类标准。

简介:

C4.5 相对于 ID3 的缺点对应有以下改进方式:

  • 引入悲观剪枝策略进行后剪枝;
  • 引入信息增益率作为属性划分方式;
  • 连续特征离散化,假设 n 个样本的连续特征 A 有 m 个取值,C4.5 将其排序并取相邻两样本值的平均数共 m-1 个划分点,分别计算以该划分点作为二元分类点时的信息增益,并选择信息增益最大的点作为该连续特征的二元离散分类点;
  • 对于缺失值的处理可以分为两个子问题:
    • 问:在特征值缺失的情况下如何进行划分特征的选择?(即如何计算特征的信息增益率)
    • 答:对于具有缺失值特征,用没有缺失的样本子集所占比重来折算;
    • 问:选定该划分特征,对于缺失该特征值的样本如何处理?(即到底把这个样本划分到哪个结点里)
    • 答:将样本同时划分到所有子结点,不过要调整样本的权重值,其实也就是以不同概率划分到不同结点中。

特征选择(属性划分)方式:

利用信息增益率可以克服信息增益的缺点,其公式为:

Gain_{ratio} \left ( D,A \right ) =\frac{Gain \left ( D,A \right )}{H_{A}\left ( D \right ) }

H_{A}\left ( D \right )=-\sum_{i=1}^{n} \frac{\left | D_{i} \right | }{\left | D \right | }\log_{2}{\frac{\left | D_{i} \right | }{\left | D \right | }}

H_{A}\left ( D \right )称为特征 A 的固有值。

这里需要注意,信息增益率对可取值较少的特征有所偏好(分母越小,整体越大),因此 C4.5 并不是直接用增益率最大的特征进行划分,而是使用一个启发式方法:先从候选划分特征中找到信息增益高于平均值的特征,再从中选择增益率最高的。

剪枝策略:

预剪枝

在节点划分前来确定是否继续增长,及早停止增长的主要方法有:

  • 节点内数据样本低于某一阈值;
  • 所有节点特征都已分裂;
  • 节点划分前准确率比划分后准确率高。

预剪枝不仅可以降低过拟合的风险而且还可以减少训练时间,但另一方面它是基于“贪心”策略,会带来欠拟合风险。

后剪枝

在已经生成的决策树上进行剪枝,从而得到简化版的剪枝决策树。

C4.5 采用的悲观剪枝方法,用递归的方式从下往上针对每一个非叶子节点,评估用一个最佳叶子节点去代替这课子树是否有益。如果剪枝后与剪枝前相比其错误率是保持或者下降,则这棵子树就可以被替换掉。C4.5 通过训练数据集上的错误分类数量来估算未知样本上的错误率。

后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。但同时其训练时间会大的多。

缺点:

  • 剪枝策略可以再优化;
  • C4.5 用的是多叉树,用二叉树效率更高;
  • C4.5 只能用于分类
  • C4.5 使用的熵模型拥有大量耗时的对数运算,连续值还有排序运算;
  • C4.5 在构造树的过程中,对数值属性值需要按照其大小进行排序,从中选择一个分割点,所以只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时,程序无法运行。

CART

ID3 和 C4.5 虽然在对训练样本集的学习中可以尽可能多地挖掘信息,但是其生成的决策树分支、规模都比较大,CART 算法的二分法可以简化决策树的规模,提高生成决策树的效率。

简介:

CART 包含的基本过程有分裂,剪枝和树选择。

  • 分裂:分裂过程是一个二叉递归划分过程,其输入和预测特征既可以是连续型的也可以是离散型的,CART 没有停止准则,会一直生长下去;
  • 剪枝:采用代价复杂度剪枝,从最大树开始,每次选择训练数据熵对整体性能贡献最小的那个分裂节点作为下一个剪枝对象,直到只剩下根节点。CART 会产生一系列嵌套的剪枝树,需要从中选出一颗最优的决策树;
  • 树选择:用单独的测试集评估每棵剪枝树的预测性能(也可以用交叉验证)。

CART 在 C4.5 的基础上进行了很多提升。

  • C4.5 为多叉树,运算速度慢,CART 为二叉树,运算速度快;
  • C4.5 只能分类,CART 既可以分类也可以回归

  • CART 使用 Gini 系数作为变量的不纯度量,减少了大量的对数运算;
  • CART 采用代理测试来估计缺失值,而 C4.5 以不同概率划分到不同节点中;
  • CART 采用“基于代价复杂度剪枝”方法进行剪枝,而 C4.5 采用悲观剪枝方法

特征选择(属性划分)方式:

熵模型拥有大量耗时的对数运算,基尼指数在简化模型的同时还保留了熵模型的优点。基尼指数代表了模型的不纯度,基尼系数越小,不纯度越低,特征越好。这和信息增益(率)正好相反。

\begin{align*} Gini\left ( D \right )&=\sum_{k=1}^{K} \frac{\left | C_{k} \right | }{\left | D \right | } \left ( 1-\frac{\left | C_{k} \right | }{\left | D \right | } \right ) \\ &=1-\sum_{k=1}^{K}\left ( \frac{\left | C_{k} \right | }{\left | D \right | } \right )^{2} Gini\left ( D\mid A \right ) \\ &=\sum_{i=1}^{n} \frac{\left | D_{i} \right | }{\left | D \right | } Gini\left ( D_{i} \right ) \end{align*}

其中 k 代表类别。

基尼指数反映了从数据集中随机抽取两个样本,其类别标记不一致的概率。因此基尼指数越小,则数据集纯度越高。基尼指数偏向于特征值较多的特征,类似信息增益。基尼指数可以用来度量任何不均匀分布,是介于 0~1 之间的数,0 是完全相等,1 是完全不相等。

此外,当 CART 为二分类,其表达式为:

Gini\left ( D\mid A \right )=\frac{\left | D_{1} \right | }{\left | D \right | } Gini\left ( D_{1} \right ) + \frac{\left | D_{2} \right | }{\left | D \right | } Gini\left ( D_{2} \right )

我们可以看到在平方运算和二分类的情况下,其运算更加简单。当然其性能也与熵模型非常接近。

那么问题来了:基尼指数与熵模型性能接近,但到底与熵模型的差距有多大呢?

我们知道\ln_{}{\left ( x \right ) } =-1+x+o\left ( x \right ),所以

H\left ( X \right ) =-\sum_{k=1}^{K} p_{k} \ln_{}{p_{k} } \approx \sum_{k=1}^{K}p_{k}\left ( 1-p_{k} \right )

我们可以看到,基尼指数可以理解为熵模型的一阶泰勒展开。这边在放上一张很经典的图:

缺失值处理:

  1. 如何在特征值缺失的情况下进行划分特征的选择?
  2. 选定该划分特征,模型对于缺失该特征值的样本该进行怎样处理?

对于问题 1,CART 一开始严格要求分裂特征评估时只能使用在该特征上没有缺失值的那部分数据,在后续版本中,CART 算法使用了一种惩罚机制来抑制提升值,从而反映出缺失值的影响(例如,如果一个特征在节点的 20% 的记录是缺失的,那么这个特征就会减少 20% 或者其他数值)。

对于问题 2,CART 算法的机制是为树的每个节点都找到代理分裂器,无论在训练数据上得到的树是否有缺失值都会这样做。在代理分裂器中,特征的分值必须超过默认规则的性能才有资格作为代理(即代理就是代替缺失值特征作为划分特征的特征),当 CART 树中遇到缺失值时,这个实例划分到左边还是右边是决定于其排名最高的代理,如果这个代理的值也缺失了,那么就使用排名第二的代理,以此类推,如果所有代理值都缺失,那么默认规则就是把样本划分到较大的那个子节点。代理分裂器可以确保无缺失训练数据上得到的树可以用来处理包含缺失值的新数据。

剪枝策略:

采用一种“基于代价复杂度的剪枝”方法进行后剪枝,这种方法会生成一系列树,每个树都是通过将前面的树的某个或某些子树替换成一个叶节点而得到的,这一系列树中的最后一棵树仅含一个用来预测类别的叶节点。然后用一种成本复杂度的度量准则来判断哪棵子树应该被一个预测类别值的叶节点所代替。这种方法需要使用一个单独的测试数据集来评估所有的树,根据它们在测试数据集熵的分类性能选出最佳的树。

类别不平衡:

CART 的一大优势在于:无论训练数据集有多失衡,它都可以将其自动消除不需要建模人员采取其他操作。

CART 使用了一种先验机制,其作用相当于对类别进行加权。这种先验机制嵌入于 CART 算法判断分裂优劣的运算里,在 CART 默认的分类模式中,总是要计算每个节点关于根节点的类别频率的比值,这就相当于对数据自动重加权,对类别进行均衡。

对于一个二分类问题,节点 node 被分成类别 1 当且仅当:

\frac{N_{1} \left ( node \right ) }{N_{1} \left ( root \right ) } > \frac{N_{0} \left ( node \right ) }{N_{0} \left ( root \right ) } diag

比如二分类,根节点属于 1 类和 0 类的分别有 20 和 80 个。在子节点上有 30 个样本,其中属于 1 类和 0 类的分别是 10 和 20 个。如果 10/20>20/80,该节点就属于 1 类。

通过这种计算方式就无需管理数据真实的类别分布。假设有 K 个目标类别,就可以确保根节点中每个类别的概率都是 1/K。这种默认的模式被称为“先验相等”。

先验设置和加权不同之处在于先验不影响每个节点中的各类别样本的数量或者份额。先验影响的是每个节点的类别赋值和树生长过程中分裂的选择。

回归树:

CART(Classification and Regression Tree,分类回归树),从名字就可以看出其不仅可以用于分类,也可以应用于回归。其回归树的建立算法上与分类树部分相似,这里简单介绍下不同之处。

连续值处理

对于连续值的处理,CART 分类树采用基尼系数的大小来度量特征的各个划分点。在回归模型中,我们使用常见的和方差度量方式,对于任意划分特征 A,对应的任意划分点 s 两边划分成的数据集D_{1}D_{2},求出使D_{1}D_{2}各自集合的均方差最小,同时D_{1}D_{2}的均方差之和最小所对应的特征和特征值划分点。表达式为:

\min_{a,s} \left [ \min_{c1} \sum_{x_{i}\in D_{1} } \left ( y_{i} -c_{1} \right )^{2} + \min_{c2} \sum_{x_{i}\in D_{2} } \left ( y_{i} -c_{2} \right )^{2} \right ]

其中, c_{1}D_{1}数据集的样本输出均值,c_{2}D_{2}数据集的样本输出均值。

预测方式

对于决策树建立后做预测的方式,上面讲到了 CART 分类树采用叶子节点里概率最大的类别作为当前节点的预测类别。而回归树输出不是类别,它采用的是用最终叶子的均值或者中位数来预测输出结果。

用自己的理解讲讲决策树算法?

决策树是一种有监督的学习算法,并且属于判别模型。根据属性划分的方式不同,决策树又分为ID3(利用信息增益)、C4.5(利用信息增益比)等,但是它们都只能处理分类,不能处理回归。而CART(利用基尼系数)既可以用于分类,也可以用于回归。

一般情况下,决策树包含一个根结点、若干个内部结点和若干个叶结点;叶结点对应于决策结果,其他每个结点则对应于一个属性测试;每个结点包含的样本集合根据属性测试的结果被划分到子结点中;根节点包含样本全集。

决策树学习的目的是为了生成一棵泛化能力强的决策树。

决策树易于实现,并具有很强的可解释性,能够方便的进行可视化分析

决策树算法相对其他拟合能力强的算法而言,在拟合速度上具有较大优势,能在相对短的时间内对大型数据源做出可行且效果良好的结果。但是,相对较弱的拟合能力也导致决策树容易发生过拟合

决策树如何防止过拟合?

由于决策树生成算法过多地考虑如何提高对训练数据的正确分类,因此会倾向于构建复杂的决策树,这样产生的决策树往往对训练数据的分类很准确,却对未知的测试数据的分类没有那么准确,即出现过拟合现象。

为了缓解决策树过拟合的现象,我们需要对已生成的决策树进行简化,这个简化的过程我们称之为剪枝(pruning)。

具体就是剪掉一些不重要的子树或叶结点,并将其根结点或父结点作为新的叶结点,从而简化树模型。换句话说,剪枝的目的就是得到最优的决策树模型。这个模型不仅对训练数据有很好的分类,对预测数据也能很好地预测。

剪枝又分为预剪枝后剪枝预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化能力的提升,则停止划分并将当前结点标记为叶节点;后剪枝则是先从训练集中生成一颗完整的树,然后自底向上对非叶节点进行考察,若该节点对应的子树替换为叶节点能够提升泛化能力,则进行剪枝将该子树替换为叶节点,否则不剪枝。

很明显,预剪枝技术抑制了很多分支的展开,这样的好处是降低了过拟合的风险,同时还减少了训练时间,缺点是存在欠拟合的风险;预剪枝基于“贪心”策略,往往可以达到局部最优解却不能达到全局最优解,也就是说预剪枝生成的决策树不一定是最佳的决策树。

后剪枝技术通常比预剪枝保留了更多的分支,它是自底向上的剪枝,因此它的欠拟合风险较小,泛化能力往往优于预剪枝,然而因为总是要完全生长一棵树,这就要花费很多时间训练了,因此并不适合在数据集规模大、维度高时使用。

Demo实践

  • Step1: 库函数导入
##  基础函数库
import numpy as np 

## 导入画图库
import matplotlib.pyplot as plt
import seaborn as sns

## 导入决策树模型函数
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
  • Step2: 训练模型
## 构造数据集
x_fearures = np.array([[-1, -2], [-2, -1], [-3, -2], [1, 3], [2, 1], [3, 2]])
y_label = np.array([0, 1, 0, 1, 0, 1])

## 调用决策树模型
tree_clf = DecisionTreeClassifier()

## 用决策树模型拟合构造的数据集
tree_clf = tree_clf.fit(x_fearures, y_label)
  • Step3: 数据和模型可视化(需要用到graphviz可视化库)
## 可视化构造的数据样本点
plt.figure()
plt.scatter(x_fearures[:, 0], x_fearures[:, 1], c=y_label, s=50, cmap='viridis')
plt.title('Dataset')
plt.show()

## 本段代码实际效果为本地生成PDF可视化文档,在体验过程中可以不运行,可能无法正常展示结果;
## 代码生成的可视化结果会截图展示实际效果
!pip install graphviz 
import graphviz
dot_data = tree.export_graphviz(tree_clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("pengunis")
## 'pengunis.pdf'

  • Step4:模型预测
## 创建新样本
x_fearures_new1 = np.array([[0, -1]])
x_fearures_new2 = np.array([[2, 1]])
## 在训练集和测试集上分别利用训练好的模型进行预测
y_label_new1_predict = tree_clf.predict(x_fearures_new1)
y_label_new2_predict = tree_clf.predict(x_fearures_new2)
print('The New point 1 predict class:\n', y_label_new1_predict)
print('The New point 2 predict class:\n', y_label_new2_predict)
# The New point 1 predict class:
 # [1]
# The New point 2 predict class:
 # [0]

基于企鹅数据集的决策树实战

在实践的最开始,我们首先需要导入一些基础的函数库包括:numpy (Python进行科学计算的基础软件包),pandas(pandas是一种快速,强大,灵活且易于使用的开源数据分析和处理工具),matplotlib和seaborn绘图。

  • Step1:函数库导入
##  基础函数库
import numpy as np 
import pandas as pd

## 绘图函数库
import matplotlib.pyplot as plt
import seaborn as sns

本次我们选择企鹅数据(palmerpenguins)进行方法的尝试训练,该数据集一共包含8个变量,其中7个特征变量,1个目标分类变量。共有150个样本,目标变量为 企鹅的类别 其都属于企鹅类的三个亚属,分别是(Adélie, Chinstrap and Gentoo)。包含的三种种企鹅的七个特征,分别是所在岛屿,嘴巴长度,嘴巴深度,脚蹼长度,身体体积,性别以及年龄。

  • Step2:数据读取/载入
## 我们利用Pandas自带的read_csv函数读取并转化为DataFrame格式

data = pd.read_csv('penguins_raw.csv')
## 为了方便我们仅选取四个简单的特征,有兴趣的同学可以研究下其他特征的含义以及使用方法
data = data[['Species', 'Culmen Length (mm)', 'Culmen Depth (mm)', 'Flipper Length (mm)', 'Body Mass (g)']]
  • Step3:数据信息简单查看
## 利用.info()查看数据的整体信息
data.info()
## <class 'pandas.core.frame.DataFrame'>
## RangeIndex: 344 entries, 0 to 343
## Data columns (total 5 columns):
## Species                344 non-null object
## Culmen Length (mm)     342 non-null float64
## Culmen Depth (mm)      342 non-null float64
## Flipper Length (mm)    342 non-null float64
## Body Mass (g)          342 non-null float64
## dtypes: float64(4), object(1)
## memory usage: 13.6+ KB
## 进行简单的数据查看,我们可以利用 .head() 头部.tail()尾部
data.head()

这里我们发现数据集中存在NaN,一般的我们认为NaN在数据集中代表了缺失值,可能是数据采集或处理时产生的一种错误。这里我们采用-1将缺失值进行填补,还有其他例如“中位数填补平均数填补”的缺失值处理方法有兴趣的同学也可以尝试。

data = data.fillna(-1)
data.tail()

## 其对应的类别标签为'Adelie Penguin', 'Gentoo penguin', 'Chinstrap penguin'三种不同企鹅的类别。
data['Species'].unique()
## array(['Adelie Penguin (Pygoscelis adeliae)',
##       'Gentoo penguin (Pygoscelis papua)',
##       'Chinstrap penguin (Pygoscelis antarctica)'], dtype=object)
## 利用value_counts函数查看每个类别数量
pd.Series(data['Species']).value_counts()
## Adelie Penguin (Pygoscelis adeliae)          152
## Gentoo penguin (Pygoscelis papua)            124
## Chinstrap penguin (Pygoscelis antarctica)     68
## Name: Species, dtype: int64
## 对于特征进行一些统计描述
data.describe()

  • Step4:可视化描述
## 特征与标签组合的散点可视化
sns.pairplot(data=data, diag_kind='hist', hue= 'Species')
plt.show()

从上图可以发现,在2D情况下不同的特征组合对于不同类别的企鹅的散点分布,以及大概的区分能力。

'''为了方便我们将标签转化为数字
       'Adelie Penguin (Pygoscelis adeliae)'        ------0
       'Gentoo penguin (Pygoscelis papua)'          ------1
       'Chinstrap penguin (Pygoscelis antarctica)   ------2 '''

def trans(x):
    if x == data['Species'].unique()[0]:
        return 0
    if x == data['Species'].unique()[1]:
        return 1
    if x == data['Species'].unique()[2]:
        return 2

data['Species'] = data['Species'].apply(trans)
for col in data.columns:
    if col != 'Species':
        sns.boxplot(x='Species', y=col, saturation=0.5, palette='pastel', data=data)
        plt.title(col)
        plt.show()

利用箱型图我们也可以得到不同类别在不同特征上的分布差异情况。

# 选取其前三个特征绘制三维散点图
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

data_class0 = data[data['Species'] == 0].values
data_class1 = data[data['Species'] == 1].values
data_class2 = data[data['Species'] == 2].values
# 'setosa'(0), 'versicolor'(1), 'virginica'(2)
ax.scatter(data_class0[:, 0], data_class0[:, 1], data_class0[:, 2],label=data['Species'].unique()[0])
ax.scatter(data_class1[:, 0], data_class1[:, 1], data_class1[:, 2],label=data['Species'].unique()[1])
ax.scatter(data_class2[:, 0], data_class2[:, 1], data_class2[:, 2],label=data['Species'].unique()[2])
plt.legend()

plt.show()

  • Step5:利用 决策树模型 在二分类上 进行训练和预测
## 为了正确评估模型性能,将数据划分为训练集和测试集,并在训练集上训练模型,在测试集上验证模型性能。
from sklearn.model_selection import train_test_split

## 选择其类别为0和1的样本 (不包括类别为2的样本)
data_target_part = data[data['Species'].isin([0, 1])][['Species']]
data_features_part = data[data['Species'].isin([0, 1])][['Culmen Length (mm)', 'Culmen Depth (mm)', 'Flipper Length (mm)', 'Body Mass (g)']]

## 测试集大小为20%, 80%/20%分
x_train, x_test, y_train, y_test = train_test_split(data_features_part, data_target_part, test_size=0.2, random_state=2020)
## 从sklearn中导入决策树模型
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
## 定义 决策树模型 
clf = DecisionTreeClassifier(criterion='entropy')
## 在训练集上训练决策树模型
clf.fit(x_train, y_train)
## DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=None,
##            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')
## 可视化
## 本段代码实际效果为本地生成PDF可视化文档,在体验过程中可以不运行,可能无法正常展示结果;
## 代码生成的可视化结果会截图展示实际效果
import graphviz
dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("penguins")
## 'penguins.pdf'

## 在训练集和测试集上分布利用训练好的模型进行预测
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
from sklearn import metrics
## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_train, train_predict))
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_test, test_predict))
## 查看混淆矩阵 (预测值和真实值的各类情况统计矩阵)
confusion_matrix_result = metrics.confusion_matrix(test_predict, y_test)
print('The confusion matrix result:\n', confusion_matrix_result)
# 利用热力图对于结果进行可视化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()
## The accuracy of the Logistic Regression is: 0.9954545454545455
## The accuracy of the Logistic Regression is: 1.0
## The confusion matrix result:
## [[31  0]
## [ 0 25]]

  • Step6:利用 决策树模型 在三分类(多分类)上 进行训练和预测
## 测试集大小为20%, 80%/20%分
x_train, x_test, y_train, y_test = train_test_split(data[['Culmen Length (mm)', 'Culmen Depth (mm)', 'Flipper Length (mm)', 'Body Mass (g)']], data[['Species']], test_size=0.2, random_state=2020)
## 定义 决策树模型 
clf = DecisionTreeClassifier()
# 在训练集上训练决策树模型
clf.fit(x_train, y_train)
## DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
##            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')
## 在训练集和测试集上分布利用训练好的模型进行预测
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
## 由于决策树模型是概率预测模型(前文介绍的 p = p(y=1|x,\theta)),所有我们可以利用 predict_proba 函数预测其概率
train_predict_proba = clf.predict_proba(x_train)
test_predict_proba = clf.predict_proba(x_test)
print('The test predict Probability of each class:\n', test_predict_proba)
## 其中第一列代表预测为0类的概率,第二列代表预测为1类的概率,第三列代表预测为2类的概率。
## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_train, train_predict))
print('The accuracy of the Logistic Regression is:', metrics.accuracy_score(y_test, test_predict))
## The test predict Probability of each class:
## [[0. 0. 1.]
## [0. 1. 0.]
## [0. 1. 0.]
## [1. 0. 0.]
## …………
## …………
## [1. 0. 0.]
## [1. 0. 0.]]
## The accuracy of the Logistic Regression is: 0.9963636363636363
## The accuracy of the Logistic Regression is: 0.9565217391304348
## 查看混淆矩阵
confusion_matrix_result = metrics.confusion_matrix(test_predict, y_test)
print('The confusion matrix result:\n', confusion_matrix_result)
# 利用热力图对于结果进行可视化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()
## The confusion matrix result:
## [[30  1  0]
## [ 0 23  0]
## [ 2  0 13]]

sklearn.tree.DecisionTreeClassifier类的参数说明

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:选择结点划分质量的度量标准,默认使用‘gini’,即基尼系数,基尼系数是CART算法中采用的度量标准,该参数还可以设置为 “entropy”,表示信息增益,是C4.5算法中采用的度量标准。

splitter:结点划分时的策略,默认使用‘best’。‘best’ 表示依据选用的criterion标准选用最优划分属性来划分该结点,一般用于训练样本数据量不大的场合,因为选择最优划分属性需要计算每种候选属性下划分的结果;该参数还可以设置为“random”,表示最优的随机划分属性,一般用于训练数据量较大的场合,可以减少计算量。

max_depth:设置决策树的最大深度,默认为None。None表示不对决策树的最大深度作约束,直到每个叶子结点上的样本均属于同一类,或者少于min_samples_leaf参数指定的叶子结点上的样本个数。也可以指定一个整型数值,设置树的最大深度,在样本数据量较大时,可以通过设置该参数提前结束树的生长,改善过拟合问题,但一般不建议这么做,过拟合问题还是通过剪枝来改善比较有效。

min_samples_split:当对一个内部结点划分时,要求该结点上的最小样本数,默认为2。

min_samples_leaf:设置叶子结点上的最小样本数,默认为1。当尝试划分一个结点时,只有划分后其左右分支上的样本个数不小于该参数指定的值时,才考虑将该结点划分,换句话说,当叶子结点上的样本数小于该参数指定的值时,则该叶子节点及其兄弟节点将被剪枝。在样本数据量较大时,可以考虑增大该值,提前结束树的生长。

min_weight_fraction_leaf:在引入样本权重的情况下,设置每一个叶子节点上样本的权重和的最小值,一旦某个叶子节点上样本的权重和小于该参数指定的值,则该叶子结点会联同其兄弟结点被减去,即其父结点不进行划分。该参数默认为0,表示不考虑权重的问题,若样本中存在较多的缺失值,或样本类别分布偏差很大时,会引入样本权重,此时就要谨慎设置该参数。

max_features:划分结点、寻找最优划分属性时,设置允许搜索的最大属性个数,默认为None。假设训练集中包含的属性个数为n,None表示搜索全部n个的候选属性;‘auto’表示最多搜索sqrt(n)个属性;sqrt表示最多搜索sqrt(n)个属性;‘log2’表示最多搜索log2(n)个属性;用户也可以指定一个整数k,表示最多搜索k个属性。需要说明的是,尽管设置了参数max_features,但是在至少找到一个有效(即在该属性上划分后,criterion指定的度量标准有所提高)的划分属性之前,最优划分属性的搜索不会停止。

random_state :当将参数splitter设置为‘random’时,可以通过该参数设置随机种子号,默认为None,表示使用np.random产生的随机种子号。

max_leaf_nodes: 设置决策树的最大叶子节点个数,该参数与max_depth等参数参数一起,限制决策树的复杂度,默认为None,表示不加限制。

min_impurity_decrease :打算划分一个内部结点时,只有当划分后不纯度(可以用criterion参数指定的度量来描述)减少值不小于该参数指定的值,才会对该结点进行划分,默认值为0。可以通过设置该参数来提前结束树的生长。

min_impurity_split打算划分一个内部结点时,只有当该结点上的不纯度不小于该参数指定的值时,才会对该结点进行划分,默认值为1e-7。该参数值0.25版本之后将取消,由min_impurity_decrease代替

class_weight:设置样本数据中每个类的权重,这里权重是针对整个类的数据设定的,默认为None,即不施加权重。用户可以用字典型或者字典列表型数据指定每个类的权重,假设样本中存在4个类别,可以按照 [{0: 1, 1: 1}, {0: 1, 1: 5}, {0: 1, 1: 1}, {0: 1, 1: 1}] 这样的输入形式设置4个类的权重分别为1、5、1、1,而不是 [{1:1}, {2:5}, {3:1}, {4:1}]的形式。该参数还可以设置为‘balance’,此时系统会按照输入的样本数据自动的计算每个类的权重,计算公式为:n_samples / ( n_classes * np.bincount(y) ),其中n_samples表示输入样本总数,n_classes表示输入样本中类别总数,np.bincount(y) 表示计算属于每个类的样本个数,可以看到,属于某个类的样本个数越多时,该类的权重越小。若用户单独指定了每个样本的权重,且也设置了class_weight参数,则系统会将该样本单独指定的权重乘以class_weight指定的其类的权重作为该样本最终的权重。

presort: 设置对训练数据进行预排序,以提升结点最优划分属性的搜索,默认为False。在训练集较大时,预排序会降低决策树构建的速度,不推荐使用,但训练集较小或者限制树的深度时,使用预排序能提升树的构建速度。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树是一种用于分类和回归分析机器学习算法。它可以帮助我们根据已知特征属性预测未知目标属性。 对于决策树算法的理解,我们可以通过下载"wine.csv"数据集进行实践和学习。该数据集是一个关于红酒的数据集,包含了与红酒品质相关的特征属性。 下载"wine.csv"文件后,我们可以使用Python的pandas库来读取和处理数据、以及使用scikit-learn库来构建决策树模型。 首先,我们导入所需的库: ``` import pandas as pd from sklearn.tree import DecisionTreeClassifier ``` 然后,我们使用pandas的read_csv函数读取"wine.csv"文件,并将其存储为一个DataFrame对象: ``` data = pd.read_csv("wine.csv") ``` 接下来,我们需要将数据集分为特征变量和目标变量。在该数据集,特征变量包括葡萄酒的化学成分,而目标变量表示葡萄酒的品质等级。 ``` X = data.drop(columns=["quality"]) y = data["quality"] ``` 接下来,我们可以创建一个决策树分类器对象,并使用fit函数来将模型与数据拟合: ``` model = DecisionTreeClassifier() model.fit(X, y) ``` 在模型拟合后,我们可以使用该模型对新数据进行预测,预测其葡萄酒的品质等级。 ``` new_data = [[13.8, 1.29, 2.6, 19.4, 107, 2.95, 2.97, 0.37, 1.76, 4.5, 1.23, 2.92, 1190]] prediction = model.predict(new_data) print(prediction) ``` 以上代码将输出预测结果。 通过下载并使用"wine.csv"数据集,我们可以学习如何使用决策树算法来进行分类预测。通过对数据集分析和模型训练,我们可以预测葡萄酒的品质等级,从而更好地了解该算法的工作原理

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值