[学习笔记] [机器学习] 6. [上]决策树算法(熵Entropy、信息增益(率)、基尼值(指数)、CART剪枝、特征工程特征提取、Jieba分词、回归决策树)

  1. 视频链接
  2. 数据集下载地址:无需下载

学习目标:

  • 掌握决策树实现过程
  • 知道信息熵的公式以及作用
  • 知道信息增益、信息增益率和基尼指数的作用
  • 知道 id3、c4.5、CART 算法的区别
  • 了解 CART 剪枝的作用
  • 知道特征提取的作用
  • 应用 DecisionTreeClassifier 实现决策树分类

1. 决策树算法简介

1.1 决策树算法简介

学习目标

  • 知道什么是决策树

决策树思想的来源非常朴素,程序设计中的条件分支结构就是 if-else 结构,最早的决策树就是利用这类结构分割数据的一种分类学习方法。

决策树是一种树形结构,其中每个内部节点表示一个属性上的判断,每个分支代表一个判断结果的输出,最后每个叶节点(没有子节点的节点就叫叶子节点)代表一种分类结果,本质是一颗由多个判断节点组成的树

在这里插入图片描述

想一想这个女生为什么把年龄放在最上面判断

上面案例是女生通过定性的主观意识,把年龄放到最上面,那么如果需要对这一过程进行量化,该如何处理呢?

此时就需要用到信息论中的知识:

  • 信息熵
  • 信息增益

小结

  • 决策树定义:
    • 是一种树形结构
    • 本质上是一颗由多个判断节点组成的树

2. 决策树分类原理

学习目标

  • 知道如何求解信息熵
  • 知道信息增益的求解过程
  • 知道信息增益率的求解过程
  • 知道基尼系数的求解过程
  • 知道信息增益信息增益率基尼系数三者之间的区别、联系

2.1 熵

2.1.1 概念

熵(shāng)是热力学中表征物质状态的参量之一,用符号 S S S 表示,其物理意义是体系混乱程度的度量。它也被社会科学用以借喻人类社会某些状态的程度。熵的概念是由德国物理学家克劳修斯于1865年提出的。

简单来说,在物理学上,熵(Entropy)是用来表示“混乱”程度的量度

在这里插入图片描述

从上面的图我们可以知道:

  • 系统越有序,熵值越低
  • 系统越混乱或者分散,熵值越高

1948 年香农(Shannon)提出了信息熵(Information Entropy)的概念。

克劳德·艾尔伍德·香农(Claude Elwood Shannon,1916年4月30日—2001年2月24日)是一位美国数学家、电子工程师和密码学家,被誉为信息论的创始人。他是密西根大学学士,麻省理工学院博士。1948年,香农发表了划时代的论文——《通讯的数学理论》,奠定了现代信息论的基础。

信息理论信息熵 (Information Entropy)是用来度量样本集合纯度的一种指标,它可以从信息的完整性有序性两个方面进行描述。

1. 从信息的完整性上进行的描述

当系统的有序状态一致时,数据越集中的地方熵值越小,数据越分散的地方熵值越大

2. 从信息的有序性上进行的描述

当数据量一致时,系统越有序,熵值越低系统越混乱或者分散,熵值越高


假定当前样本集合 D D D 中第 k k k 类样本所占总样本的比例为 p k ( k = 1 , 2 , . . . , ∣ y ∣ ) p_k(k = 1, 2, ..., |y|) pk(k=1,2,...,y) p k = C k D p_k = \frac{C^k}{D} pk=DCk D D D 为样本的所有数量, C k C^k Ck 为第 k k k 类样本的数量。

样本集合 D D D 的信息熵定义为

E n t ( D ) = − ∑ k = 1 n log ⁡ C k D = − ∑ k = 1 n p k log ⁡ 2 p k = − p 1 log ⁡ 2 p 1 − p 2 log ⁡ 2 p 2 − . . . − p n log ⁡ 2 p n \begin{aligned} \mathrm{Ent}(D) & = -\sum_{k=1}^n \log \frac{C^k}{D} \\ & = -\sum_{k=1}^n p_k \log_2^{p_k} \\ & = -p_1 \log_2^{p_1} - p_2\log_2^{p2} - ... - p_n\log_2^{p_n} \end{aligned} Ent(D)=k=1nlogDCk=k=1npklog2pk=p1log2p1p2log2p2...pnlog2pn

其中:

  • log ⁡ \log log 是以 2 为底, lg ⁡ \lg lg 是以 10 为底。
  • D D D:表示样本集合。
  • k k k:表示样本集合中的第 k k k 类样本。
  • n n n:表示样本集合中类别的总数。
  • ∣ y ∣ |y| y 表示样本集合中类别的总数。 ∣ y ∣ |y| y n n n 是等价的。
  • p k p_k pk:表示第 k k k 类样本在样本集合中所占的比例,即 p k = C k D p_k = \frac{C^k}{D} pk=DCk,其中 C k C^k Ck 为第 k k k 类样本的数量。
  • E n t ( D ) \mathrm{Ent}(D) Ent(D):表示样本集合 D D D 的信息熵。

因此,根据公式,样本集合 D D D 的信息熵 E n t ( D ) \mathrm{Ent}(D) Ent(D) 可以简化为:

E n t ( D ) = − ∑ k = 1 n p k log ⁡ 2 p k \mathrm{Ent}(D) = -\sum_{k=1}^n p_k \log_2^{p_k} Ent(D)=k=1npklog2pk

其中, ∑ k = 1 n \sum_{k=1}^n k=1n 表示对样本集合中所有类别进行求和, log ⁡ 2 p k \log_2^{p_k} log2pk 表示以 2 为底, p k p_k pk 的对数。

根据公式可知:

  • E n t ( D ) \mathrm{Ent}(D) Ent(D) 的值越小,则 D D D 的纯度越高(熵越高代表越不稳定,纯度越低)。

2.1.2 案例

案例介绍

假设我们没有看世界杯的比赛,但是想知道哪支球队会是冠军,我们只能猜测某支球队是或不是冠军,然后观众用对或不对来回答,我们想要猜测次数尽可能少,你会用什么方法?

答案:二分法。

假如有 16 支球队,编号为 1-16。先问是否在 1 ~ 8 之间,如果是就继续问是否在 1 ~ 4 之间,以此类推,直到最后判断出冠军球队是哪支

如果球队数量是 16,我们需要问 4 次来得到最后的答案。那么世界冠军这条消息的信息熵就是 4。

那么信息熵等于 4,是如何进行计算的呢?

E n t ( D ) = − ( p 1 × log ⁡ 2 p 1 + p 2 × log ⁡ 2 p 2 + . . . + p 16 × log ⁡ 2 p 16 ) \mathrm{Ent}(D) = -(p_1 \times \log_2{p_1} + p_2 \times \log_2{p_2} + ... + p_{16} \times \log_2{p_{16}}) Ent(D)=(p1×log2p1+p2×log2p2+...+p16×log2p16)

其中 p 1 , . . . , p 16 p_1, ..., p_{16} p1,...,p16 分别是这 16 支球队夺冠的概率。

当每支球队夺冠概率相等(都是 1 16 \frac{1}{16} 161)时:

E n t ( D ) = − 16 × ( 1 16 × log ⁡ 2 1 16 ) = − 16 × ( 1 16 × log ⁡ 2 4 − 2 ) = − 16 × ( 1 16 × − 2 × log ⁡ 2 4 ) = 16 × ( 1 8 × 2 ) = 4 \begin{aligned} \mathrm{Ent}(D) &= - 16 \times ( \frac{1}{16} \times \log_2{\frac{1}{16}})\\ &= - 16 \times ( \frac{1}{16} \times \log_2{4^{-2}})\\ &= - 16 \times ( \frac{1}{16} \times -2\times \log_2{4})\\ &= 16 \times ( \frac{1}{8}\times 2)\\ &= 4 \end{aligned} Ent(D)=16×(161×log2161)=16×(161×log242)=16×(161×2×log24)=16×(81×2)=4

每个事件概率相同时,熵最大,这件事越不确定。

2.1.3 随堂练习

篮球比赛里,有4个球队 {A, B, C, D},获胜概率分别为 {1/2, 1/4, 1/8, 1/8} E n t ( D ) \mathrm{Ent}(D) Ent(D)

答案

E n t ( D ) = − p 1 log ⁡ 2 p 1 − p 2 log ⁡ 2 p 2 − . . . − p n log ⁡ 2 p n = − ( 1 2 log ⁡ 2 1 2 + 1 4 log ⁡ 2 1 4 + 1 8 log ⁡ 2 1 8 + 1 8 log ⁡ 2 1 8 ) = − ( 1 2 log ⁡ 2 2 − 1 + 1 4 log ⁡ 2 2 − 2 + 1 8 log ⁡ 2 2 − 3 + 1 8 log ⁡ 2 2 − 3 ) = − ( − 1 2 − 1 2 − 3 8 − 3 8 ) = 1 2 + 1 2 + 3 8 + 3 8 = 1 + 3 4 = 7 4 \begin{aligned} \mathrm{Ent}(D) & = -p_1 \log_2^{p_1} - p_2\log_2^{p2} - ... - p_n\log_2^{p_n}\\ & = -(\frac{1}{2}\log_2^{\frac{1}{2}} + \frac{1}{4}\log_2^{\frac{1}{4}} + \frac{1}{8}\log_2^{\frac{1}{8}} + \frac{1}{8}\log_2^{\frac{1}{8}}) \\ & = -(\frac{1}{2}\log_2^{2^{-1}} + \frac{1}{4}\log_2^{2^{-2}} + \frac{1}{8}\log_2^{2^{-3}} + \frac{1}{8}\log_2^{2^{-3}}) \\ & = -(-\frac{1}{2} -\frac{1}{2} -\frac{3}{8} -\frac{3}{8}) \\ & = \frac{1}{2} + \frac{1}{2} + \frac{3}{8} + \frac{3}{8} \\ & = 1 + \frac{3}{4} \\ & = \frac{7}{4} \end{aligned} Ent(D)=p1log2p1p2log2p2...pnlog2pn=(21log221+41log241+81log281+81log281)=(21log221+41log222+81log223+81log223)=(21218383)=21+21+83+83=1+43=47

从上面两个例子中我们可以看到,如果每支球队获胜的概率是一样的,那么我们就很难猜到到底是哪支球队夺冠了(此时熵很高),如果不同球队获胜的概率是不一样的,那么我们倾向于猜胜率高的球队,因此熵就减小了。

2.2 信息增益(Information Gain)【决策树的划分依据·一】

2.2.1 概念

信息增益(Information Gain)是一个统计量,用来描述一个属性区分数据样本的能力。它定义为一个特征能够为分类系统带来多少信息,带来的信息越多,说明该特征越重要,相应的信息增益也就越大。在决策树算法中,信息增益是特征选择的一个重要指标。它表示在一个条件下,信息复杂度(不确定性)减少的程度。如果选择一个特征后,信息增益最大(信息不确定性减少的程度最大),那么我们就选取这个特征。

信息熵 (Information Entropy)是用来度量样本集合纯度的一种指标


Q:意思就是说,如果有一个特征它足够简单,那么它的信息增益就越强吗?
A:不完全是这样的。信息增益衡量的是一个特征对于数据分类的贡献,而不是特征本身的复杂度。信息增益越大,说明这个特征对于数据分类的贡献越大,也就是说,使用这个特征进行分类可以更好地区分数据

  • 举个例子,假设我们要根据一些特征来预测一个人是否喜欢运动。其中一个特征是“身高”,另一个特征是“喜欢的颜色”。显然,“身高”这个特征比“喜欢的颜色”更能够帮助我们预测一个人是否喜欢运动。因此,“身高”这个特征的信息增益会比“喜欢的颜色”这个特征的信息增益大。
  • 总之,信息增益衡量的是一个特征对于数据分类的贡献,而不是特征本身的复杂度。

信息增益(Information Gain)是以某特征划分数据集前后的熵的差值(这里我们可以认为信息增益就是一个 Δ \Delta Δ。熵可以表示样本集合的不确定性,熵越大,样本的不确定性就越大。因此可以使用划分前后集合熵的差值来衡量使用当前特征对于样本集合 D D D 划分效果的好坏。

信息增益 ‾ Δ = E n t r o p y 前 − E n t r o p y 后 \rm \underset{\Delta}{\underline{信息增益}} = Entropy_前 - Entropy_后 Δ信息增益=EntropyEntropy

注意:信息增益表示得知特征 X X X 的信息而使得类 Y Y Y 的信息熵减少的程度

2.2.2 定义与公式

假定离散属性 a a a V V V 个可能的取值: a 1 , a 2 , . . . , a V a^1, a^2, ..., a^V a1,a2,...,aV。这里我们假设离散属性 a a a 为性别,有 2 个可能的取值(男或女)。即, v = 2 v = 2 v=2 a 1 a^1 a1 表示男, a 2 a^2 a2 表示女。

若使用 a a a 来对样本集 D D D 进行划分,则会产生 v = 2 v=2 v=2 个分支结点。其中第 v v v 个分支结点包含了 D D D 中所有在属性 a a a 上且取值为 a v a^v av 的样本,记为 D v D^v Dv

例如,在前面提到的性别属性的例子中,如果我们使用性别属性 a a a 来划分样本集 D D D,那么所有男性样本都会被分配到一个子集中 D 1 D^1 D1,所有女性样本都会被分配到另一个子集中 D 2 D^2 D2。这两个子集中的样本在性别属性上的取值都相同。

注意这里面的 v v v 并不是一个确定的值,把 v v v 换为 n n n 就好理解了!

我们可以根据前面给出的信息熵公式计算出 D ′ D' D 的信息熵。再考虑到不同的分支结点所包含的样本数不同,给分支结点赋予权重 ∣ D v ∣ ∣ D ∣ \frac{|D^v|}{|D|} DDv。(注意:绝对值符号只是用来表示集合中元素的数量,而不是数值的绝对值),即样本数越多的分支结点的影响越大

因此我们可以计算出用属性 a a a 对样本集 D D D 进行划分所获得的“信息增益(Information Gain)”。

其中:特征 a = { a 1 , a 2 } a = \{ a^1, a^2 \} a={ a1,a2} 对训练数据集 D D D 的信息增益 G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a) 定义为:集合 D D D 的信息熵 E n t ( D ) \mathrm{Ent}(D) Ent(D) 与给定特征 a a a 条件下 D D D 的信息条件熵 E n t ( D ∣ a ) \mathrm{Ent}(D|a) Ent(Da) 之差,即公式为:

G a i n ( D , a ) = E n t ( D ) − E n t ( D ∣ a ) = E n t ( D ) − ∑ v = 1 v ∣ D v ∣ ∣ D ∣ E n t ( D v ) \begin{aligned} \mathrm{Gain}(D, a) &= \mathrm{Ent}(D) - \mathrm{Ent}(D|a) \\ & = \mathrm{Ent}(D) - \sum_{v=1}^v \frac{|D^v|}{|D|} \mathrm{Ent}(D^v) \end{aligned} Gain(D,a)=Ent(D)Ent(Da)=Ent(D)v=1vDDvEnt(Dv)

其中:

  • D D D:表示样本集合。
  • a a a:表示离散属性。
  • V V V:表示离散属性 a a a 的可能取值个数。
  • a v a^v av:表示离散属性 a a a 的第 v v v 个可能取值。
  • D v D^v Dv:表示样本集合 D D D 中所有在属性 a a a 上取值为 a v a^v av 的样本。
  • G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a):表示特征 a a a 对训练数据集 D D D 的信息增益。
  • E n t ( D ) \mathrm{Ent}(D) Ent(D):表示样本集合 D D D 的信息熵。
  • E n t ( D ∣ a ) \mathrm{Ent}(D|a) Ent(Da):表示给定特征 a a a 条件下 D D D 的信息条件熵。
  • ∑ v = 1 v \sum_{v=1}^v v=1v 表示对离散属性 a a a 的所有可能取值进行求和
  • ∣ D v ∣ ∣ D ∣ \frac{|D^v|}{|D|} DDv 表示分支结点的权重
  • E n t ( D v ) \mathrm{Ent}(D^v) Ent(Dv) 表示分支结点 D v D^v Dv 的信息熵。
  • 注意:绝对值符号只是用来表示集合中元素的数量,而不是数值的绝对值

这个公式的意义是:对于一个离散属性 a = { a 1 , a 2 , . . . , a v } a = \{ a^1, a^2, ..., a^v \} a={ a1,a2,...,av},它有 v v v 个可能的取值。如果使用这个属性 a a a 来对样本集合 D D D 进行划分,则会产生 v v v 个分支结点 D 1 , D 2 , . . . , D v D^1, D^2, ..., D^v D1,D2,...,Dv。每个分支结点包含了样本集合 D D D 中所有在属性 a a a 上取值为 a v a^v av 的样本,记为 D v D^v Dv。我们可以根据前面给出的信息熵公式计算出每个分支结点的信息熵。由于不同的分支结点所包含的样本数不同,所以我们需要给每个分支结点赋予一个权重 ∣ D v ∣ ∣ D ∣ \frac{|D^v|}{|D|} DDv,表示样本数越多的分支结点的影响越大。最后,将所有分支结点的信息熵加权求和,就得到了给定特征 a a a 条件下 D D D 的信息条件熵 E n t ( D ∣ a ) \mathrm{Ent}(D|a) Ent(Da)

注意这里面的 v v v 并不是一个确定的值,把 v v v 换为 n n n 就好理解了!

因此,离散特征属性 a = { a 1 , a 2 , . . . , a v } a = \{ a^1, a^2, ..., a^v \} a={ a1,a2,...,av} 对训练数据集 D D D 的信息增益 G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a) 可以理解为:在给定特征 a a a 的条件下,样本集合 D D D 的信息不确定性减少的程度。如果选择一个特征后,信息增益最大(信息不确定性减少的最多),那么我们就选取这个特征。


公式的详细解释如下

  • 信息熵的计算

E n t ( D ) = − ∑ k = 1 n C k D log ⁡ 2 C k D \mathrm{Ent}(D) = -\sum^n_{k=1}\frac{C^k}{D}\log_2^{\frac{C^k}{D}} Ent(D)=k=1nDCklog2DCk

  • 条件熵的计算

E n t ( D ∣ a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ ∑ k = 1 K C k v D v log ⁡ C k v D v \begin{aligned} \mathrm{Ent}(D|a) & = \sum_{v=1}^V \frac{|D^v|}{|D|} \mathrm{Ent}(D^v)\\ & = -\sum_{v=1}^V \frac{|D^v|}{|D|} \sum_{k=1}^K \frac{C^{kv}}{D_v} \log\frac{C^{kv}}{D_v} \end{aligned} Ent(Da)=v=1VDDvEnt(Dv)=v=1VDDvk=1KDvCkvlogDvCkv

其中:

  • D v D^v Dv 表示 a a a 属性中第 v v v 个分支节点包含的样本数
  • C k v C^{kv} Ckv 表示 a a a 属性中第 v v v 个分支节点包含的样本数中,第 k k k 个类别下包含的样本数
  • 注意:绝对值符号只是用来表示集合中元素的数量,而不是数值的绝对值

条件熵是 E n t ( D ∣ a ) \mathrm{Ent}(D | a) Ent(Da),用 ∣ | ,而信息增益是 G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a),用 , , ,

一般而言,信息增益越大,则意味着使用属性 a a a 来进行划分所获得的“纯度提升”越大。因此,我们可用信息增益来进行决策树的划分属性选择,著名的 ID3 决策树学习算法就是以信息增益为准则来选择划分属性。

ID3 决策树学习算法是一种贪心算法,用来构造决策树。它的全称是 Iterative Dichotomiser 3,即迭代二分器 3。ID3 算法起源于概念学习系统(CLS),以信息熵的下降速度为选取测试属性的标准,即在每一个节点选取还尚未被用来划分的具有最高信息增益的属性作为划分标准,然后继续这个过程,直到生成的决策树能完美的分类训练样例。

ID3 算法主要用于决策树分类问题。它通过计算每个特征的信息增益来选择最优划分属性,然后递归地构建决策树。ID3 算法能够自动地从数据中学习规律,并用生成的决策树对新数据进行分类。

2.2.3 案例

如下图,第一列为论坛号码,第二列为性别,第三列为活跃度,最后一列用户是否流失(1 表示已流失(正样本),0 表示未流失(负样本))。我们要解决一个问题:通过性别和活跃度两个特征,判断哪个特征对用户流失影响更大

在这里插入图片描述

通过计算信息增益可以解决这个问题,统计如右表信息。

其中,Positive 为正样本(已流失),Negative 为负样本(未流失),下面的数值为不同划分下对应的人数。

因此我们可以得到三个熵

a. 计算类别信息熵(算计整体熵)

E n t ( D ) = − ∑ k = 1 n C k D log ⁡ 2 C k D = − 5 15 log ⁡ 2 5 15 − 10 15 log ⁡ 2 10 15 = 0.9182 \begin{aligned} \mathrm{Ent}(D) & = -\sum^n_{k=1}\frac{C^k}{D}\log_2^{\frac{C^k}{D}} \\ & = -\frac{5}{15}\log_2^{\frac{5}{15}} - \frac{10}{15}\log_2^{\frac{10}{15}}\\ & = 0.9182 \end{aligned} Ent(D)=k=1nDCklog2DCk=155log21551510log21510=0.9182

b1. 计算性别属性的信息熵(a=“性别”)

E n t ( D ∣ 性别 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) = ∣ D 1 ∣ ∣ D ∣ E n t ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ E n t ( D 2 ) \begin{aligned} \mathrm{Ent}(D|性别) & = \sum_{v=1}^V \frac{|D^v|}{|D|} \mathrm{Ent}(D^v)\\ & = \frac{|D^1|}{|D|}\mathrm{Ent}(D^1) + \frac{|D^2|}{|D|}\mathrm{Ent}(D^2) \end{aligned} Ent(D性别)=v=1VDDvEnt(Dv)=DD1Ent(D1)+DD2Ent(D2)

E n t ( D 1 ) = − 3 8 log ⁡ 2 3 8 − 5 8 log ⁡ 2 5 8 = 0.9543 \mathrm{Ent}(D^1) = -\frac{3}{8}\log_2^{\frac{3}{8}} - \frac{5}{8}\log_2^{\frac{5}{8}} = 0.9543 Ent(D1)=83log28385log285=0.9543

E n t ( D 2 ) = − 2 7 log ⁡ 2 2 7 − 5 7 log ⁡ 2 5 7 = 0.8631 \mathrm{Ent}(D^2) = -\frac{2}{7}\log_2^{\frac{2}{7}} - \frac{5}{7}\log_2^{\frac{5}{7}} = 0.8631 Ent(D2)=72log27275log275=0.8631

c1. 计算性别的信息增益(a=“性别”)

G a i n ( D ∣ 性别 ) = E n t ( D ) − E n t ( D ∣ a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) = E n t ( D ) − 8 15 E n t ( D 1 ) − 7 15 E n t ( D 2 ) = 0.0064 \begin{aligned} \mathrm{Gain}(D|性别) &= \mathrm{Ent}(D) - \mathrm{Ent}(D|a) \\ & = \mathrm{Ent}(D) - \sum_{v=1}^V \frac{|D^v|}{|D|} \mathrm{Ent}(D^v)\\ &= \mathrm{Ent}(D) - \frac{8}{15}\mathrm{Ent}(D^1) - \frac{7}{15}\mathrm{Ent}(D^2)\\ &=0.0064 \end{aligned} Gain(D性别)=Ent(D)Ent(Da)=Ent(D)v=1VDDvEnt(Dv)=Ent(D)158Ent(D1)157Ent(D2)=0.0064


b2. 计算活跃度属性的信息熵(a=“活跃度”)

E n t ( D , 活跃度 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) = ∣ D 1 ∣ ∣ D ∣ E n t ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ E n t ( D 2 ) \begin{aligned} \mathrm{Ent}(D, 活跃度) & = \sum_{v=1}^V \frac{|D^v|}{|D|} \mathrm{Ent}(D^v)\\ & = \frac{|D^1|}{|D|}\mathrm{Ent}(D^1) + \frac{|D^2|}{|D|}\mathrm{Ent}(D^2) \end{aligned} Ent(D,活跃度)=v=1VDDvEnt(Dv)=DD1Ent(D1)+DD2Ent(D2)

E n t ( D 1 ) = − 0 6 log ⁡ 2 0 6 − 6 6 log ⁡ 2 6 6 = − 0 − 0 = 0 \begin{aligned} \mathrm{Ent}(D^1) & = -\frac{0}{6}\log_2^{\frac{0}{6}} - \frac{6}{6}\log_2^{\frac{6}{6}} \\ & = -0 - 0 \\ & = 0 \end{aligned} Ent(D1)=60log26066log266=00=0

E n t ( D 2 ) = − 1 5 log ⁡ 2 1 5 − 4 5 log ⁡ 2 4 5 = 0.7219 \begin{aligned} \mathrm{Ent}(D^2) & = -\frac{1}{5}\log_2^{\frac{1}{5}} - \frac{4}{5}\log_2^{\frac{4}{5}} \\ & = 0.7219 \end{aligned} Ent(D2)=51log25154log254=0.7219

E n t ( D 3 ) = − 4 4 log ⁡ 2 4 4 − 0 4 log ⁡ 2 0 4 = − 0 − 0 = 0 \begin{aligned} \mathrm{Ent}(D^3) & = -\frac{4}{4}\log_2^{\frac{4}{4}} - \frac{0}{4}\log_2^{\frac{0}{4}} \\ & = -0 - 0 \\ & = 0 \end{aligned} Ent(D3)=44log24440log240=00=0

注意:当 log ⁡ \log log 函数中的参数为 0 0 0 1 1 1 时, log ⁡ ( 0 ) \log(0) log(0) log ⁡ ( 1 ) \log(1) log(1) 的值分别为未定义和 0 0 0。因此,在计算信息熵时,我们通常会忽略这些项。

c2. 计算活跃度的信息增益(a=“活跃度”)

G a i n ( D , 活跃度 ) = E n t ( D ) − E n t ( D ∣ a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) = E n t ( D ) − 6 15 E n t ( D 1 ) − 5 15 E n t ( D 2 ) − 4 15 E n t ( D 3 ) = 0.6776 \begin{aligned} \mathrm{Gain}(D, 活跃度) &= \mathrm{Ent}(D) - \mathrm{Ent}(D|a) \\ & = \mathrm{Ent}(D) - \sum_{v=1}^V \frac{|D^v|}{|D|} \mathrm{Ent}(D^v)\\ &= \mathrm{Ent}(D) - \frac{6}{15}\mathrm{Ent}(D^1) - \frac{5}{15}\mathrm{Ent}(D^2) - \frac{4}{15}\mathrm{Ent}(D^3)\\ &= 0.6776 \end{aligned} Gain(D,活跃度)=Ent(D)Ent(Da)=Ent(D)v=1VDDvEnt(Dv)=Ent(D)156Ent(D1)155Ent(D2)154Ent(D3)=0.6776


我们对比一下两种不同特征的信息增益:

特征名称 信息增益
性别 G a i n ( D , 性别 ) = 0.0064 \mathrm{Gain}(D, 性别)=0.0064 Gain(D,性别)=0.0064
活跃度 G a i n ( D , 活跃度 ) = 0.6776 \mathrm{Gain}(D, 活跃度)=0.6776 Gain(D,活跃度)=0.6776

很明显,活跃度的信息增益比性别的信息增益大。也就是说,活跃度对用户流失的影响比性别大。在做特征选择或者数据分析的时候,我们应该重点考察活跃度这个指标。

2.3 信息增益率(Information Gain Rate)【决策树的划分依据·二】

2.3.1 概念

在上面的介绍中,我们有意忽略了“编号”这一列。若把“编号”也作为一个候选划分属性,则根据信息增益公式可计算出它的信息增益为 0.9182 0.9182 0.9182,这远大于其他候选划分属性。

计算每个属性的信息熵过程中,我们发现,该属性的值为 0,也就是其信息增益为 0.9182。但是很明显如果这么分类,那么最后出现的结果不具有泛化效果,即无法对新样本进行有效预测。

实际上,信息增益(Information Gain)准则对可取值数目较多的属性有所偏好。为了减少这种偏好可能带来的不利影响,著名的 C4.5 决策树算法被提出。C4.5 算法不直接使用信息增益,而是使用“增益率” (Information Gain Ratio)来选择最优的划分属性

信息增益率(Information Gain Ratio):信息增益率是用前面的信息增益 G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a) 和属性 a a a 对应的“固有值”(Intrinsic Value, I V \mathrm{IV} IV)的比值来共同定义的。

G a i n   r a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) \mathrm{Gain \ ratio}(D,a) = \frac{\mathrm{Gain}(D, a)}{\mathrm{IV}(a)} Gain ratio(D,a)=IV(a)Gain(D,a)

其中:

  • D D D 表示数据集
  • a a a 表示属性
  • I V ( a ) \mathrm{IV}(a) IV(a) 表示属性 a a a 的固有值
  • D v D^v Dv 表示数据集 D D D 中属性 a a a 取值为 a v a^v av 的样本子集
    • 因此, ∣ D v ∣ ∣ D ∣ \frac{|D^v|}{|D|} DDv 表示数据集 D D D 中属性 a a a 取值为 a v a^v av 的样本所占的比例。

固有值 I V ( a ) \mathrm{IV}(a) IV(a) 的求解

I V ( a ) = − ∑ v = 1 V D v D log ⁡ ∣ D v ∣ ∣ D ∣ \mathrm{IV}(a) = -\sum^V_{v=1}\frac{D^v}{D}\log{\frac{|D^v|}{|D|}} IV(a)=v=1VDDvlogDDv

其中:

  • I V \mathrm{IV} IV 是固有值(Intrinsic Value)。
    • 固有值 I V ( a ) \mathrm{IV}(a) IV(a) 是用来衡量属性 a a a 的固有信息量的一个指标。
  • V V V 表示属性 a a a 的可能取值的数目
  • D v D^v Dv 表示数据集 D D D 中属性 a a a 取值为 a v a^v av 的样本子集
    • 因此, ∣ D v ∣ ∣ D ∣ \frac{|D^v|}{|D|} DDv 表示数据集 D D D 中属性 a a a 取值为 a v a^v av 的样本所占的比例。

属性 a a a 的可能取值的数目越多(即 V V V 越大),则 I V ( a ) \mathrm{IV}(a) IV(a) 的值通常会越大。

2.3.2 案例

2.3.2.1 案例一

a. 计算类别信息熵

b. 计算性别属性的信息熵(性别、活跃度)

c. 计算活跃度的信息增益(性别、活跃度)

d. 计算属性分裂信息度量(也就是固有值 I V \mathrm{IV} IV

用分裂信息度量来考虑某种属性进行分裂时分支的数量信息和尺寸信息,我们把这些信息称为属性的内在信息 (Intrinsic Information,II) 。信息增益率 IGR 用信息增益 IG / 内在信息 II,会导致属性的重要性随着内在信息 II 的增大而减小(也就是说,如果这个属性本身不确定性就很大,那我就越不倾向于选取它),这样算是对单纯用信息增益有所补偿。

I V ( 性别 ) = − ∑ v = 1 V D v D log ⁡ ∣ D v ∣ ∣ D ∣ = − 7 15 log ⁡ 2 7 15 − 8 15 log ⁡ 2 8 15 = 0.9968 \begin{aligned} \mathrm{IV}(性别) & = -\sum^V_{v=1}\frac{D^v}{D}\log{\frac{|D^v|}{|D|}}\\ & = -\frac{7}{15}\log_2^{\frac{7}{15}} -\frac{8}{15}\log_2^{\frac{8}{15}}\\ & = 0.9968 \end{aligned} IV(性别)=v=1VDDvlogDDv=157log2157158log2158=0.9968

I V ( 活跃度 ) = − ∑ v = 1 V D v D log ⁡ ∣ D v ∣ ∣ D ∣ = − 6 15 log ⁡ 2 6 15 − 5 15 log ⁡ 2 5 15 = 1.5656 \begin{aligned} \mathrm{IV}(活跃度) & = -\sum^V_{v=1}\frac{D^v}{D}\log{\frac{|D^v|}{|D|}}\\ & = -\frac{6}{15}\log_2^{\frac{6}{15}} -\frac{5}{15}\log_2^{\frac{5}{15}}\\ & = 1.5656 \end{aligned} IV(活跃度)=v=1VDDvlogDDv=156log2156155log2155=1.5656

e. 计算信息增益率

G a i n   r a t i o ( D , 性别 ) = G a i n ( D , a ) I V ( a ) = 0.0064 0.9968 = 0.0064 \begin{aligned} \mathrm{Gain \ ratio}(D,性别) & = \frac{\mathrm{Gain}(D, a)}{\mathrm{IV}(a)} \\ & = \frac{0.0064}{0.9968}\\ & = 0.0064 \end{aligned} Gain ratio(D,性别)=IV(a)Gain(D,a)=0.99680.0064=0.0064

G a i n   r a t i o ( D , 活跃度 ) = G a i n ( D , a ) I V ( a ) = 0.6776 1.5656 = 0.4328 \begin{aligned} \mathrm{Gain \ ratio}(D,活跃度) & = \frac{\mathrm{Gain}(D, a)}{\mathrm{IV}(a)} \\ & = \frac{0.6776}{1.5656}\\ & = 0.4328 \end{aligned} Gain ratio(D,活跃度)=IV(a)Gain(D,a)=1.56560.6776=0.4328

活跃度的信息增益率更高一些( 0.4328 > 0.0064 0.4328>0.0064 0.4328>0.0064),所以在构建决策树的时候,优先选择。

通过引入固有值 IV 从而求信息增益率的这种方式,在选取节点的过程中,我们可以降低取值较多的属性的选取偏好

2.3.2.2 案例二

如下图,第一列为天气,第二列为温度,第三列为湿度,第四列为风速,最后一列该活动是否进行。

我们要解决:根据下面表格数据,判断在对应天气下,活动是否会进行?

在这里插入图片描述

在这里插入图片描述

该数据集有四个属性,属性集合 A = { 天气,温度,湿度,风速 } A=\{天气,温度,湿度,风速\} A={ 天气,温度,湿度,风速},类别标签有两个,类别集合 L = { 进行,取消 } L=\{进行,取消\} L={ 进行,取消}


a. 计算类别信息熵

类别信息熵 E n t ( D ) \mathrm{Ent}(D) Ent(D) 表示的是所有样本中各种类别出现的不确定性之和。根据熵的概念,熵越大,不确定性就越大,把事情搞清楚所需要的信息量就越多。

E n t ( D ) = − ∑ k = 1 n C k D log ⁡ 2 C k D = − 9 14 log ⁡ 2 9 14 − 5 14 log ⁡ 2 5 14 = 0.940 \begin{aligned} \mathrm{Ent}(D) & = -\sum^n_{k=1}\frac{C^k}{D}\log_2^{\frac{C^k}{D}} \\ & = -\frac{9}{14}\log_2^{\frac{9}{14}} - \frac{5}{14}\log_2^{\frac{5}{14}}\\ & = 0.940 \end{aligned} Ent(D)=k=1nDCklog2DCk=149log2149145log2145=0.940


b. 计算每个属性的信息熵

每个属性的信息熵相当于一种条件熵 E n t ( D ∣ a ) \mathrm{Ent}(D|a) Ent(Da)。它表示的是在某种属性 a a a 的条件下,各种类别出现的不确定性之和。属性的信息熵越大,表示这个属性中拥有的样本类别越不“纯”。

  • a = “天气”(5 个“晴”,4 个“阴”,5 个“雨”)

E n t ( D ∣ 天气 ) = ∑ v = 1 V D v D E n t ( D v ) = 5 14 × [ − 2 5 log ⁡ 2 2 5 − 3 5 log ⁡ 2 3 5 ] + 4 14 × [ − 4 4 log ⁡ 2 4 4 ] + 5 14 × [ − 2 5 log ⁡ 2 2 5 − 3 5 log ⁡ 2 3 5 ] = 0.694 \begin{aligned} \mathrm{Ent}(D | 天气) &= \sum_{v=1}^V \frac{D^v}{D} \mathrm{Ent}(D^v)\\ &=\frac{5}{14} \times [-\frac{2}{5}\log_2^{\frac{2}{5}} -\frac{3}{5}\log_2^{\frac{3}{5}}] + \frac{4}{14} \times [-\frac{4}{4}\log_2^{\frac{4}{4}}] + \frac{5}{14} \times [-\frac{2}{5}\log_2^{\frac{2}{5}}-\frac{3}{5}\log_2^{\frac{3}{5}}]\\ &=0.694 \end{aligned} Ent(D天气)=v=1VDDvEnt(Dv)=145×[52log25253log253]+144×[44log244]+145×[52log25253log253]=0.694

  • a = “温度”(4 个"寒冷",6 个“适中",4 个“炎热”)

E n t ( D ∣ 温度 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) = 4 14 × [ − 2 4 log ⁡ 2 2 4 − 2 4 log ⁡ 2 2 4 ] + 6 14 × [ − 4 6 log ⁡ 2 4 6 − 2 6 log ⁡ 2 2 6 ] + 4 14 × [ − 3 4 log ⁡ 2 3 4 − 1 4 log ⁡ 2 1 4 ] = 0.911 \begin{aligned} \mathrm{Ent}(D|温度) & = \sum_{v=1}^V \frac{|D^v|}{|D|} \mathrm{Ent}(D^v)\\ & = \frac{4}{14} \times [-\frac{2}{4}\log_2^{\frac{2}{4}} -\frac{2}{4}\log_2^{\frac{2}{4}}] + \frac{6}{14} \times [-\frac{4}{6}\log_2^{\frac{4}{6}} -\frac{2}{6}\log_2^{\frac{2}{6}}] + \frac{4}{14} \times [-\frac{3}{4}\log_2^{\frac{3}{4}} -\frac{1}{4}\log_2^{\frac{1}{4}}]\\ & = 0.911 \end{aligned} Ent(D温度)=v=1VDDvEnt(Dv)=144×[42log24242log242]+146×[64log26462log262]+144×[43log24341log241]=0.911

  • a = “湿度”(7 个“正常”,7个“高”)

E n t ( D ∣ 湿度 ) = 0.789 \mathrm{Ent}(D|湿度) = 0.789 Ent(D湿度)=0.789

  • a = “风速”(8 个“弱”,6 个“强”)

E n t ( D ∣ 风速 ) = 0.892 \mathrm{Ent}(D|风速) = 0.892 Ent(D风速)=0.892


c. 计算信息增益

信息增益 = 熵 - 条件熵,在这里就是 类别信息熵 - 属性信息熵,它表示的是信息不确定性减少的程度。如果一个属性的信息增益越大,就表示用这个属性进行样本划分可以更好的减少划分后样本的不确定性,当然,选择该属性就可以更快更好地完成我们的分类目标。

信息增益越大越好

信息增益是 ID3 算法的特征选择指标

G a i n ( D , 天气 ) = 0.940 − 0.694 = 0.246 \mathrm{Gain}(D, 天气) = 0.940 - 0.694 = 0.246 Gain(D,天气)=0.9400.694=0.246

G a i n ( D , 温度 ) = 0.940 − 0.911 = 0.029 \mathrm{Gain}(D, 温度) = 0.940 - 0.911 = 0.029 Gain(D,温度)=0.9400.911=0.029

G a i n ( D , 湿度 ) = 0.940 − 0.789 = 0.15 \mathrm{Gain}(D, 湿度) = 0.940 - 0.789 = 0.15 Gain(D,湿度)=0.9400.789=0.15

G a i n ( D , 风速 ) = 0.940 − 0.892 = 0.048 \mathrm{Gain}(D, 风速) = 0.940 - 0.892 = 0.048 Gain(D,风速)=0.9400.892=0.048

假设我们在上面表格 1 的数据前面添加一列,取名为“编号”,取值为 1~14。若把“编号”也作为一个候选划分属性,则根据前面步骤:计算每个属性的信息熵过程中,我们发现,该属性的值为 0,也就是其信息增益为 0.940。

但是很明显,如果这么分类,最后出现的结果并不具有泛化效果。此时根据信息增益就无法选择出有效分类特征。所以,C4.5 选择使用信息增益率对 ID3 进行改进。


d. 计算属性分裂信息度量(固有值IV)

I V ( 天气 ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ log ⁡ ∣ D v ∣ ∣ D ∣ = − 5 14 log ⁡ 2 5 14 − 5 14 log ⁡ 2 5 14 − 4 14 log ⁡ 2 4 14 = 1.577 \begin{aligned} \mathrm{IV}(天气) & = -\sum^V_{v=1}\frac{|D^v|}{|D|}\log{\frac{|D^v|}{|D|}}\\ & = -\frac{5}{14}\log_2^{\frac{5}{14}} -\frac{5}{14}\log_2^{\frac{5}{14}} -\frac{4}{14}\log_2^{\frac{4}{14}}\\ & = 1.577 \end{aligned} IV(天气)=v=1VDDvlogDDv=145log2145145log2145144log2144=1.577

I V ( 温度 ) = − 4 14 log ⁡ 2 4 14 − 6 14 log ⁡ 2 6 14 − 4 14 log ⁡ 2 4 14 = 1.556 \begin{aligned} \mathrm{IV}(温度) & = -\frac{4}{14}\log_2^{\frac{4}{14}} -\frac{6}{14}\log_2^{\frac{6}{14}} -\frac{4}{14}\log_2^{\frac{4}{14}}\\ & = 1.556 \end{aligned} IV(温度)=144log2144146log2146144log2144=1.556

I V ( 湿度 ) = − 7 14 log ⁡ 2 7 14 − 7 14 log ⁡ 2 7 14 = 1.0 \begin{aligned} \mathrm{IV}(湿度) & = -\frac{7}{14}\log_2^{\frac{7}{14}} -\frac{7}{14}\log_2^{\frac{7}{14}}\\ & = 1.0 \end{aligned} IV(湿度)=147log2147147log2147=1.0

I V ( 风速 ) = − 9 14 log ⁡ 2 9 14 − 5 14 log ⁡ 2 5 14 = 0.985 \begin{aligned} \mathrm{IV}(风速) & = -\frac{9}{14}\log_2^{\frac{9}{14}} -\frac{5}{14}\log_2^{\frac{5}{14}}\\ & = 0.985 \end{aligned} IV(风速)=149log2149145log2145=0.985


e. 计算信息增益率

G a i n   r a t i o ( D , 天气 ) = G a i n ( D , 天气 ) I V ( 天气 ) = 0.246 1.577 = 0.156 \begin{aligned} \mathrm{Gain \ ratio}(D,天气) & = \frac{\mathrm{Gain}(D, 天气)}{\mathrm{IV}(天气)} \\ & = \frac{0.246}{1.577}\\ & = 0.156 \end{aligned} Gain ratio(D,天气)=IV(天气)Gain(D,天气)=1.5770.246=0.156

G a i n   r a t i o ( D , 温度 ) = G a i n ( D , 温度 ) I V ( 温度 ) = 0.026 1.556 = 0.0167 \begin{aligned} \mathrm{Gain \ ratio}(D,温度) & = \frac{\mathrm{Gain}(D, 温度)}{\mathrm{IV}(温度)} \\ & = \frac{0.026}{1.556}\\ & = 0.0167 \end{aligned} Gain ratio(D,温度)=IV(温度)Gain(D,温度)=1.5560.026=0.0167

G a i n   r a t i o ( D , 湿度 ) = G a i n ( D , 湿度 ) I V ( 湿度 ) = 0.151 1.0 = 0.151 \begin{aligned} \mathrm{Gain \ ratio}(D,湿度) & = \frac{\mathrm{Gain}(D, 湿度)}{\mathrm{IV}(湿度)} \\ & = \frac{0.151}{1.0}\\ & = 0.151 \end{aligned} Gain ratio(D,湿度)=IV(湿度)Gain(D,湿度)=1.00.151=0.151

G a i n   r a t i o ( D , 风速 ) = G a i n ( D , 风速 ) I V ( 风速 ) = 0.048 0.985 = 0.0487 \begin{aligned} \mathrm{Gain \ ratio}(D,风速) & = \frac{\mathrm{Gain}(D, 风速)}{\mathrm{IV}(风速)} \\ & = \frac{0.048}{0.985}\\ & = 0.0487 \end{aligned} Gain ratio(D,风速)=IV(风速)Gain(D,风速)=0.9850.048=0.0487

属性名称 信息增益率
天气 0.156
温度 0.0167
湿度 0.151
风速 0.0487

从上表可知,天气的信息增益率最高,选择 天气 为分裂属性。发现分裂了之后,天气是“阴”的条件下,类别是“纯”的,所以把它定义为叶子节点,选择不“纯”的结点继续分裂。

在这里插入图片描述

在子结点当中重复过程 1~5,直到所有的叶子结点足够“纯”。

现在我们来总结一下 C4.5 的算法流程

while (当前节点"不纯"):
    1. 计算当前节点的类别熵(以类别取值计算):Ent(D)
    2. 计算当前阶段的属性熵(按照属性求得类别取值计算):Ent(D|a)
    3. 计算信息增益:Gain(D,a)
    4. 计算各个属性的分裂信息度量:固有值IV(a)
    5. 计算各个属性的信息增益率:Gain Ratio(D, a)
    
    if 设置的所有值都为叶子结点:
        return  # 结束

Q:这里的“值”具体指的是什么?
A:在 C4.5 算法中,这里的“值”指的是属性值。在决策树算法中,每个节点都代表一个属性,而每个分支代表该属性的一个可能取值。因此,当我们说“所有设置的值都为叶子结点”时,我们指的是当前节点的所有子节点都是叶子节点,即它们都属于同一类别。

2.3.3 为什么使用 C4.5 会更好?

  1. 采用信息增益率 Gain Ratio 来选择属性:克服了用信息增益来选择属性时偏向选择值多的属性的问题。
  2. 采用了一种后剪枝方法:避免树的高度无节制的增长,从而避免模型过度拟合数据
  3. 增加了对于缺失值的处理:在某些情况下,可供使用的数据可能缺少某些属性的值。
    • 假如 < x x x, c ( x ) c(x) c(x)> 是样本集 S S S 中的一个训练实例,但是其属性 A A A 的值 A ( x ) A(x) A(x) 未知。
    • 处理缺少属性值一般有两种策略:
      • 一种策略是赋给它结点 n n n 所对应的训练实例中该属性的最常见值;
      • 另外一种更复杂的策略是为 A A A 的每个可能值赋予一个概率。
    • 例如:给定一个布尔属性 A A A,如果结点 n n n 包含 6 个已知 A = 1 A=1 A=1 和 4 个 A = 0 A=0 A=0 的实例,那么 A ( x ) = 1 A(x)=1 A(x)=1 的概率是 0.6,而 A ( x ) = 0 A(x)=0 A(x)=0 的概率是0.4。于是,实例 x x x 60 % 60\% 60% 被分配到 A = 1 A=1 A=1 的分支, 40 % 40\% 40% 被分配到另一个分支。
    • C4.5 就是使用这种方法处理缺少的属性值。

2.4 基尼值(Gini Value)和基尼指数(Gini Index)【决策树的划分依据·三】

2.4.1 概念

CART 决策树(Classification and Regression Tree,分类和回归树)使用基尼指数(Gini Index)来选择划分属性。

CART 是Classification and Regression Tree(分类和回归树)的简称,这是一种著名的决策树学习算法,分类和回归任务都可用。

基尼值和基尼指数的定义

一、基尼值(Gini Value)

基尼值(Gini Value)的定义:是一种用于衡量数据集纯度的指标,它表示从数据集 D D D 中随机抽取两个样本,其类别标记不一致的概率 G i n i ( D ) ∈ [ 0 , 1 ] \mathrm{Gini}(D) \in [0, 1] Gini(D)[0,1]

  • G i n i ( D ) \mathrm{Gini}(D) Gini(D) 值越小,数据集 D D D 的纯度越高(越好)
  • G i n i ( D ) \mathrm{Gini}(D) Gini(D) 值越大,数据集 D D D 的纯度越低(越坏)

换言之,数据集 D D D 的纯度可用基尼值来量化

G i n i ( D ) = ∑ k = 1 ∣ y ∣ ∑ k ′ ≠ k p k p k ′ = 1 − ∑ k = 1 ∣ y ∣ p k 2 \begin{aligned} \mathrm{Gini}(D) & = \sum_{k=1}^{|y|}\sum_{k' \neq k}p_kp_{k'} \\ & = 1 - \sum_{k=1}^{|y|}p_k^2 \end{aligned} Gini(D)=k=1yk=kpkpk=1k=1ypk2

其中

  • ∣ y ∣ |y| y 表示类别数
  • p k = C k D p_k = \frac{C^k}{D} pk=DCk 表示第 k k k 类样本在数据集 D D D 中所占的比例
  • C k C^k Ck 为第 k k k 类样本的数量、
  • k ′ k' k 是一个指标,表示类别。它与 k k k 不同,即 k ′ ≠ k k' \neq k k=k。在计算基尼值时,我们需要计算所有类别之间的组合,因此需要使用两个指标 k k k k ′ k' k 来表示不同的类别

二、基尼指数(Gini Index)

基尼指数(Gini Index)的定义:是一种用于选择最优划分属性的指标。一般选择使划分后基尼系数最小的属性作为最优化分属性。

G i n i   i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) \mathrm{Gini \ index}(D, a) = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v) Gini index(D,a)=v=1VDDvGini(Dv)

其中:

  • D D D 表示数据集。
  • a a a 表示属性。
  • V V V 表示属性 a a a 的取值个数。
  • v v v 是一个指标,表示属性 a a a 的第 v v v 个取值。
  • D v D^v Dv 表示数据集 D D D 中属性 a a a 取值为 a v a^v av 的样本子集。
  • G i n i ( D v ) \mathrm{Gini}(D^v) Gini(Dv) 表示数据集 D v D^v Dv 的基尼值。
  • ∣ D v ∣ ∣ D ∣ \frac{|D^v|}{|D|} DDv 表示数据集 D v D^v Dv 在数据集 D D D 中所占的比例。

因此,基尼指数 G i n i   i n d e x ( D , a ) \mathrm{Gini \ index}(D, a) Gini index(D,a) 表示在属性 a a a 上对数据集 D D D 进行划分后,各个子集的基尼值的加权平均值。


Q1:什么是基尼指数?
A1:基尼系数(Gini coefficient)是 20 世纪初意大利学者科拉多·基尼根据洛伦兹曲线所定义的判断年收入分配公平程度的指标,是比例数值,在 0 和 1 之间。基尼指数(Gini index)是基尼系数乘 100 倍作百分比表示。

  • 基尼系数 ∈ \in [0, 1]
  • 基尼指数 ∈ \in [0%, 100%]

Q2:基尼系数只能用于判断年收入分配公平程度吗?
A2:基尼系数通常用来衡量一个国家或地区居民收入差距的常用指标之一。它包括收入基尼系数(Income Gini)和财富基尼系数(Wealth Gini)。两者的算法大致相同,区别在于收入基尼系数的数据是来自于某地区的家庭收入统计,财富基尼系数的数据是来自于某地区的家庭总资产统计。

除了收入不平等,基尼系数也可以用来衡量其他方面的不平等情况,比如教育水平、健康状况和政治参与等。

Q3:意思是,基尼系数(基尼指数)是用来衡量不平等情况的吗?
A3:是的,基尼系数(基尼指数)通常用来衡量一个国家或地区居民收入差距的常用指标之一。它也可以用来衡量其他方面的不平等情况,比如教育水平、健康状况和政治参与等。

Q4:基尼系数(基尼指数)越大代表着什么?
A4:基尼系数(基尼指数)越大,代表着收入分配或其他方面的不平等程度越高。基尼系数最大为 “1”,最小等于 “0”。前者表示居民之间的收入分配绝对不平均,即 100% 的收入被一个单位的人全部占有了;而后者则表示居民之间的收入分配绝对平均,即人与人之间收入完全平等,没有任何差异。因此,基尼系数的实际数值只能介于 0~1 之间,基尼系数越小收入分配越平均,基尼系数越大收入分配越不平均。

Q5:基尼系数(基尼指数)是否可以应用到机器学习中?
A5:是的,基尼系数(基尼指数)可以应用到机器学习中。在决策树算法中,基尼系数(基尼指数)常用作衡量数据集的不纯度(impurity)的指标。在构建决策树时,算法会选择基尼系数最小的特征进行分裂,以便得到更纯净的子数据集。

Q6:什么是基尼值?
A6:基尼值(Gini value)是指在决策树算法中,用来衡量数据集的不纯度(impurity)的指标。它是基于基尼系数(Gini coefficient)的概念计算而来。基尼值越小,表示数据集的不纯度越低,即数据集中的样本属于同一类别的可能性越大。


在 CART 决策树中,基尼值(Gini Value)、基尼指数(Gini Index)和基尼系数(Gini Coefficient)实际上也是同一个概念的不同叫法。它们都是用来衡量数据集纯度的指标,表示从数据集中随机抽取两个样本,其类别标记不一致的概率。基尼值越小,数据集的纯度越高;基尼值越大,数据集的纯度越低。在构建 CART 决策树时,可以使用基尼值来选择最佳的划分属性。

2.4.2 案例

请根据下方表格,按照基尼指数的划分依据,做出决策树。

序号 是否有房 婚姻状况 年收入 是否拖欠贷款
1 yes single 125k no
2 no married 100k no
3 no single 70k no
4 yes married 120k no
5 no divorced 95k yes
6 no married 60k no
7 yes divorced 220k no
8 no single 85k yes
9 no married 75k no
10 no single 90k yes

1. 对数据集非序列标号属性(是否有房、婚姻状况、年收入)分别计算它们的 Gini 指数,取 Gini 指数最小的属性作为决策树的根节点属性

第一次大循环

2. 根节点的 Gini 值为:

G i n i ( 是否拖欠贷款 ) = 1 − ∑ k = 1 ∣ y ∣ p k 2 = 1 − [ ( 3 10 ) 2 + ( 7 10 ) 2 ] = 0.42 \begin{aligned} \mathrm{Gini}(是否拖欠贷款) & = 1 - \sum_{k=1}^{|y|}p_k^2\\ & = 1 - [(\frac{3}{10})^2 + (\frac{7}{10})^2]\\ & = 0.42 \end{aligned} Gini(是否拖欠贷款)=1k=1ypk2=1[(103)2+(107)2]=0.42

在决策树算法中,我们通常会选择一个类别属性作为决策属性,然后根据这个属性的取值来划分数据集。这里我们选择“是否拖欠贷款”这个属性作为决策属性,则可以计算出数据集 D D D 的 Gini 值为 0.42。

3. 当根据是否有房来进行划分时,Gini 指数计算过程为:

G i n i ( 左子节点 ) = 1 − ∑ k = 1 ∣ y ∣ p k 2 = 1 − [ ( 0 3 ) 2 + ( 3 3 ) 2 ] = 0 \begin{aligned} \mathrm{Gini}(左子节点) & = 1 - \sum_{k=1}^{|y|}p_k^2\\ & = 1 - [(\frac{0}{3})^2 + (\frac{3}{3})^2]\\ & = 0 \end{aligned} Gini(左子节点)=1k=1ypk2=1[(30)2+(33)2]=0

G i n i ( 右子节点 ) = 1 − ∑ k = 1 ∣ y ∣ p k 2 = 1 − [ ( 3 7 ) 2 + ( 4 7 ) 2 ] = 0.4898 \begin{aligned} \mathrm{Gini}(右子节点) & = 1 - \sum_{k=1}^{|y|}p_k^2\\ & = 1 - [(\frac{3}{7})^2 + (\frac{4}{7})^2]\\ & = 0.4898 \end{aligned} Gini(右子节点)=1k=1ypk2=1[(73)2+(74)2]=0.4898

G i n i   i n d e x ( D , 是否有房 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) = 7 10 × 0.4898 + 3 10 × 0 = 0.343 \begin{aligned} \mathrm{Gini \ index}(D, 是否有房) & = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v)\\ & = \frac{7}{10} \times 0.4898 + \frac{3}{10} \times 0\\ & = 0.343 \end{aligned} Gini index(D,是否有房)=v=1VDDvGini(Dv)=107×0.4898+103×0=0.343

其中:

  • 左子节点:有房(yes)
  • 右子节点:没房(no)

在这里插入图片描述

4. 若按婚姻状况属性来划分,属性婚姻状况有三个可能的取值:

  • {married} | {single, divorced}
  • {single} | {married, divorced}
  • {divorced} | {single, married}

4.1 当分组为 {married} | {single, divorced} 时:

G i n i   i n d e x ( D , 婚姻状况 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) = 4 10 × 0 + 6 10 × [ 1 − ( 3 6 ) 2 − ( 3 6 ) 2 ] = 0.3 \begin{aligned} \mathrm{Gini \ index}(D, 婚姻状况) & = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v)\\ & = \frac{4}{10} \times 0 + \frac{6}{10} \times [1 - (\frac{3}{6})^2 - (\frac{3}{6})^2] \\ & = 0.3 \end{aligned} Gini index(D,婚姻状况)=v=1VDDvGini(Dv)=104×0+106×[1(63)2(63)2]=0.3

4.2 当分组为 {single} | {married, divorced} 时:

G i n i   i n d e x ( D , 婚姻状况 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) = 4 10 × [ 1 − ( 2 4 ) 2 − ( 2 4 ) 2 ] + 6 10 × [ 1 − ( 1 6 ) 2 − ( 5 6 ) 2 ] = 0.367 \begin{aligned} \mathrm{Gini \ index}(D, 婚姻状况) & = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v)\\ & = \frac{4}{10} \times [1 - (\frac{2}{4})^2 - (\frac{2}{4})^2] + \frac{6}{10} \times [1 - (\frac{1}{6})^2 - (\frac{5}{6})^2] \\ & = 0.367 \end{aligned} Gini index(D,婚姻状况)=v=1VDDvGini(Dv)=104×[1(42)2(42)2]+106×[1(61)2(65)2]=0.367

4.3 当分组为 {divorced} | {single, married} 时:

G i n i   i n d e x ( D , 婚姻状况 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) = 2 10 × [ 1 − ( 2 4 ) 2 − ( 2 4 ) 2 ] + 8 10 × [ 1 − ( 2 8 ) 2 − ( 6 8 ) 2 ] = 0.4 \begin{aligned} \mathrm{Gini \ index}(D, 婚姻状况) & = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v)\\ & = \frac{2}{10} \times [1 - (\frac{2}{4})^2 - (\frac{2}{4})^2] + \frac{8}{10} \times [1 - (\frac{2}{8})^2 - (\frac{6}{8})^2] \\ & = 0.4 \end{aligned} Gini index(D,婚姻状况)=v=1VDDvGini(Dv)=102×[1(42)2(42)2]+108×[1(82)2(86)2]=0.4

对比计算结果,根据婚姻状况属性来划分根节点时取 Gini 指数最小的分组作为划分结果,即:{married} | {single, divorced}

5. 同理可得年收入的 Gini 指数:

对于年收入属性为数值型属性,首先需要对数据按升序排序,然后从小到大依次用相邻值的中间值作为分隔将样本划分为两组。例如当面对年收入为 60k 和 70k 这两个值时,我们算得其中间值为 65k。以中间值 65k 作为分割点求出 Gini 指数。

以中间值为 65k 为例,小于 65 的归为一类,大于 65 的归为一类,这样就可以计算 Gini 指数了

在这里插入图片描述

根据计算知道,三个属属性划分根节点的指数最小的有两个:年收入属性和婚姻状况,它们的指数都为 0.3。此时,选取首先出现的属性【married】作为第一次划分。

第二次大循环

6. 接下来,采用同样的方法,分别计算剩下属性,其中根节点的 Gini 系数为(此时是否拖欠贷款的各有 3 个 records)

G i n i ( 是否拖欠贷款 ) = 1 − ∑ k = 1 ∣ y ∣ p k 2 = 1 − [ ( 3 6 ) 2 + ( 3 6 ) 2 ] = 0.5 \begin{aligned} \mathrm{Gini}(是否拖欠贷款) & = 1 - \sum_{k=1}^{|y|}p_k^2\\ & = 1 - [(\frac{3}{6})^2 + (\frac{3}{6})^2]\\ & = 0.5 \end{aligned} Gini(是否拖欠贷款)=1k=1ypk2=1[(63)2+(63)2]=0.5

7. 对于是否有房属性,可得:

G i n i   i n d e x ( D , 是否有房 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) = 2 6 × 0 + 4 6 × [ 1 − ( 3 4 ) 2 − ( 1 4 ) 2 ] = 0.25 \begin{aligned} \mathrm{Gini \ index}(D, 是否有房) & = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v)\\ & = \frac{2}{6} \times 0 + \frac{4}{6} \times [1 - (\frac{3}{4})^2 - (\frac{1}{4})^2] \\ & = 0.25 \end{aligned} Gini index(D,是否有房)=v=1VDDvGini(Dv)=62×0+64×[1(43)2(41)2]=0.25

8. 对于年收入属性则有:

在这里插入图片描述

G i n i   i n d e x ( D , 是否有房 ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) = 2 6 × 0 + 4 6 × [ 1 − ( 3 4 ) 2 − ( 1 4 ) 2 ] = 0.25 \begin{aligned} \mathrm{Gini \ index}(D, 是否有房) & = \sum_{v=1}^V \frac{|D^v|}{|D|}\mathrm{Gini}(D^v)\\ & = \frac{2}{6} \times 0 + \frac{4}{6} \times [1 - (\frac{3}{4})^2 - (\frac{1}{4})^2] \\ & = 0.25 \end{aligned} Gini index(D,是否有房)=v=1VDDvGini(Dv)=62×0+64×[1(43)2(41)2]=0.25

经过如上流程,构建的决策树,如下图:

在这里插入图片描述


现在我们来总结一下 CART(Classification and Regression Tree,分类和回归树) 的算法流程:

while(当前节点"不纯"):
    1. 遍历每个变量的每一种分割方式,找到最好的分割点
    2. 分割成两个节点 N1 和 N2

    if 每个节点足够"纯":
        return  # 结束

2.5 总结

2.5.1 常见决策树的启发函数比较

一、信息熵

E n t ( D ) = − ∑ k = 1 n p k log ⁡ 2 p k \mathrm{Ent}(D) = -\sum_{k = 1}^n p_k \log_2^{p_k} Ent(D)=k=1npklog2pk

  • D D D 表示数据集
  • n n n 表示数据集中类别的个数
  • p k p_k pk 表示数据集中第 k k k 类样本所占的比例

二、信息增益:ID3 决策树

G a i n ( D , a ) = E n t ( D ) − E n t ( D ∣ a ) = E n t ( D ) − ∑ v = 1 V D v D E n t ( D v ) \begin{aligned} \mathrm{Gain}(D, a) & = \mathrm{Ent}(D) - \mathrm{Ent}(D|a)\\ & = \mathrm{Ent}(D) - \sum_{v=1}^V \frac{D^v}{D} \mathrm{Ent}(D^v) \end{aligned} Gain(D,a)=Ent(D)Ent(Da)=Ent(D)v=1VDDvEnt(Dv)

  • G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a) 表示使用属性 a a a 对数据集 D D D 进行划分所获得的信息增益
  • E n t ( D ∣ a ) \mathrm{Ent}(D|a) Ent(Da) 表示使用属性 a a a 对数据集 D D D 进行划分后的条件熵
  • V V V 表示属性 a a a 的可取值个数
  • D v D \frac{D^v}{D} DDv 表示数据集 D D D 中属性 a a a 取值为 v v v 的样本所占的比例
  • E n t ( D v ) \mathrm{Ent}(D^v) Ent(Dv) 表示数据集 D D D 中属性 a a a 取值为 v v v 的样本子集的信息熵。

三、信息增益率:C4.5 决策树

G a i n   R a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) \mathrm{Gain \ Ratio}(D, a) = \frac{\mathrm{Gain}(D, a)}{\mathrm{IV}(a)} Gain Ratio(D,a)=IV(a)Gain(D,a)

  • G a i n   R a t i o ( D , a ) \mathrm{Gain \ Ratio}(D, a) Gain Ratio(D,a) 表示使用属性 a a a 对数据集 D D D 进行划分所获得的信息增益率
  • G a i n ( D , a ) \mathrm{Gain}(D, a) Gain(D,a) 表示使用属性 a a a 对数据集 D D D 进行划分所获得的信息增益
  • I V ( a ) \mathrm{IV}(a) IV(a) 表示属性 a a a 的固有值(Intrinsic Value)
    • I V ( a ) = − ∑ v = 1 V D v D log ⁡ 2 D v D \mathrm{\mathrm{IV}}(a) = - \sum_{v=1}^V \frac{D^v}{D} \log_2 \frac{D^v}{D} IV(a)=v=1VDDvlog2DDv
    • 其中:
      • V V V 表示属性 a a a 的可取值个数
      • D v D \frac{D^v}{D} DDv 表示数据集 D D D 中属性 a a a 取值为 v v v 的样本所占的比例
    • 固有值 I V ( a ) \mathrm{IV}(a) IV(a) 反映了属性 a a a 对数据集 D D D 的划分能力。 I V ( a ) \mathrm{IV}(a) IV(a) 值越大,表示属性 a a a 对数据集 D D D 的划分能力越强。

四、基尼值

G i n i ( D ) = ∑ k = 1 ∣ y ∣ ∑ k ′ ≠ k p k p k ′ = 1 − ∑ k = 1 ∣ y ∣ p k 2 \begin{aligned} \mathrm{Gini}(D) & = \sum_{k=1}^{|y|}\sum_{k'\neq k}p_k p_k'\\ & = 1 - \sum_{k=1}^{|y|}p_k^2 \end{aligned} Gini(D)=k=1yk=kpkpk=1k=1ypk2

  • G i n i ( D ) \mathrm{Gini}(D) Gini(D) 表示数据集 D D D 的基尼值
  • ∣ y ∣ |y| y 表示数据集中类别的个数
  • p k p_k pk 表示数据集中第 k k k 类样本所占的比例

五、基尼指数:CART 决策树

G i n i   i n d e x ( D , a ) = ∑ v = 1 V D v D G i n i ( D v ) \mathrm{Gini \ index}(D, a) = \sum_{v = 1}^V \frac{D^v}{D} \mathrm{Gini}(D^v) Gini index(D,a)=v=1VDDvGini(Dv)

  • G i n i   i n d e x ( D , a ) \mathrm{Gini \ index}(D, a) Gini index(D,a) 表示使用属性 a a a 对数据集 D D D 进行划分所获得的基尼指数
  • D v D \frac{D^v}{D} DDv 表示数据集 D D D 中属性 a a a 取值为 v v v 的样本所占的比例
  • G i n i ( D v ) \mathrm{Gini}(D^v) Gini(Dv) 表示数据集 D D D 中属性 a a a 取值为 v v v 的样本子集的基尼值

名称 提出时间 提出作者 分支方式 回归任务 分类任务 离散特征 连续特征 备注
ID3 1986 Ross Quinlan 信息增益 ID3 只能对离散属性的数据集构成决策树
C4.5 1993 Ross Quinlan 信息增益率 解决了 ID3 分支过程中总喜欢偏向选择值较多的属性
CART 1984 Breiman等人 Gini 指数或最小二乘法 可以进行分类和回归,可以处理离散属性,也可以处理连续属性

Q1:这些公式都是用来干什么的?
A1:这些公式都是用于决策树学习中的概念。

  • 信息熵(Entropy):衡量数据集合纯度的指标,值越小表示数据集合越纯。
  • 信息增益(Information Gain):衡量使用属性 a a a 对数据集 D D D 进行划分所获得的纯度提升。
  • 信息增益率(Information Gain Ratio):对信息增益进行了归一化,以解决信息增益对可取值数目较多的属性有所偏好的问题。
  • 基尼值(Gini Value):与信息熵类似,也是衡量数据集合纯度的指标。
  • 基尼指数(Gini Index):CART 决策树使用基尼指数来选择最优划分属性。

总之,这些公式都是用于选择最优划分属性,从而构建决策树。


Q2:什么是决策树?
A2:决策树(Decision Tree)是一种常用的监督学习方法,可以用于分类和回归问题。它通过对数据集的递归划分,构建一棵树形结构来进行预测。

决策树的每个非叶子节点表示一个属性测试,每个分支代表一个测试输出,而每个叶子节点存储一个类别标签。使用决策树进行预测时,从根节点开始,对实例进行测试,根据测试结果选择对应的分支进入下一层节点,直到到达叶子节点,最终将叶子节点存储的类别标签作为预测结果。

决策树具有易于理解和解释、计算复杂度较低、能够处理类别型和数值型数据等优点。


Q3:决策树有什么应用?
A3:决策树在各个领域都有广泛的应用,包括金融、医疗、电子商务、市场营销等。它可以用于分类和回归问题,例如:

  • 银行可以使用决策树来预测客户是否会违约。
  • 医生可以使用决策树来辅助诊断疾病。
  • 电子商务网站可以使用决策树来预测用户是否会购买某个产品。
  • 市场营销人员可以使用决策树来划分客户群体,以便更好地进行营销活动。

此外,决策树还可以用作其他机器学习算法的基础模型,例如随机森林和梯度提升树等。


Q4:决策树有什么缺点?
A4:尽管决策树具有很多优点,但它也有一些缺点,主要包括:

  • 容易过拟合:决策树容易生成过于复杂的模型,导致过拟合。为了避免过拟合,需要对决策树进行剪枝。
  • 不稳定性:决策树对数据中的微小变化非常敏感,这可能导致生成的模型不稳定。可以通过集成学习方法来提高模型的稳定性。
  • 局部最优:决策树学习算法采用贪心策略,每次选择最优划分属性,但这并不能保证生成的决策树是全局最优的。

尽管存在这些缺点,但决策树仍然是一种非常实用的机器学习方法。


Q5:如何构建决策树?
A5:构建决策树通常包括以下步骤:

  1. 选择最优划分属性:使用某种指标(如信息增益、信息增益率、基尼指数等)来选择最优划分属性。
  2. 划分数据集:根据最优划分属性的取值,将数据集划分为若干个子集。
  3. 递归构建决策树:对每个子集递归地构建决策树,直到满足停止条件(如子集中所有样本属于同一类别、子集中样本数量小于阈值等)。

构建好的决策树可能会过拟合,因此需要对其进行剪枝。剪枝通常包括预剪枝后剪枝两种方法。

  • 预剪枝是在构建决策树的过程中进行剪枝
  • 后剪枝是在构建好决策树进行剪枝

构建决策树的具体方法可能会因算法而异,常见的决策树算法包括 ID3、C4.5 和 CART 等。

名称 提出时间 提出作者 分支方式 回归任务 分类任务 离散特征 连续特征 备注
ID3 1986 Ross Quinlan 信息增益 ID3 只能对离散属性的数据集构成决策树
C4.5 1993 Ross Quinlan 信息增益率 解决了 ID3 分支过程中总喜欢偏向选择值较多的属性
CART 1984 Breiman等人 Gini 指数或最小二乘法 可以进行分类和回归,可以处理离散属性,也可以处理连续属性

2.5.1.1 ID3 算法的优缺点

ID3 算法是一种决策树算法,它的优点包括简单易懂,理论清晰,方法简单,学习能力较强,健壮性好,不受噪声影响,可以训练缺少属性值的实例。

但是,ID3 算法也有一些缺点

  • 它只考虑分类型的特征,没有考虑连续特征,比如长度、密度都是连续值,无法在 ID3 运用,这大大限制了ID3的用途 —— ID3 算法只能对描述属性为离散型的数据集构建决策树
  • ID3 算法对于缺失值没有进行考虑,没有考虑过拟合的问题
  • ID3 算法在选择根节点和各内部节点中的分支属性时,采用信息增益 G a i n ( D ) \mathrm{Gain}(D) Gain(D) 作为评价标准。而信息增益的缺点是倾向于选择取值较多的属性,在有些情况下这类属性可能不会提供太多有价值的信息

2.5.1.2 C4.5 算法的优缺点

C4.5 算法是一种决策树算法,它是 ID3 算法的一种延伸和优化。 C4.5 算法对 ID3 算法进行了改进,改进点主要有:

  • 用信息增益率 G a i n   R a t i o ( D ) \mathrm{Gain \ Ratio}(D) Gain Ratio(D) 来选择划分特征,克服了用信息增益选择的不足
  • 能够处理离散型和连续型的属性类型,即将连续型的属性进行离散化处理
  • 能够处理具有缺失属性值的训练数据
  • 在构造树的过程中进行剪枝

C4.5 算法具有条理清晰,能处理连续型属性,防止过拟合,准确率较高和适用范围广等优点。但是,C4.5 算法也有一些缺点

  • C4.5 对数据进行多次顺序扫描和排序,效率较低
  • 虽然使用了更加先进的信息增益率 G a i n   R a t i o ( D ) \mathrm{Gain \ Ratio}(D) Gain Ratio(D),但信息增益率 G a i n   R a t i o ( D ) \mathrm{Gain \ Ratio}(D) Gain Ratio(D) 会对可取值数目较少的属性有所偏好
  • C4.5 只适合于能够驻留于内存的数据集,当训练集大得无法在内存中容纳时,程序无法运行

2.5.1.3 CART 算法的优缺点

CART 算法是一种二叉决策树算法,它既可以用于分类问题,也可以用于回归问题。在分类问题中,CART 算法使用基尼系数作为特征选择准则。CART 算法可以处理连续型和离散型的属性类型,并且可以处理具有缺失属性值的训练数据。

与 ID3 和 C4.5 相比,CART 算法的优点如下:

  • 使用简化的二叉树结构,运算速度更快
  • CART 算法不仅可以用于分类问题,还可以用于回归问题

缺点

  • 与 C4.5 相比,CART 算法没有剪枝策略

注意:

  • C4.5 不一定是二叉树,但 CART 一定是二叉树

2.5.1.4 多变量决策树(Multi-variate Decision Tree)

无论是 ID3、C4.5 还是 CART,在做特征选择的时候都是选择最优的一个特征来做分类决策。但是大多数时候,分类决策不应该是由某一个特征决定的,而是应该由一组特征决定的。这样得到的决策树更加准确。这种由一组特征生成的决策树叫做多变量决策树(Multi-variate Decision Tree)。

在选择最优特征的时候,多变量决策树不是选择某一个最优特征,而是选择最优的一个特征线性组合来做决策。这个算法的代表是 OC1,这里不多介绍。

一般情况下,当样本发生一点点的改动,就会导致树结构的剧烈改变。这个问题可以通过集成学习里面的随机森林之类的方法解决。

2.5.2 决策树变量的两种类型

一、数字型(Numeric)

变量类型是整数或浮点数,如前面例子中的“年收入”。用>=><<=作为分割条件(排序后,利用已有的分割情况,可以优化分割算法的时间复杂度)。

二、名称型(Nominal)

类似编程语言中的枚举类型,变量只能从有限的选项中选取,比如前面例子中的“婚姻情况”,只能是“单身”,“已婚”或“离婚”,并使用=来分割。

2.5.3 如何评估分割点的好坏?

如果一个分割点可以将当前的所有节点分为两类,使得每一类都很“纯”,也就是同一类的记录较多,那么就是一个好分割点。

比如上面的例子,“拥有房产”,可以将记录分成两类,“是”的节点全部都可以偿还债务(没有拖欠贷款),非常“纯”;“否”的节点,拖欠贷款和不拖欠贷款的人都有,不是很“纯”,但是两个节点加起来的纯度之和与原始节点的纯度之差最大,所以按照这种方法分割。

构建决策树采用贪心算法,只考虑当前纯度差最大的情况作为分割点

2.5.4 【拓展】贪心算法、动态规划和分治算法

Q1:什么是贪心算法?
A1:贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是局部最优解能决定全局最优解。简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。

贪心算法并不保证能够得到全局最优解,因为它并不总是做出在某种意义上的最佳选择但对于许多问题来说,贪心算法能产生非常接近最优解的结果,甚至是最优解


Q2:什么是动态规划?
A2:动态规划是一种用来解决最优化问题的算法。它通过将问题分解为更小的子问题来解决,通常使用递归或迭代的方法。动态规划通常用于求解具有重叠子问题和最优子结构性质的问题。

重叠子问题意味着子问题会被多次计算,因此动态规划算法会将已经计算过的子问题的解存储起来,避免重复计算。最优子结构性质意味着问题的最优解可以通过其子问题的最优解来构造。

动态规划算法通常用于求解组合优化问题,如最短路径、最长公共子序列和背包问题等。


Q3:什么是分治算法?
A3:分治算法是一种解决问题的方法,它将一个复杂的问题分解为若干个更小的子问题,然后递归地解决这些子问题,最后将子问题的解组合起来得到原问题的解。分治算法通常用于解决具有递归结构的问题。

分治算法的基本步骤包括:

  1. 分解:将原问题分解为若干个规模较小的子问题。
  2. 解决:递归地解决每个子问题。如果子问题的规模足够小,则直接求解。
  3. 合并:将子问题的解组合起来,构成原问题的解。

分治算法的经典应用包括快速排序、归并排序和二分查找等


Q4:贪心算法、动态规划和分治算法有什么区别?
A4:贪心算法、动态规划和分治算法都是用来解决最优化问题的算法,但它们之间存在一些区别。

  • 贪心算法在每一步都采取当前状态下最优的选择,希望能够得到全局最优解。它并不保证能够得到全局最优解,但对于许多问题来说,贪心算法能产生非常接近最优解的结果,甚至是最优解。

  • 动态规划通过将问题分解为更小的子问题来解决,通常使用递归或迭代的方法。它通常用于求解具有重叠子问题和最优子结构性质的问题。动态规划算法会将已经计算过的子问题的解存储起来,避免重复计算。

  • 分治算法将一个复杂的问题分解为若干个更小的子问题,然后递归地解决这些子问题,最后将子问题的解组合起来得到原问题的解。分治算法通常用于解决具有递归结构的问题。

总之,贪心算法、动态规划和分治算法都是用来解决最优化问题的算法,但它们采取的方法不同。贪心算法在每一步都采取局部最优选择;动态规划通过分解问题并存储子问题的解来避免重复计算;分治算法通过分解问题并递归地解决子问题来得到原问题的解。


Q5:动态规划和分治算法都是使用递归,二者有什么区别吗?
A5:动态规划和分治算法都可以使用递归来解决问题,但它们之间存在一些重要的区别。

  • 分治算法通过将一个复杂的问题分解为若干个更小的子问题来解决,然后递归地解决这些子问题,最后将子问题的解组合起来得到原问题的解。分治算法通常用于解决具有递归结构的问题。

  • 动态规划也通过将问题分解为更小的子问题来解决,但它通常用于求解具有重叠子问题和最优子结构性质的问题。动态规划算法会将已经计算过的子问题的解存储起来,避免重复计算。这种存储已经计算过的子问题的解的方法被称为“记忆化”。

总之,动态规划和分治算法都可以使用递归来解决问题,但它们采取的方法不同。

  • 分治算法通过 分解问题 并 递归地解决子问题来得到原问题的解
  • 动态规划通过 分解问题 并 存储子问题的解来避免重复计算

3. CART 剪枝

学习目标

  • 了解为什么要进行 CART 剪枝
  • 知道常用的 CART 剪枝方法

3.1 为什么要剪枝

在这里插入图片描述

图形描述

  • 横轴表示在决策树创建过程中树的结点总数(决策树的结点总数可以理解为模型的复杂度,结点越多,模型越复杂),纵轴表示决策树的预测精度
  • 实线显示的是决策树在训练集上的精度,虚线显示的是在一个独立的测试集上的精度

随着树的增长,在训练样集上的精度是单调上升的,然而在独立的测试样例上测出的精度先上升后下降。很明显,模型(决策树)出现了过拟合!

出现这种情况的原因

  • 原因 1:噪声、样本冲突,即错误的样本数据(学习到了错误的样本和特征)
  • 原因 2:特征(即属性)不能完全作为分类标准
  • 原因 3:学习到了巧合的现律性,这些规律并不是真正的规律,一般是因为数据量不够大

剪枝(Pruning)是决策树学习算法对付"过拟合"的主要手段。

Pruning:英[ˈpruːnɪŋ] 美[ˈpruːnɪŋ]
v. 修剪树枝; 打杈; 裁减; 削减; 精简;
n. 修剪;剪枝;
adj. 修剪用的;

在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学得“太好”了,以致于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合。因此,可通过主动去掉一些分支来降低过拟合的风险。

Q:如何判断决策树泛化性能是否提升呢?
A:可使用前面介绍的留出法,即预留一部分数据用作“测试集”以进行性能评估

例如对下表的西瓜数据集,我们将其随机划分为两部分,其中编号为 {1, 2, 3, 6, 7, 10, 14, 15, 16, 17}的样例组成训练集,编号为{4, 5, 8, 9, 11, 12, 13}的样例组成测试集。

训练集

编号 色泽 根蒂 敲声 纹理 脐部 触感 好瓜
1 青绿 蜷缩 浊响 清晰 凹陷 硬滑
2 乌黑 蜷缩 沉闷 清晰 凹陷 硬滑
3 乌黑 蜷缩 浊响 清晰 凹陷 硬滑
6 青绿 稍蜷 浊响 清晰 稍凹 软粘
7 乌黑 稍蜷 浊响 稍糊 稍凹 软粘
10 青绿 硬挺 清脆 清晰 平坦 软粘
14 浅白 稍蜷 沉闷 稍糊 凹陷 硬滑
15 乌黑 稍蜷 浊响 清晰 稍凹 软粘
16 浅白 蜷缩 浊响 模糊 平坦 硬滑
17 青绿 蜷缩 沉闷 稍糊 稍凹 硬滑

测试集

编号 色泽 根蒂 敲声 纹理 脐部 触感 好瓜
4 青绿 蜷缩 沉闷 清晰 凹陷 硬滑
5 浅白 蜷缩 浊响 清晰 凹陷 硬滑
8 乌黑 稍蜷 浊响 清晰 稍凹 硬滑
9 乌黑 稍蜷 沉闷 稍糊 稍凹 软粘
11 浅白 硬挺 清脆 模糊 平坦 硬滑
12 浅白 蜷缩 浊响 模糊 平坦 软粘
13 青绿 稍蜷 浊响 稍糊 凹陷 硬滑

假定咱们采用信息增益 G a i n ( D ) \mathrm{Gain}(D) Gain(D) 准则来划分属性选择,则上表中训练集将会生成一棵决策树,如下所示。为便于讨论,我们对圈中的部分结点做了编号。

在这里插入图片描述

接下来,我们一起看一下,如何对这一棵树进行剪枝。

3.2 常用的剪枝方法

决策树剪枝的基本策略有“预剪枝”(pre-pruning)和“后剪枝”(post- pruning):

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

3.2.1 预剪枝

首先,基于信息增益准则,我们会选取属性“脐部”来对训练集进行划分,并产生 3 个分支,如下图所示。然而,是否应该进行这个划分呢?预剪枝要对划分前后的泛化性能进行估计。

在这里插入图片描述

在划分之前,所有样例集中在根结点。

  • 若不进行划分,该结点将被标记为叶结点(没有子节点了),其类别标记为训练样例数最多的类别,假设我们将这个叶结点标记为“好瓜”。
  • 那么我们用前面表的测试集对这个单结点决策树进行评估。则编号为 {4, 5, 8} 的样例被分类正确。另外 4 个样例分类错误,于是测试集精度为 3 7 × 100 % = 42.9 % \frac{3}{7}\times 100\% = 42.9\% 73×100%=42.9%

在用属性“脐部”划分之后,上图中的结点 ②、③、④ 分别包含编号为 {1, 2, 3, 14}{6, 7, 15, 17}{10, 16} 的训练样例,因此这 3 个结点分别被标记为叶结点“好瓜”、“好瓜”、“坏瓜”。

在这里插入图片描述

此时,测试集中编号为 {4, 5, 8, 11, 12} 的样例被分类正确,测试集精度为 5 7 × 100 % = 71.4 % > 42.9 % \frac{5}{7}\times 100\% = 71.4\% > 42.9\% 75×100%=71.4%>42.9%

于是,用“脐部”进行划分得以确定(确定“脐部”为根节点了)。

然后,决策树算法应该对结点 2 进行划分,基于信息增益准则将挑选出划分属性“色泽”。然而,在使用“色泽”划分后,编号为 {5} 的测试集样本分类结果会由正确转为错误,使得测试集精度下降为 57.1 % 57.1\% 57.1%。于是,预剪枝策略将禁止结点 2 被划分。

对结点 3 ,最优划分属性为“根蒂”,划分后测试集精度仍为 71.4 % 71.4\% 71.4%,这个划分不能提升测试集精度,于是预剪枝策略禁止结点 3 被划分。

对结点 4,其所含训练样例己属于同一类,不再进行划分。

于是,基于预剪枝策略从上表数据所生成的决策树如上图所示,其测试集精度为 71.4 % 71.4\% 71.4%。这是一棵仅有一层划分的决策树,亦称“决策树桩”(Decision Stump)。

3.2.2 后剪枝

后剪枝先从训练集生成一棵完整决策树,继续使用上面的案例.从前面可知,我们前面构造的决策树的测试集精度为 42.9 % 42.9\% 42.9%

在这里插入图片描述

后剪枝首先考察结点 6。若将其领衔的分支剪除(相当于把结点 6 替换为叶子结点),替换后的叶结点包含编号为 {7, 15} 的训练样本,于是该叶结点的类别标记为“好瓜”,此时决策树的测试集精度提高至 57.1 % 57.1\% 57.1%。于是,后剪枝策略决定剪枝,如下图所示。

在这里插入图片描述

然后考察结点 5。若将其邻衔的子树替换为叶结点,则替换后的叶结点包含编号为 {6, 7, 15} 的训练样例,叶结点类别标记为“好瓜”,此时决策树测试集精度仍为 57.1 % 57.1\% 57.1%。于是,可以不进行剪枝。

对结点 2。若将其领衔的子树替换为叶结点,则替换后的叶结点包含编号为 {1, 2, 3, 14} 的训练样例,叶结点标记为“好瓜”,此时决策树的测试集精度提高至 71.4 % 71.4\% 71.4%。于是,后剪枝策略决定剪枝。

对结点 3 和 1,若将其领衔的子树替换为叶结点,则所得决策树的测试集精度分别为 71.4 % 71.4\% 71.4% 42.9 % 42.9\% 42.9%,均未得到提高,于是它们被保留。

最终,基于后剪枝策略所生成的决策树就如上图所示(就剪了一下),其测试集精度为 $71.4%。

对比两种剪枝方法

  • 后剪枝决策树通常比预剪枝决策树保留了更多的分支。
  • 一般情形下,后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。
  • 但后剪枝过程是在生成完全决策树之后进行的。并且要自底向上地对树中的所有非叶结点进行逐一考察,因此其训练时间开销比未剪枝决策树和预剪枝决策树都要大得多。

Q1:在剪枝的过程中,如果精度不变呢?
A1:如果剪枝前后的精度没有变化,那么剪枝的决策取决于具体情况。

  • 在预剪枝中,由于提前终止树的生长可以减少计算量,所以通常会进行剪枝。
  • 在后剪枝中,由于剪枝可以简化模型,减少模型复杂度,所以也可能会进行剪枝。但是,这些都不是绝对的,具体决策取决于实际应用场景和需求。

Q2:预剪枝和后剪枝哪个更好?
A2:预剪枝和后剪枝都有各自的优缺点,它们哪个更好取决于具体的应用场景。

  • 预剪枝的优点是计算速度快,因为它在构建决策树的过程中提前终止树的生长,减少了计算量。但是,预剪枝有时会过于简化模型,导致欠拟合。

  • 后剪枝的优点是能够更好地避免欠拟合,因为它在构建完整的决策树后再进行剪枝。但是,后剪枝的计算量比预剪枝大,计算速度较慢。

总之,预剪枝和后剪枝都是有效的防止过拟合的方法。在实际应用中,可以根据数据集的大小、模型复杂度和计算能力等因素来选择合适的方法。


小结

  • 剪枝原因【了解】
    • 噪声、样本冲突,即错误的样本数据
    • 特征即属性不能完全作为分类标准
    • 巧合的规律性,数据量不够大
  • 常用剪枝方法【知道】
    • 预剪枝:在构建树的过程中,同时剪枝
      • 限制节点最小样本数
      • 指定数据高度
      • 指定熵值的最小值
    • 后剪枝:把一棵树,构建完成之后,再进行从下往上的剪枝

4. 特征工程-特征提取

学习目标

  • 了解什么是特征提取
  • 知道字典特征提取操作流程
  • 知道文本特征提取操作流程
  • 知道 TF-IDF 的实现思想

什么是特征提取呢?

在这里插入图片描述

我们想让机器去识别文字时,并不能很好的把文字识别出来,此时我们可以将文字转换为数字,以提高机器的识别效果。

4.1 特征提取

4.1.1 定义

将任意数据(如文本或图像)转换为可用于机器学习的数字特征。

注意:将 特征 数值化 是为了计算机更好的去理解数据。

  • 特征提取的分类
    • 字典特征提取(特征离散化)
    • 文本特征提取
    • 图像特征提取(在深度学习将介绍)

4.1.2 特征提取 API

sklearn.feature_extraction

4.2 字典特征提取

sklearn.feature_extraction.DictVectorizer 是一个类,它可以将特征值映射列表转换为向量。这个转换器将特征名称映射到特征值的映射列表(类似于字典的对象)转换为Numpy数组或scipy.sparse矩阵,以便与 scikit-learn 估计器(模型)一起使用。

sklearn.feature_extraction.DictVectorizer(sparse=True,...)
  • 作用:对字典数据进行特征值化。
  • 参数
    • dtype:默认为 np.float64。特征值的类型。作为 dtype 参数传递给 Numpy 数组 或 scipy.sparse 矩阵构造函数。
    • separator:默认为 '='。在进行一键编码时构造新特征时使用的分隔符字符串。
    • sparse:默认为 True。是否应该产生 scipy.sparse 矩阵。
    • sort:默认为 True。在拟合时是否应对 feature_names_vocabulary_ 进行排序。

sparse: 英[spɑːs] 美[spɑːrs]
adj. 稀少的; 稀疏的; 零落的;


类方法

DictVectorizer.fit_transform(X)
  • 作用:用于学习特征名称到索引的映射列表,并将输入数据转换为向量。
  • 参数
    • X:输入数据,应该是一个字典列表,其中每个字典表示一个样本,键表示特征名称,值表示特征值。
    • y:可选参数,默认为 None。目标值,仅用于兼容 scikit-learn 的管道(pipeline)和模型选择工具。

类属性

DictVectorizer.get_feature_names_out()
  • 作用:该方法返回一个包含特征名称的列表,列表中的元素顺序与转换后的向量中的特征顺序相同。
  • 参数
    • input_features:可选参数,默认为 None。输入特征名称,用于生成输出特征名称。

4.2.1 应用

我们对以下数据进行特征提取:

[{
    
    'city': '北京', 'temperature': 100}, 
 {
    
    'city': '上海', 'temperature': 60}, 
 {
    
    'city': '深圳', 'temperature': 30}]

4.2.2 流程分析

  1. 实例化类DictVectorizer
  2. 调用fit_transform方法输入数据并转换(注意返回格式)
from sklearn.feature_extraction import DictVectorizer


data = [{
    
    'city': '北京', 'temperature': 100},
        {
    
    'city': '上海', 'temperature': 60},
        {
    
    'city': '深圳', 'temperature': 30}]

# 1. 实例化一个转换器类
transfer = DictVectorizer(sparse=False)  # 不产生 `scipy.sparse` 矩阵

# 2. 调用fit_transform方法
data = transfer.fit_transform(data)
print(f"返回的结果:\r\n {
      
      data}")

print(f"特征名称:\r\n {
      
      transfer.get_feature_names_out()}")

结果:

返回的结果:
[[  0.   1.   0. 100.]
 [  1.   0.   0.  60.]
 [  0.   0.   1.  30.]]
特征名称:
['city=上海' 'city=北京' 'city=深圳' 'temperature']

这段代码使用了 scikit-learn 库中的 DictVectorizer 类来对字典类型的数据进行特征提取。DictVectorizer 类可以将字典类型的数据转换为矩阵形式,其中数值型特征保持不变,类别型特征会被转换为 one-hot 编码。

在这个例子中,原始数据包含三个样本,每个样本有两个特征:城市(city)和温度(temperature)。城市是一个类别型特征,温度是一个数值型特征。

使用 DictVectorizer 类对原始数据进行转换后,得到了一个 3x4 的矩阵。其中,前三列分别表示城市为上海、北京和深圳的 one-hot 编码,第四列表示温度

例如,第一个样本的城市为北京,所以在第二列(对应北京)的位置为 1,其他位置为 0;第二个样本的城市为上海,所以在第一列(对应上海)的位置为 1,其他位置为 0;第三个样本的城市为深圳,所以在第三列(对应深圳)的位置为 1,其他位置为 0。温度特征保持不变。


注意:如果没有加上sparse=False参数,则结果为:

返回的结果:
  (0, 1)	1.0
  (0, 3)	100.0
  (1, 0)	1.0
  (1, 3)	60.0
  (2, 2)	1.0
  (2, 3)	30.0
特征名称:
['city=上海' 'city=北京' 'city=深圳' 'temperature']

如果没有加上 sparse=False 参数,那么 DictVectorizer 类会返回一个稀疏矩阵(scipy.sparse 矩阵)。稀疏矩阵是一种特殊的矩阵,它只存储非零元素,可以大大节省内存。

在这个例子中,返回的稀疏矩阵采用了坐标格式(COO format)来存储。每一行表示一个非零元素,其中前两个数字表示该元素在矩阵中的坐标(行和列),第三个数字表示该元素的值

例如,第一行 (0, 1) 1.0 表示在第 0 行第 1 列的位置上有一个值为 1.0 的非零元素;第二行 (0, 3) 100.0 表示在第 0 行第 3 列的位置上有一个值为 100.0 的非零元素。

如果将这个稀疏矩阵转换为普通矩阵,那么就会得到与前面相同的结果:

[[  0.   1.   0. 100.]
 [  1.   0.   0. 60.]
 [  0.   0.   1. 30.]]

拓展内容:One-hot 编码

之前在学习 Pandas 中的离散化的时候,也实现了类似的效果。我们把这个处理数据的技巧叫做 “one-hot” 编码。

原始数据

在这里插入图片描述

转换后的 One-hot 数据

在这里插入图片描述

我们做的是为每个类别生成一个布尔列。这些列中只有一列可以为每个样本取值 1。因此,术语为一个热编码。


小结

  • 对于特征当中存在类别信息的,我们都会做 One-hot 编码处理

4.3 文本特征提取

sklearn.feature_extraction.text.CountVectorizer 是一个类,它可以将文本文档集合转换为令牌计数矩阵。该实现使用 scipy.sparse.csr_matrix 生成计数的稀疏表示。


令牌计数矩阵(Token Count Matrix)是一种用来表示文本文档集合的矩阵。它的每一行表示一个文档,每一列表示一个令牌(token),即一个单词或短语。矩阵中的元素表示该令牌在该文档中出现的次数。

例如,假设我们有两个文档:

文档1: "I love dogs"
文档2: "I love cats and dogs"

那么,对应的令牌计数矩阵为:

       I  love  dogs  cats  and
文档1: 1    1     1     0    0
文档2: 1    1     1     1    1

sklearn.feature_extraction.text.CountVectorizer 类可以将文本文档集合转换为令牌计数矩阵。它使用 scipy.sparse.csr_matrix 来生成计数的稀疏表示,可以大大节省内存


sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
  • 作用:对文本数据进行特征值化(转换为数字)。
  • 参数
    • stop_words。该参数用于指定停用词列表。
      • 如果设置为 'english',则使用内置的英语停用词列表。
      • 如果设置为一个列表,则该列表被认为包含停用词,所有这些停用词都将从结果令牌中删除。
      • 如果设置为 None,则不使用停用词。在这种情况下,将 max_df 设置为较高的值(例如在 0.7 到 1.0 的范围内)可以根据术语的语料库文档频率自动检测和过滤停用词。

方法一fit_transform

CountVectorizer.fit_transform(X)
  • 作用:用于学习词汇表并将文本文档集合转换为令牌计数矩阵。
  • 参数
    • X:输入数据,应该是一个字符串列表,其中每个字符串表示一个文档。
    • y:可选参数,默认为 None。目标值,仅用于兼容 scikit-learn 的管道和模型选择工具。
      返回值:该方法返回一个稀疏矩阵(sparse matrix),表示文本文档集合中每个文档的令牌计数。矩阵中的每一行表示一个文档,每一列表示一个特征(即一个令牌),元素值表示该令牌在该文档中出现的次数。

方法二CountVectorizer.get_feature_names_out()

CountVectorizer.get_feature_names_out()
  • 作用:返回一个包含特征名称的列表,列表中的元素顺序与转换后的向量中的特征顺序相同。
  • 参数
    • input_features:可选参数,默认为 None。输入特征名称,用于生成输出特征名称。

sklearn.feature_extraction.text.TfidfVectorizer

后面再对其说明

4.3.1 应用

我们对以下数据进行特征提取:

["life is short, i like python",
"life is too long, i dislike python"]

4.3.2 流程分析

  1. 实例化类 CountVectorizer
  2. 调用 fit_transform 方法输入数据并转换(注意返回格式,利用 toarray()进行sparse矩阵转换array数组)
from sklearn.feature_extraction.text import CountVectorizer


data = ["life is short, i like python",
        "life is too long, i dislike python"]

# 1. 实例化一个转换器类
transfer = CountVectorizer()

# 2. 调用fit_transform方法
data = transfer.fit_transform(raw_documents=data)

# 这里要使用toarray将sparse矩阵转换为ndarray矩阵
print("返回的特征名称为:", transfer.get_feature_names_out())
print("文本特征抽取的结果为:\r\n", data.toarray())  # 将稀疏矩阵转换为密集的 Numpy 数组

# 如果输出为sparse矩阵
print("\r\n文本特征抽取的结果为(sparse矩阵):\r\n", data)

结果如下

返回的特征名称为: ['dislike' 'is' 'life' 'like' 'long' 'python' 'short' 'too']
文本特征抽取的结果为:
 [[0 1 1 1 0 1 1 0]
 [1 1 1 0 1 1 0 1]]

文本特征抽取的结果为(sparse矩阵):
  (0, 2)	1
  (0, 1)	1
  (0, 6)	1
  (0, 3)	1
  (0, 5)	1
  (1, 2)	1
  (1, 1)	1
  (1, 5)	1
  (1, 7)	1
  (1, 4)	1
  (1, 0)	1

上面的代码使用了 sklearn.feature_extraction.text 模块中的 CountVectorizer 类来对给定数据进行文本特征提取。调用 fit_transform 方法将数据转换为令牌计数的稀疏矩阵表示。然后使用 toarray 方法将稀疏矩阵转换为密集的 Numpy 数组。使用 get_feature_names_out 方法获取与转换后数据的列对应的特征名称。输出显示了这些操作的结果。

CountVectorizer类用于将文本数据转换为数值特征向量。它通过统计每个文本中每个单词出现的次数来实现这一点。

在这个例子中,给定的数据包含两个文本字符串:“life is short, i like python” 和 “life is too long, i dislike python”。CountVectorizer首先对这些文本进行分词,得到 8 个不同的单词:‘dislike’, ‘is’, ‘life’, ‘like’, ‘long’, ‘python’, ‘short’ 和 ‘too’。然后,它统计每个文本中每个单词出现的次数,并将其转换为数值特征向量。

因此,第一个文本字符串"life is short, i like python"被转换为特征向量 [0 1 1 1 0 1 1 0],表示其中’dislike’出现 0 次,'is’出现 1 次,'life’出现 1 次,'like’出现 1 次,'long’出现 0 次,'python’出现 1 次,'short’出现 1 次,'too’出现 0 次。

同理,第二个文本字符串"life is too long, i dislike python"被转换为特征向量 [1 1 1 0 1 1 0 1],表示其中’dislike’出现 1 次,'is’出现1次,'life’出现 1 次,'like’出现 0 次,'long’出现 1 次,'python’出现 1 次,'short’出现 0 次,'too’出现 1 次。


Q1:分词的依据是什么,i为什么不算呢?
A1:分词是指将文本字符串分割成单独的单词或词语的过程。在英文文本中,分词通常是基于空格和标点符号进行的,因为英文单词之间通常用空格分隔。

在这个例子中,CountVectorizer使用了默认的分词器,它基于空格和标点符号对文本进行分词。因此,给定的两个文本字符串被分割成了如下单词:‘life’, ‘is’, ‘short’, ‘i’, ‘like’, ‘python’, ‘life’, ‘is’, ‘too’, ‘long’, ‘i’, ‘dislike’ 和 ‘python’。

然而,在生成特征向量时,CountVectorizer默认会忽略掉英文停用词。停用词是指在文本中经常出现,但对文本意义影响不大的词语,例如’I’, ‘me’, ‘my’, ‘myself’, 'we’等。在这个例子中,'i’被认为是一个停用词,因此在生成特征向量时被忽略掉了。

如果希望保留停用词,可以在创建CountVectorizer对象时指定stop_words=None参数,例如:

transfer = CountVectorizer(stop_words=None)

这样,在生成特征向量时就不会忽略掉任何单词了。

简单来说,停用词就是不统计的词


Q2:如果我们将数据替换成中文呢?

"人生苦短,我喜欢Python", "生活太长久,我不喜欢Python"

A2:那么最终得到的结果是:

返回的特征名称为: ['人生苦短' '我不喜欢python' '我喜欢python' '生活太长久']
文本特征抽取的结果为:
 [[1 0 1 0]
 [0 1 0 1]]

文本特征抽取的结果为(sparse矩阵):
  (0, 0)	1
  (0, 2)	1
  (1, 3)	1
  (1, 1)	1

正确的划分应该是:'人生' '苦短' '不喜欢' 'python' '喜欢' '生活' '太长久'。这是因为CountVectorizer本身并不支持中文分词。它默认的分词器是基于空格和标点符号进行分词的,这对于英文文本来说是有效的,但对于中文文本来说并不适用,因为中文单词之间通常没有空格。

4.3.3 jieba 分词处理

jieba.cut 方法是 jieba 库中用于对文本进行分词的主要方法。它接受一个字符串作为输入,并返回一个生成器,其中包含分词后的单词。

jieba:结巴

jieba.cut()
  • 作用:对中文文本进行分词
  • 参数
    • sentence:要分词的文本字符串。
    • cut_all:是否使用全模式。
      • 如果为 True,则返回所有可能的分词结果;
      • 如果为 False,则返回最精确的分词结果。默认为 False。
    • HMM:是否使用隐马尔科夫模型(HMM)进行未登录词识别。默认为 True。
    • use_paddle:是否使用 PaddlePaddle 深度学习框架进行分词。默认为 False。

下面是一个简单的例子,展示了如何使用 jieba.cut 方法对文本进行分词:

import jieba

text = "人生苦短,我喜欢Python"

# 使用精确模式进行分词
words = jieba.cut(text, cut_all=False)
print("精确模式分词结果:", "/".join(words))

# 使用全模式进行分词
words = jieba.cut(text, cut_all=True)
print("全模式分词结果:", "/".join(words))

输出结果为:

精确模式分词结果: 人生/苦短///喜欢/Python
全模式分词结果: 人生/苦短////喜欢/Python

可以看到,使用不同的参数会影响分词的结果。


如果要使用 CountVectorizer 处理中文文本,需要自定义一个中文分词器,并将其传递给 CountVectorizer。可以使用第三方中文分词库,例如 jieba 来实现。

下面是一个简单的例子,展示了如何使用 jieba 库和 CountVectorizer 对中文文本进行特征提取:

import jieba
from sklearn.feature_extraction.text import CountVectorizer

def cut_word(text):
    # 使用jieba库进行中文分词
    return " ".join(list(jieba.cut(text)))

data = ["人生苦短,我喜欢Python", 
        "生活太长久,我不喜欢Python"]

# 对中文文本进行分词
data = [cut_word(text) for text in data]

# 创建CountVectorizer对象,并指定自定义的分词器
transfer = CountVectorizer(tokenizer=lambda text: text.split())

# 调用fit_transform方法
data = transfer.fit_transform(raw_documents=data)

# 输出结果
print("返回的特征名称为:", transfer.get_feature_names_out())
print("文本特征抽取的结果为:\n", data.toarray())

输出结果为:

返回的特征名称为: ['python' '不' '人生' '喜欢' '太长久' '我' '生活' '苦短' ',']
文本特征抽取的结果为:
 [[1 0 1 1 0 1 0 1 1]
 [1 1 0 1 1 1 1 0 1]]

这里其实还有问题,停用词并不包含(按道理应该包含的)

4.3.4 案例分析

对以下三句话进行特征值化:

今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。

我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。

如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。
  • 分析
    • 准备句子,利用 jieba.cut() 进行分词。
    • 实例化 CountVectorizer
    • 将分词结果变成字符串当作 fit_transform() 的输入值
from sklearn.feature_extraction.text import CountVectorizer
import jieba


def cut_word(text):
    # 用jieba对中文字符串进行分割
    text = " ".join(list(jieba.cut(text)))  # 分的词后面加上空格
    return text


if __name__ == "__main__":
    data = ["今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。", 
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
    
    # 将原始数据转换为分好词的形式
    text_lst = []
    for sentence in data:
        text_lst.append(cut_word(sentence))
    print("分好词的数据为:\r\n", text_lst)
    
    # 1. 实例化一个转换器类(对于中文,我们也可以使用停用词)
    transfer = CountVectorizer(stop_words=["一种", "今天", "我", ",", "。"])

    # 2. 调用fit_transform方法
    data = transfer.fit_transform(raw_documents=text_lst)

    # 这里要使用toarray将sparse矩阵转换为ndarray矩阵
    print("\r\n返回的特征名称为:", transfer.get_feature_names_out())
    print("\r\n文本特征抽取的结果为:\r\n", data.toarray())

返回结果

分好词的数据为:
 ['今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。']

返回的特征名称为: ['不会' '不要' '之前' '了解' '事物' '光是在' '几百万年' '发出' '取决于' '只用' '后天' '含义' '大部分'
 '如何' '如果' '宇宙' '我们' '所以' '放弃' '方式' '明天' '星系' '晚上' '某样' '残酷' '每个' '看到'
 '真正' '秘密' '绝对' '美好' '联系' '过去' '这样']

文本特征抽取的结果为:
 [[0 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 0]
 [0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 1]
 [1 0 0 4 3 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0]]

注意:中文的停用词有很多,我们不能每次都手动输入停用词,所以可以借用别人总结好的停用词。

停用词大全举例:最全中文停用词表整理(1893个)


QCountVectorizer 是用来分词和数量统计的,这些次数统计对于我们来说有什么意义呢?
ACountVectorizer 是一个文本特征提取工具,它可以将文本数据转换为数值特征向量,以便用于机器学习模型。它通过统计每个文本中每个单词出现的次数来实现这一点

这些次数统计对于文本分析和自然语言处理任务来说非常重要。例如,在文本分类任务中,我们可以使用 CountVectorizer 将文本数据转换为数值特征向量,然后使用这些特征向量来训练分类器。分类器会根据每个文本中不同单词出现的次数来判断该文本属于哪个类别

此外,CountVectorizer 还可以用于其他自然语言处理任务,例如情感分析、主题建模和文本聚类等。在这些任务中,单词出现的次数也是非常重要的特征。

总之,CountVectorizer 提供了一种简单有效的方法,可以将文本数据转换为数值特征向量,以便用于各种自然语言处理任务。这些次数统计对于理解文本数据、挖掘文本中的信息以及构建有效的机器学习模型都非常重要


那如果把这样的词语特征用于分类,会出现什么问题

在这里插入图片描述

该如何处理某个词或短语在多篇文章中出现的次数高这种情况?

从上图中可以看到,“车”和“共享”出现的频率高,这篇文章可能是在说“共享单车”或“共享汽车”;“经济”“证券”“银行”出现的次数多,说明这篇文章可能与经融有关。

Q:那么上面这些分析是通过什么实现的呢?
A:就是我们之前按下不表的 TfidfVectorizer

4.3.5 TF-IDF 文本特征提取

TF-IDF 是 Term Frequency-Inverse Document Frequency 的缩写,中文译为“词频-逆文档频率”。它是一种用于评估单词在文档中的重要性的统计方法

主要思想如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类

作用:可以用来衡量单词在文档中的重要性。如果一个单词在某个文档中出现得很频繁,但在其他文档中很少出现,那么这个单词的 TF-IDF 值就会很高,说明它对这个文档的意义很大。

应用:TF-IDF 在自然语言处理领域有着广泛的应用。它常用于信息检索、文本分类、关键词提取和文本摘要等任务。例如,在信息检索系统中,可以使用 TF-IDF 来计算查询词与文档之间的相关性,从而返回与查询最相关的文档。

总之,TF-IDF 是一种常用的文本特征提取方法,它可以帮助我们衡量单词在文档中的重要性,并用于各种自然语言处理任务。

4.3.5.1 公式

  • 词频(Term Frequency,TF)指的是某一个给定的词语在该文件中出现的频率
  • 逆向文档频率(Inverse Document Frequency,IDF)是一个词语普遍重要性的度量。某一特定词语的 IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以 10 为底的对数得到
  • TF-IDF 的值就是 TF 和 IDF 的乘积。

T F I D F i , j = T F i , j × I D F i \mathrm{TFIDF}_{i,j} = \mathrm{TF_{i, j}}\times \mathrm{IDF}_i TFIDFi,j=TFi,j×IDFi

最终得出结果可以理解 某个词 语 j 某个词语_{j} 某个词j 某个文 档 i 某个文档_i 某个文i 中的重要程度。


举例

假如一篇文章的总词语数是 100 个,而词语“非常”出现了 5 次,那么“非常”一词在该文件中的词频就(TF)是 5 100 = 0.05 \frac{5}{100} = 0.05 1005=0.05。而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现“非常”一词的文件数。

所以,如果“非常”一词在 1,0000 份文件出现过,而文件总数是 10,000,000 份的话,其逆向文件频率就是 lg ⁡ 10 , 000 , 000 1 , 000 = 3 \lg{\frac{10,000,000}{1,000}} = 3 lg1,00010,000,000=3

最后“非常”对于这篇文档的 TF-IDF 的分数为:

T F I D F i , j = T F i , j × I D F i = 0.05 × 3 = 0.15 \begin{aligned} \mathrm{TFIDF}_{i,j} & = \mathrm{TF_{i, j}}\times \mathrm{IDF}_i\\ & = 0.05 \times 3\\ & = 0.15 \end{aligned} TFIDFi,j=TFi,j×IDFi=0.05×3=0.15

4.3.5.2 案例

from sklearn.feature_extraction.text import TfidfVectorizer
import jieba


def cut_word(txt):
    # 用jieba对中文字符串进行分词(使用空格分割)
    return " ".join(list(jieba.cut(txt)))


if __name__ == "__main__":
    data = ["今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。", 
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
    
    # 1. 使用jieba对中文数据进行分词
    txt_lst = []
    for sentence in data:
        txt_lst.append(cut_word(sentence))
    print("分词后的结果为:\r\n", txt_lst)
    
    # 2. 实例化一个TF-IDF转换器类
    transfer = TfidfVectorizer(stop_words=["一种", "今天", "我", ",", "。"])
    
    # 3. 调用fit_transform
    data = transfer.fit_transform(txt_lst)
    print("\r\n特征名称:\r\n", transfer.get_feature_names_out())
    print("\r\n特征数量:", len(transfer.get_feature_names_out()))
    print("\r\n文本特征抽取的结果:\r\n", data.toarray())

结果如下:

分词后的结果为:
 ['今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。']

特征名称:
 ['不会' '不要' '之前' '了解' '事物' '光是在' '几百万年' '发出' '取决于' '只用' '后天' '含义' '大部分'
 '如何' '如果' '宇宙' '我们' '所以' '放弃' '方式' '明天' '星系' '晚上' '某样' '残酷' '每个' '看到'
 '真正' '秘密' '绝对' '美好' '联系' '过去' '这样']

特征数量: 34

文本特征抽取的结果:
 [[0.         0.24253563 0.         0.         0.         0.
  0.         0.         0.         0.         0.24253563 0.
  0.24253563 0.         0.         0.         0.         0.24253563
  0.24253563 0.         0.48507125 0.         0.24253563 0.
  0.48507125 0.24253563 0.         0.         0.         0.24253563
  0.24253563 0.         0.         0.        ]
 [0.         0.         0.2410822  0.         0.         0.2410822
  0.2410822  0.2410822  0.         0.         0.         0.
  0.         0.         0.         0.2410822  0.55004769 0.
  0.         0.         0.         0.2410822  0.         0.
  0.         0.         0.48216441 0.         0.         0.
  0.         0.         0.2410822  0.2410822 ]
 [0.15895379 0.         0.         0.63581516 0.47686137 0.
  0.         0.         0.15895379 0.15895379 0.         0.15895379
  0.         0.15895379 0.15895379 0.         0.12088845 0.
  0.         0.15895379 0.         0.         0.         0.15895379
  0.         0.         0.         0.31790758 0.15895379 0.
  0.         0.15895379 0.         0.        ]]

4.3.6 TF-IDF 的重要性

分类机器学习算法进行文章分类中前期数据处理的方式之一。在自然语言处理的诸多课题如信息检索(Information Retrieval)和文本探勘(Text Mining)当中,我们希望找出重要的单词或文句。在过程中我们需要将文字进行量化(转化为向量)以进行后续处理及筛选。而 TF-IDF 是一种常用的方法来衡量单词对于一份文件的重要程度。它可以帮助我们在信息检索和文本挖掘等领域找到重要的单词或短语。


小结

  • 特征提取【了解】:将任意数据(如文本或图像)转换为可用于机器学习的数字特征
  • 特征提取分类:【了解】
    • 字典特征提取(特征离散化)。
    • 文本特征提取
    • 图像特征提取
  • 字典特征提取【知道】:字典特征提取就是对类别型数据进行转换。
  • API:sklearn.feature_extraction.DictVectorizer(sparse=True, ...)
    • sparse 矩阵(稀疏矩阵):
      • 节省内存
      • 提高读取效率
    • 注意:
      • 对于特征当中存在类别信息的我们都会做 One-hot 编码处理
  • 文本特征提取(英文)【知道】
    • API:sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
      • stop_words:停用词(不统计词频的次)
      • 注意
        • CountVectorizer没有 sparse 这个参数、
        • CountVectorizer对于英文句子,单个字母标点符号不做统计
  • 文本特征提取(中文)【知道】
    • 注意
      • 在中文文本特征提取之前,需要对句子(文章)进行分词
        • jieba.cut()
      • CountVectorizer依旧可以使用停用词,进行词语的限制
  • TF-IDF【知道】
    • 主要思想:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类
    • TF-IDF
      • TF:词频
      • IDF:逆向文档频率
      • API:sklearn.feature_extraction.text.TfidfVectorizer
      • 注意:
        • TFIDF 是分类机器学习算法进行文章分类的中前期数据处理方式之一

注意:特征工程并不是服务于决策树的,在其他特征提取方法(模型)中,我们也要使用特征工程使得数据(如文本或图像)转换为可用于机器学习的数字特征!

猜你喜欢

转载自blog.csdn.net/weixin_44878336/article/details/130798760
今日推荐