CategoryResourceRepost/极客时间专栏/数据分析实战45讲/第二模块:数据分析算法篇/17 丨决策树(上):要不要去打篮球?决策树来告诉你.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

244 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="17 丨决策树(上):要不要去打篮球?决策树来告诉你" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f6/42/f62875ac408e70b3595a23e6ba200442.mp3"></audio>
想象一下一个女孩的妈妈给她介绍男朋友的场景:
女儿:长的帅不帅?
妈妈:挺帅的。
女儿:有没有房子?
妈妈:在老家有一个。
女儿:收入高不高?
妈妈:还不错,年薪百万。
女儿:做什么工作的?
妈妈IT男互联网公司做数据挖掘的。
女儿:好,那我见见。
在现实生活中,我们会遇到各种选择,不论是选择男女朋友,还是挑选水果,都是基于以往的经验来做判断。如果把判断背后的逻辑整理成一个结构图,你会发现它实际上是一个树状图,这就是我们今天要讲的**决策树**。
## 决策树的工作原理
决策树基本上就是把我们以前的经验总结出来。我给你准备了一个打篮球的训练集。如果我们要出门打篮球,一般会根据“天气”、“温度”、“湿度”、“刮风”这几个条件来判断,最后得到结果:去打篮球?还是不去?
<img src="https://static001.geekbang.org/resource/image/dc/90/dca4224b342894f12f54a9cb41d8cd90.jpg" alt=""><br>
上面这个图就是一棵典型的决策树。我们在做决策树的时候,会经历两个阶段:**构造和剪枝**。
**构造**
什么是构造呢?构造就是生成一棵完整的决策树。简单来说,**构造的过程就是选择什么属性作为节点的过程**,那么在构造过程中,会存在三种节点:
<li>
根节点:就是树的最顶端,最开始的那个节点。在上图中,“天气”就是一个根节点;
</li>
<li>
内部节点:就是树中间的那些节点,比如说“温度”、“湿度”、“刮风”;
</li>
<li>
叶节点:就是树最底部的节点,也就是决策结果。
</li>
节点之间存在父子关系。比如根节点会有子节点,子节点会有子子节点,但是到了叶节点就停止了,叶节点不存在子节点。那么在构造过程中,你要解决三个重要的问题:
<li>
选择哪个属性作为根节点;
</li>
<li>
选择哪些属性作为子节点;
</li>
<li>
什么时候停止并得到目标状态,即叶节点。
</li>
**剪枝**
决策树构造出来之后是不是就万事大吉了呢也不尽然我们可能还需要对决策树进行剪枝。剪枝就是给决策树瘦身这一步想实现的目标就是不需要太多的判断同样可以得到不错的结果。之所以这么做是为了防止“过拟合”Overfitting现象的发生。
“过拟合”这个概念你一定要理解,它指的就是模型的训练结果“太好了”,以至于在实际应用的过程中,会存在“死板”的情况,导致分类错误。
欠拟合,和过拟合就好比是下面这张图中的第一个和第三个情况一样,训练的结果“太好“,反而在实际应用过程中会导致分类错误。
<img src="https://static001.geekbang.org/resource/image/d3/df/d30bfa3954ffdf5baf47ce53df9366df.jpg" alt=""><br>
造成过拟合的原因之一就是因为训练集中样本量较小。如果决策树选择的属性过多,构造出来的决策树一定能够“完美”地把训练集中的样本分类,但是这样就会把训练集中一些数据的特点当成所有数据的特点,但这个特点不一定是全部数据的特点,这就使得这个决策树在真实的数据分类中出现错误,也就是模型的“泛化能力”差。
泛化能力指的分类器是通过训练集抽象出来的分类能力,你也可以理解是举一反三的能力。如果我们太依赖于训练集的数据,那么得到的决策树容错率就会比较低,泛化能力差。因为训练集只是全部数据的抽样,并不能体现全部数据的特点。
既然要对决策树进行剪枝具体有哪些方法呢一般来说剪枝可以分为“预剪枝”Pre-Pruning和“后剪枝”Post-Pruning
预剪枝是在决策树构造时就进行剪枝。方法是在构造的过程中对节点进行评估,如果对某个节点进行划分,在验证集中不能带来准确性的提升,那么对这个节点进行划分就没有意义,这时就会把当前节点作为叶节点,不对其进行划分。
后剪枝就是在生成决策树之后再进行剪枝,通常会从决策树的叶节点开始,逐层向上对每个节点进行评估。如果剪掉这个节点子树,与保留该节点子树在分类准确性上差别不大,或者剪掉该节点子树,能在验证集中带来准确性的提升,那么就可以把该节点子树进行剪枝。方法是:用这个节点子树的叶子节点来替代该节点,类标记为这个节点子树中最频繁的那个类。
## 如何判断要不要去打篮球?
我给你准备了打篮球的数据集,训练数据如下:
<img src="https://static001.geekbang.org/resource/image/32/07/327eafa4a33e3e76ca86ac59195c0307.png" alt=""><br>
我们该如何构造一个判断是否去打篮球的决策树呢?再回顾一下决策树的构造原理,在决策过程中有三个重要的问题:将哪个属性作为根节点?选择哪些属性作为后继节点?什么时候停止并得到目标值?
显然将哪个属性(天气、温度、湿度、刮风)作为根节点是个关键问题,在这里我们先介绍两个指标:**纯度**和**信息熵**。
先来说一下纯度。你可以把决策树的构造过程理解成为寻找纯净划分的过程。数学上,我们可以用纯度来表示,纯度换一种方式来解释就是让目标变量的分歧最小。
我在这里举个例子假设有3个集合
<li>
集合16次都去打篮球
</li>
<li>
集合24次去打篮球2次不去打篮球
</li>
<li>
集合33次去打篮球3次不去打篮球。
</li>
按照纯度指标来说集合1&gt;集合2&gt;集合3。因为集合1的分歧最小集合3的分歧最大。
然后我们再来介绍信息熵entropy的概念**它表示了信息的不确定度**。
在信息论中,随机离散事件出现的概率存在着不确定性。为了衡量这种信息的不确定性,信息学之父香农引入了信息熵的概念,并给出了计算信息熵的数学公式:
<img src="https://static001.geekbang.org/resource/image/74/d5/741f0ed01c53fd53f0e75204542abed5.png" alt=""><br>
p(i|t)代表了节点t为分类i的概率其中log2为取以2为底的对数。这里我们不是来介绍公式的而是说存在一种度量它能帮我们反映出来这个信息的不确定度。当不确定性越大时它所包含的信息量也就越大信息熵也就越高。
我举个简单的例子假设有2个集合
<li>
集合15次去打篮球1次不去打篮球
</li>
<li>
集合23次去打篮球3次不去打篮球。
</li>
在集合1中有6次决策其中打篮球是5次不打篮球是1次。那么假设类别1为“打篮球”即次数为5类别2为“不打篮球”即次数为1。那么节点划分为类别1的概率是5/6为类别2的概率是1/6带入上述信息熵公式可以计算得出
<img src="https://static001.geekbang.org/resource/image/ab/a4/aba6bb24c3444923bfa2320119ce54a4.png" alt=""><br>
同样集合2中也是一共6次决策其中类别1中“打篮球”的次数是3类别2“不打篮球”的次数也是3那么信息熵为多少呢我们可以计算得出
<img src="https://static001.geekbang.org/resource/image/e0/c2/e05fe27109330b49453b62505e37e4c2.png" alt=""><br>
从上面的计算结果中可以看出,信息熵越大,纯度越低。当集合中的所有样本均匀混合时,信息熵最大,纯度最低。
我们在构造决策树的时候,会基于纯度来构建。而经典的 “不纯度”的指标有三种分别是信息增益ID3算法、信息增益率C4.5算法以及基尼指数Cart算法
我们先看下ID3算法。ID3算法计算的是**信息增益**,信息增益指的就是划分可以带来纯度的提高,信息熵的下降。它的计算公式,是父亲节点的信息熵减去所有子节点的信息熵。在计算的过程中,我们会计算每个子节点的归一化信息熵,即按照每个子节点在父节点中出现的概率,来计算这些子节点的信息熵。所以信息增益的公式可以表示为:
<img src="https://static001.geekbang.org/resource/image/bf/34/bfea7626733fff6180341c9dda3d4334.png" alt=""><br>
公式中D是父亲节点Di是子节点Gain(D,a)中的a作为D节点的属性选择。
假设天气=晴的时候会有5次去打篮球5次不打篮球。其中D1刮风=是有2次打篮球1次不打篮球。D2 刮风=否有3次打篮球4次不打篮球。那么a 代表节点的属性,即天气=晴。
你可以在下面的图例中直观地了解这几个概念。
<img src="https://static001.geekbang.org/resource/image/40/67/40810468abc4140f45f3a09a2d427667.jpg" alt=""><br>
比如针对图上这个例子D作为节点的信息增益为
<img src="https://static001.geekbang.org/resource/image/f2/82/f23f88a18b1227398c2ab3ef445d5382.png" alt=""><br>
也就是D节点的信息熵-2个子节点的归一化信息熵。2个子节点归一化信息熵=3/10的D1信息熵+7/10的D2信息熵。
我们基于ID3的算法规则完整地计算下我们的训练集训练集中一共有7条数据3个打篮球4个不打篮球所以根节点的信息熵是
<img src="https://static001.geekbang.org/resource/image/9f/9b/9f01e1d1e8082e55850676da50a84f9b.png" alt="">
如果你将天气作为属性的划分会有三个叶子节点D1、D2和D3分别对应的是晴天、阴天和小雨。我们用+代表去打篮球,-代表不去打篮球。那么第一条记录晴天不去打篮球可以记为1-于是我们可以用下面的方式来记录D1D2D3
D1(天气=晴天)={1-,2-,6+}
D2(天气=阴天)={3+,7-}
D3(天气=小雨)={4+,5-}
我们先分别计算三个叶子节点的信息熵:
<img src="https://static001.geekbang.org/resource/image/85/7f/8537ab10a1a3747d22059bfbbd2aa17f.png" alt=""><br>
因为D1有3个记录D2有2个记录D3有2个记录所以D中的记录一共是3+2+2=7即总数为7。所以D1在D父节点中的概率是3/7D2在父节点的概率是2/7D3在父节点的概率是2/7。那么作为子节点的归一化信息熵= 3/7*0.918+2/7*1.0+2/7*1.0=0.965。
因为我们用ID3中的信息增益来构造决策树所以要计算每个节点的信息增益。
天气作为属性节点的信息增益为Gain(D ,天气)=0.985-0.965=0.020。。
同理我们可以计算出其他属性作为根节点的信息增益,它们分别为
Gain(D ,温度)=0.128<br>
Gain(D ,湿度)=0.020<br>
Gain(D ,刮风)=0.020
我们能看出来温度作为属性的信息增益最大。因为ID3就是要将信息增益最大的节点作为父节点这样可以得到纯度高的决策树所以我们将温度作为根节点。其决策树状图分裂为下图所示
<img src="https://static001.geekbang.org/resource/image/70/28/7067d83113c892a586e703d8b2e19828.jpg" alt=""><br>
然后我们要将上图中第一个叶节点也就是D1={1-,2-,3+,4+}进一步进行分裂,往下划分,计算其不同属性(天气、湿度、刮风)作为节点的信息增益,可以得到:
Gain(D ,湿度)=1<br>
Gain(D ,天气)=1<br>
Gain(D ,刮风)=0.3115
我们能看到湿度或者天气为D1的节点都可以得到最大的信息增益这里我们选取湿度作为节点的属性划分。同理我们可以按照上面的计算步骤得到完整的决策树结果如下
<img src="https://static001.geekbang.org/resource/image/11/48/1187ab0048daeec40cd261ea26cd3448.jpg" alt=""><br>
于是我们通过ID3算法得到了一棵决策树。ID3的算法规则相对简单可解释性强。同样也存在缺陷比如我们会发现ID3算法倾向于选择取值比较多的属性。这样如果我们把“编号”作为一个属性一般情况下不会这么做这里只是举个例子那么“编号”将会被选为最优属性 。但实际上“编号”是无关属性的,它对“打篮球”的分类并没有太大作用。
所以ID3有一个缺陷就是有些属性可能对分类任务没有太大作用但是他们仍然可能会被选为最优属性。这种缺陷不是每次都会发生只是存在一定的概率。在大部分情况下ID3都能生成不错的决策树分类。针对可能发生的缺陷后人提出了新的算法进行改进。
## 在ID3算法上进行改进的C4.5算法
那么C4.5都在哪些方面改进了ID3呢
**1. 采用信息增益率**
因为ID3在计算的时候倾向于选择取值多的属性。为了避免这个问题C4.5采用信息增益率的方式来选择属性。信息增益率=信息增益/属性熵,具体的计算公式这里省略。
当属性有很多值的时候相当于被划分成了许多份虽然信息增益变大了但是对于C4.5来说,属性熵也会变大,所以整体的信息增益率并不大。
**2. 采用悲观剪枝**
ID3构造决策树的时候容易产生过拟合的情况。在C4.5中会在决策树构造之后采用悲观剪枝PEP这样可以提升决策树的泛化能力。
悲观剪枝是后剪枝技术中的一种,通过递归估算每个内部节点的分类错误率,比较剪枝前后这个节点的分类错误率来决定是否对其进行剪枝。这种剪枝方法不再需要一个单独的测试数据集。
**3. 离散化处理连续属性**
C4.5可以处理连续属性的情况,对连续的属性进行离散化的处理。比如打篮球存在的“湿度”属性,不按照“高、中”划分,而是按照湿度值进行计算,那么湿度取什么值都有可能。该怎么选择这个阈值呢,**C4.5选择具有最高信息增益的划分所对应的阈值**。
**4. 处理缺失值**
针对数据集不完整的情况C4.5也可以进行处理。
假如我们得到的是如下的数据,你会发现这个数据中存在两点问题。第一个问题是,数据集中存在数值缺失的情况,如何进行属性选择?第二个问题是,假设已经做了属性划分,但是样本在这个属性上有缺失值,该如何对样本进行划分?
<img src="https://static001.geekbang.org/resource/image/50/95/50b43c1820c03561f3ca3e627b454995.png" alt=""><br>
我们不考虑缺失的数值可以得到温度D={2-,3+,4+,5-,6+,7-}。温度=高D1={2-,3+,4+} ;温度=中D2={6+,7-};温度=低D3={5-} 。这里+号代表打篮球,-号代表不打篮球。比如ID=2时决策是不打篮球我们可以记录为2-。
针对将属性选择为温度的信息增为:
Gain(D, 温度)=Ent(D)-0.792=1.0-0.792=0.208<br>
属性熵=1.459, 信息增益率Gain_ratio(D, 温度)=0.208/1.459=0.1426。
D的样本个数为6而D的样本个数为7所以所占权重比例为6/7所以Gain(D温度)所占权重比例为6/7所以<br>
Gain_ratio(D, 温度)=6/7*0.1426=0.122。
这样即使在温度属性的数值有缺失的情况下,我们依然可以计算信息增益,并对属性进行选择。
Cart算法在这里不做介绍我会在下一讲给你讲解这个算法。现在我们总结下ID3和C4.5算法。首先ID3算法的优点是方法简单缺点是对噪声敏感。训练数据如果有少量错误可能会产生决策树分类错误。C4.5在ID3的基础上用信息增益率代替了信息增益解决了噪声敏感的问题并且可以对构造树进行剪枝、处理连续数值以及数值缺失等情况但是由于C4.5需要对数据集进行多次扫描,算法效率相对较低。
## 总结
前面我们讲了两种决策树分类算法ID3和C4.5了解了它们的数学原理。你可能会问公式这么多在实际使用中该怎么办呢实际上我们可以使用一些数据挖掘工具使用它们比如Python的sklearn或者是Weka一个免费的数据挖掘工作平台它们已经集成了这两种算法。只是我们在了解了这两种算法之后才能更加清楚这两种算法的优缺点。
我们总结下,这次都讲到了哪些知识点呢?
首先我们采用决策树分类需要了解它的原理包括它的构造原理、剪枝原理。另外在信息度量上我们需要了解信息度量中的纯度和信息熵的概念。在决策树的构造中一个决策树包括根节点、子节点、叶子节点。在属性选择的标准上度量方法包括了信息增益和信息增益率。在算法上我讲解了两种算法ID3和C4.5其中ID3是基础的决策树算法C4.5在它的基础上进行了改进,也是目前决策树中应用广泛的算法。然后在了解这些概念和原理后,强烈推荐你使用工具,具体工具的使用我会在后面进行介绍。
<img src="https://static001.geekbang.org/resource/image/d0/7a/d02e69930c8cf00c93578536933ad07a.png" alt="">
最后我们留一道思考题吧。请你用下面的例子来模拟下决策树的流程假设好苹果的数据如下请用ID3算法来给出好苹果的决策树。
<img src="https://static001.geekbang.org/resource/image/0a/09/0a759fd725add916417c2c294600b609.png" alt="">
如果你觉得这篇文章有所价值,欢迎点击“请朋友读”,把它分享给你的朋友或者同事。