机器学习之决策树ID3/C4.5/CART学习算法比较

一、概述
  • 决策树是机器学习中最基础、应用最广泛的算法模型,常用于解决分类和回归问题。
  • 决策树的构建是一种自上而下的递归分裂学习方法,其学习的关键在于如何选择最优划分属性。一般情况下,随着划分过程不断进行,决策树的分支结点所包含的样本会尽可能属于同一类别,即结点的纯度(purity)越来越高。
  • 度量样本集合纯度有三种常用的评估准则:ID3、C4.5和CART。本文将从构造、应用和实现三个角度,对比这三种模型的异同点。
二、决策树学习算法
2.1 相亲数据集
编号 年龄 长相 工资 编程 类别
1 不会 不见
2 年轻 一般 中等
3 年轻 不会 不见
4 年轻 一般
5 年轻 一般 不会 不见
2.2 ID3(Iterative Dichotomiser 3)--信息增益

  信息熵(information entropy)是度量样本集合纯度最常用的一种指标。对于样本集合D,类别数为K,信息熵定义为:
H(D)=-\sum_{k=1}^K\frac{|C_k|}{|D|}\log_2\frac{|C_k|}{|D|}
  其中,C_k是样本集合D中属于第k(k=1,2,3...K)类的样本子集,|C_k|表示该子集的元素个数,|D|表示样本集合的元素个数。特征属性A的条件熵H(D|A)定义为:
H(D|A)=\sum_{i=1}^n\frac{|D_i|}{|D|}H(D_i)=\sum_{i=1}^n\frac{|D_i|}{|D|}(-\sum_{k=1}^K\frac{|D_{ik}|}{|D_i|}\log_2\frac{|D_{ik}|}{|D_i|})
  其中,|D_i|表示D中特征A取第i个值的样本子集,D_{ik}表示D_i中属于第k类的样本子集。因此,特征A的信息增益等于两者之差:
g(D,A)=H(D)-H(D|A)
  以表2.1中相亲数据为例,该数据包含5个样本集,正样本占比\frac{2}{5},负样本占比\frac{3}{5}。于是,根据公式计算出根节点的信息熵为:
H(D)=-\frac{3}{5}\log_2\frac{3}{5}-\frac{2}{5}\log_2\frac{2}{5}=0.971
  然后,计算当前属性集合{年龄,长相,工资,编程}中每个属性的条件熵。以属性“年龄”为例,它有2个可能的取值:{老,年轻}。若使用该属性对D进行划分,则可得到2个子集,分别为:D_1(年龄=老),D_2(年龄=年轻)。

  • 子集D_1包含编号{1}的1个样例,其中正样本占比p_1=\frac{0}{1},负样本占比p_2=\frac{1}{1}
  • 子集D_2包含编号{2,3,4,5}的4个样例,其中正样本占比p_1=\frac{2}{4},负样本占比p_2=\frac{2}{4}
    根据公式计算出属性=年龄的条件熵为:
    H(D|年龄)=\frac{1}{5}H(老)+\frac{4}{5}H(年轻)=\frac{1}{5}(-0)+\frac{4}{5}(-\frac{2}{4}\log_2\frac{2}{4}-\frac{2}{4}\log_2\frac{2}{4})=0.8
    依此类推:
    H(D|长相)=\frac{1}{5}H(帅)+\frac{3}{5}H(一般)+\frac{1}{5}H(丑)=0+\frac{3}{5}(-\frac{2}{3}\log_2\frac{2}{3}-\frac{1}{3}\log_2\frac{1}{3})+0=0.551
    H(D|工资)=\frac{3}{5}H(高)+\frac{1}{5}H(中等)+\frac{1}{5}H(低)=\frac{3}{5}(-\frac{2}{3}\log_2\frac{2}{3}-\frac{1}{3}\log_2\frac{1}{3})+0+0=0.551
    H(D|编程)=\frac{3}{5}H(不会)+\frac{2}{5}H(会)=\frac{3}{5}(0)+\frac{2}{5}(0)=0
    每个属性对应的信息增益为:
    g(D,年龄)=0.171,g(D,长相)=0.42,g(D,工资)=0.42,g(D,编程)=0.971
      由此可得,特征“编程”的信息增益最大,使用特征“编程”来进行划分所得的纯度提升越大。图2.1给出了基于“编程”对根节点进行划分的结果:
    图2.1 基于编程属性对根节点划分

      然后,决策树学习算法对每个分支节点做进一步划分。以图2.1中第一个分支节点(编程=会)为例,该节点包含的样本集合D_1有{2,4}两个样本,可用的属性集合有{年龄,长相,工资},基于D_1计算出各属性的信息增益,继续划分树节点,直到满足停止分裂的条件。
      最后,ID3对取值较多的特征有所偏好,特征取值越多意味着确定性越高,也就是条件熵越小,信息增益越大。如果将前面的编号也作为一个划分属性,其信息增益为0.971,它将产生5个分支,每个分支结点仅包含一个样本,显然这样划分出来的决策树不具备泛化能力,无法对新样本进行有效预测。因此,C4.5对ID3进行优化,通过引入信息增益比,对取值较多的特征进行惩罚,避免出现过拟合的特性,提升决策树的泛化能力。

信息熵和条件熵计算的scala-spark实现:

/**
    * 计算信息熵
    *
    * @param df
    * @param column
    * @return
    */
  def calculate(df: DataFrame, column: String = "label"): Double = {
    val counts = df.select(column).groupBy(column).agg(count(column)).collect().map(row => row.getLong(1))
    val totalCount = counts.sum.toDouble
    if (totalCount == 0) {
      return 0
    }
    counts.map {
      count =>
        var impurity = 0.0
        if (count != 0) {
          val freq = count / totalCount
          impurity -= freq * log2(freq)
        }
        impurity
    }.reduce((v1, v2) => v1 + v2)
  }

  /**
    * 计算每个特征的条件熵
    *
    * @param df
    * @param column
    * @return
    */
  def calculateFeature(df: DataFrame, column: String): Double = {
    val counts = df.select(column).groupBy(column).agg(count(column)).collect()
    val totalCount = counts.map(row => row.getLong(1)).sum.toDouble
    if (totalCount == 0) {
      return 0
    }
    val impurity = counts.map {
      row =>
        val featureValue = row.get(0).toString.toDouble
        val featureCount = row.getLong(1)
        val freq = featureCount / totalCount
        val tmp = df.filter(col(column) === featureValue)
        freq * calculate(tmp, "label")
    }.reduce((v1, v2) => v1 + v2)
    impurity
  }
2.3 C4.5--信息增益比

  特征A对于数据集D的信息增益比定义为:
g_R(D,A)=\frac{g(D,A)}{H_A(D)}
其中
H_A(D)=-\sum_{i=1}^n\frac{|D_i|}{|D|}\log_2\frac{|D_i|}{|D|}
称为数据集D关于A的取值熵。因此,可以根据上面的公式求出每个特征的取值熵:
H_{年龄}(D)=-\frac{1}{5}\log_2\frac{1}{5}-\frac{4}{5}\log_2\frac{4}{5}=0.722
H_{长相}(D)=-\frac{1}{5}\log_2\frac{1}{5}-\frac{3}{5}\log_2\frac{3}{5}-\frac{1}{5}\log_2\frac{1}{5}=1.371
H_{工资}(D)=-\frac{3}{5}\log_2\frac{3}{5}-\frac{1}{5}\log_2\frac{1}{5}-\frac{1}{5}\log_2\frac{1}{5}=1.371
H_{编程}(D)=-\frac{3}{5}\log_2\frac{3}{5}-\frac{2}{5}\log_2\frac{2}{5}=0.971
最终可计算出各个特征的信息增益比:
g_R(D,年龄)=\frac{g(D,年龄)}{H_{年龄}(D)}=\frac{0.171}{0.722}=0.2368
g_R(D,长相)=\frac{g(D,长相)}{H_{长相}(D)}=\frac{0.42}{1.371}=0.3063
g_R(D,工资)=\frac{g(D,工资)}{H_{工资}(D)}=\frac{0.42}{1.371}=0.3063
g_R(D,编程)=\frac{g(D,编程)}{H_{编程}(D)}=\frac{0.971}{0.971}=1
通过信息增益比,特征年龄对应的指标上升了,而特征长相和工资有所下降。

2.4 CART--基尼指数(Gini)

  CART决策树使用基尼指数来选择划分属性,Gini描述的是数据的纯度,其定义为:
Gini(D)=1-\sum_{k=1}^n(\frac{|C_k|}{|D|})^2
  其中,C_k是样本集合D中属于第k(k=1,2,3...K)类的样本子集,|C_k|表示该子集的元素个数,|D|表示样本集合的元素个数。如果所有样本都属于同一个类别,则|C_k|=|D|Gini(D)=0,此时impurity最小。CART利用基尼指数构造二叉决策树。如果特征是离散型变量,将样本按特征A的取值切分成两份;如果特征是连续型变量,CART的处理方式和C4.5相同,先将特征值进行升序排序,然后把左边第一个值(index=1)作为一个分类,右边其他值作为另一个分类,计算其Gini指数,然后移动index的位置,直到计算完所有的分类结果,然后选取Gini最小的位置对应的index作为切分点。特征A的Gini指数定义为:
Gini(D|A)=\sum_{i=1}^n\frac{|D_i|}{|D|}Gini(D_i)
当n=2时,该公式可以简化为:
Gini(D|A)=\frac{|D_1|}{|D|}Gini(D_1) + \frac{|D_2|}{|D|}Gini(D_2)

使用CART分类准则,选取年龄维度,把老作为特征标签,那么年轻就被划分到另外一类

老(总数=1) 年轻(总数=4)
类别 不见 见、不见、见、不见

Gini(D|年龄=老)=\frac{1}{5}(1-(\frac{1}{1})^2-(\frac{0}{1})^2)+\frac{4}{5}(1-(\frac{1}{2})^2-(\frac{1}{2})^2)=0.4
Gini(D|年龄=年轻)=\frac{1}{5}(1-(\frac{1}{1})^2-(\frac{0}{1})^2)+\frac{4}{5}(1-(\frac{1}{2})^2-(\frac{1}{2})^2)=0.4

帅(总数=1) 一般、丑(总数=4)
类别 不见 见、不见、见、不见

Gini(D|长相=帅)=\frac{1}{5}(1-(\frac{1}{1})^2-(\frac{0}{1})^2)+\frac{4}{5}(1-(\frac{1}{2})^2-(\frac{1}{2})^2)=0.4
Gini(D|长相=丑)=\frac{1}{5}(1-(\frac{1}{1})^2-(\frac{0}{1})^2)+\frac{4}{5}(1-(\frac{1}{2})^2-(\frac{1}{2})^2)=0.4

一般(总数=3) 帅、丑(总数=2)
类别 见、不见 不见

Gini(D|长相=一般)=\frac{3}{5}(1-(\frac{2}{3})^2-(\frac{1}{3})^2)+\frac{2}{5}(1-(\frac{1}{2})^2-(\frac{1}{2})^2)=0.47

高(总数=3) 中等、低(总数=2)
类别 见、不见 见、不见

Gini(D|工资=高)=\frac{3}{5}(1-(\frac{2}{3})^2-(\frac{1}{3})^2)+\frac{2}{5}(1-(\frac{1}{2})^2-(\frac{1}{2})^2)=0.47

会(总数=2) 不会(总数=3)
类别 不见

Gini(D|编程=会)=\frac{2}{5}(1-(\frac{2}{2})^2)+\frac{3}{5}(1-(\frac{3}{3})^2)=0
因此,特征编程的Gini指数最小,选择该特征作为最优的切分点。

三、小结

  通过比较ID3、C4.5和CART三种决策树的构造准则,在同一个样本集上,表现出不同的划分行为。

  • ID3和C4.5在每个结点上可以产生多个分支,而CART每个结点只会产生两个分支
  • C4.5通过引入信息增益比,弥补了ID3在特征取值比较多时,由于过拟合造成泛化能力变弱的缺陷
  • ID3只能处理离散型变量,而C4.5和CART可以处理连续型变量
  • ID3和C4.5只能用于分类任务,而CART可以用于分类和回归任务

参考文献:
[1]诸葛越,葫芦娃.百面机器学习
[2]周志华.机器学习

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容