ID3与C4.5算法

大家好,我是一名正在学习机器学习的小白,最近在写一些关于机器学习基础概念的文章。如果你也对机器学习感兴趣,或者想要了解一些基础知识,欢迎来关注我哦!

决策树

决策树是一种基于树形结构的分类和回归模型。它通过对数据集进行划分,构建一棵树来进行决策。每个节点代表一个特征,每个分支代表该特征的一个取值,每个叶子节点代表一个分类或回归结果。在分类问题中,决策树可以用于判断一个样本属于哪个类别;在回归问题中,决策树可以用于预测一个连续值。决策树具有易于理解、易于解释、易于实现等优点,因此被广泛应用于数据挖掘、机器学习等领域。

生成决策树的一般步骤如下:

  1. 收集数据:收集数据是生成决策树的第一步,需要收集有关决策问题的所有相关数据。

  2. 准备数据:准备数据是生成决策树的第二步,需要将收集到的数据进行处理,包括数据清洗、数据转换、数据归一化等。

  3. 选择属性:选择属性是生成决策树的第三步,需要根据数据集中的属性选择最佳的属性作为划分标准。

  4. 划分数据集:划分数据集是生成决策树的第四步,需要将数据集根据选择的属性进行划分,得到子集。

  5. 计算信息增益:计算信息增益是生成决策树的第五步,需要计算每个子集的信息熵,以及划分前后的信息增益。

  6. 递归生成决策树:递归生成决策树是生成决策树的最后一步,需要根据计算得到的信息增益,选择最佳的属性作为当前节点,然后递归生成子树,直到所有的叶子节点都是同一类别。

  7. 剪枝:剪枝是生成决策树的最后一步,需要对生成的决策树进行剪枝,以避免过拟合的问题。

ID3算法

ID3算法是一种用于决策树分类的算法,它基于信息熵的概念,通过计算每个特征的信息增益来选择最优特征,从而构建决策树。

ID3算法的步骤如下:

  1. 计算数据集的熵(entropy),公式为: H ( D ) = − ∑ i = 1 n p i log ⁡ 2 p i H(D)=-\sum_{i=1}^{n}p_i\log_2p_i H(D)=i=1npilog2pi,其中 n n n为类别数, p i p_i pi为第 i i i类样本在数据集中的占比。

    例如,假设有一个数据集包含10个样本,其中有6个属于类别A,2个属于类别B,2个属于类别C。则该数据集的熵可以计算如下:

    H ( X ) = − ( 6 10 log ⁡ 2 6 10 + 2 10 log ⁡ 2 2 10 + 2 10 log ⁡ 2 2 10 ) ≈ 1.57 H(X)=-\left(\frac{6}{10}\log_2\frac{6}{10}+\frac{2}{10}\log_2\frac{2}{10}+\frac{2}{10}\log_2\frac{2}{10}\right) \approx 1.57 H(X)=(106log2106+102log2102+102log2102)1.57

    这个结果表示该数据集的不确定性较高,因为它包含多个类别,每个类别出现的概率相对较接近。

  2. 对于每个特征,计算其信息增益(information gain),公式为: I G ( D , f ) = H ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ H ( D v ) IG(D, f)=H(D)-\sum_{v=1}^{V}\frac{|D^v|}{|D|}H(D^v) IG(D,f)=H(D)v=1VDDvH(Dv),其中 f f f为特征, V V V为特征 f f f的取值个数, D v D^v Dv为特征 f f f取值为 v v v的样本子集, ∣ D v ∣ |D^v| Dv D v D^v Dv的样本个数, ∣ D ∣ |D| D是数据集样本个数。

    信息增益是用来衡量一个特征对于分类任务的重要性的指标,它的计算方法如下:

    信息增益 = 数据集的熵 − 特征的熵 \text{信息增益} = \text{数据集的熵} - \text{特征的熵} 信息增益=数据集的熵特征的熵

    其中,数据集的熵表示整个数据集的混乱程度,特征的熵表示在该特征下,数据集的混乱程度。

    假设我们有一个数据集,其中包含了 10 个样本,每个样本有两个特征:颜色和形状。其中,颜色有红、绿、蓝三种取值,形状有圆、方两种取值。我们的任务是根据这两个特征将样本分为两类:好瓜和坏瓜。

    样本 颜色 形状 类别
    1 坏瓜
    2 坏瓜
    3 坏瓜
    4 绿 好瓜
    5 绿 好瓜
    6 好瓜
    7 绿 好瓜
    8 坏瓜
    9 绿 好瓜
    10 好瓜

    首先,我们需要计算数据集的熵。根据熵的定义,我们可以得到:

    数据集的熵 = − 6 10 log ⁡ 2 6 10 − 4 10 log ⁡ 2 4 10 ≈ 0.971 \text{数据集的熵} = -\frac{6}{10}\log_2\frac{6}{10} - \frac{4}{10}\log_2\frac{4}{10} \approx 0.971 数据集的熵=106log2106104log21040.971

    接下来,我们需要计算每个特征的熵。首先,我们计算颜色的熵。根据颜色的取值,我们可以将数据集分成三个子集:

    子集 颜色 类别
    1 坏瓜
    2 绿 好瓜、好瓜
    3 好瓜、坏瓜、好瓜

    根据子集的类别分布,我们可以得到每个子集的熵:

    子集1的熵 = − 1 log ⁡ 2 1 − 0 log ⁡ 2 0 = 0 \text{子集1的熵} = -1\log_2 1 - 0\log_2 0 = 0 子集1的熵=1log210log20=0

    子集2的熵 = − 2 2 log ⁡ 2 2 2 − 0 log ⁡ 2 0 = 0 \text{子集2的熵} = -\frac{2}{2}\log_2\frac{2}{2} - 0\log_2 0 = 0 子集2的熵=22log2220log20=0

    子集3的熵 = − 2 3 log ⁡ 2 2 3 − 1 3 log ⁡ 2 1 3 ≈ 0.918 \text{子集3的熵} = -\frac{2}{3}\log_2\frac{2}{3} - \frac{1}{3}\log_2\frac{1}{3} \approx 0.918 子集3的熵=32log23231log2310.918

    根据颜色的熵的定义,我们可以得到:

    颜色的熵 = 3 10 × 0 + 2 10 × 0 + 5 10 × 0.918 ≈ 0.459 \text{颜色的熵} = \frac{3}{10}\times 0 + \frac{2}{10}\times 0 + \frac{5}{10}\times 0.918 \approx 0.459 颜色的熵=103×0+102×0+105×0.9180.459

    接下来,我们计算形状的熵。根据形状的取值,我们可以将数据集分成两个子集:

    子集 形状 类别
    1 坏瓜、坏瓜、坏瓜、好瓜、好瓜、好瓜
    2 好瓜、坏瓜、好瓜、好瓜

    根据子集的类别分布,我们可以得到每个子集的熵:

    子集1的熵 = − 3 6 log ⁡ 2 3 6 − 3 6 log ⁡ 2 3 6 ≈ 1 \text{子集1的熵} = -\frac{3}{6}\log_2\frac{3}{6} - \frac{3}{6}\log_2\frac{3}{6} \approx 1 子集1的熵=63log26363log2631

    子集2的熵 = − 3 4 log ⁡ 2 3 4 − 1 4 log ⁡ 2 1 4 ≈ 0.811 \text{子集2的熵} = -\frac{3}{4}\log_2\frac{3}{4} - \frac{1}{4}\log_2\frac{1}{4} \approx 0.811 子集2的熵=43log24341log2410.811

    根据形状的熵的定义,我们可以得到:

    形状的熵 = 6 10 × 1 + 4 10 × 0.811 ≈ 0.971 \text{形状的熵} = \frac{6}{10}\times 1 + \frac{4}{10}\times 0.811 \approx 0.971 形状的熵=106×1+104×0.8110.971

    最后,我们可以计算颜色和形状的信息增益:

    颜色的信息增益 = 0.971 − 0.459 ≈ 0.512 \text{颜色的信息增益} = 0.971 - 0.459 \approx 0.512 颜色的信息增益=0.9710.4590.512

    形状的信息增益 = 0.971 − 0.971 = 0 \text{形状的信息增益} = 0.971 - 0.971 = 0 形状的信息增益=0.9710.971=0

    因此,我们可以得到结论:在这个数据集中,颜色的信息增益比形状的信息增益更大,因此颜色是更重要的特征。

  3. 选择信息增益最大的特征作为当前节点的划分特征,将数据集划分为若干个子集,每个子集对应一个分支。

  4. 对于每个子集,如果所有样本属于同一类别,则将该子集作为叶节点,否则递归地进行步骤2-3,直到所有子集都被划分为同一类别或者没有更多特征可供划分。

ID3算法的缺点包括:

  1. 对于连续型变量的处理不够灵活。ID3算法只能处理离散型变量,对于连续型变量需要进行离散化处理,这可能会导致信息损失。

  2. 对于噪声数据和缺失数据的处理不够鲁棒。ID3算法对于噪声数据和缺失数据的处理能力较弱,可能会导致决策树的不稳定性。

  3. 容易出现过拟合现象。ID3算法在构建决策树时,容易出现过拟合现象,即对训练数据过度拟合,导致泛化能力较差。

  4. 对于类别数较多的数据集,决策树的构建效率较低。ID3算法在处理类别数较多的数据集时,需要进行大量的计算,导致构建效率较低。

这些缺点主要是由于ID3算法的基本思想是贪心算法,只考虑当前节点的最优划分,而没有考虑全局最优解。因此,在实际应用中,需要根据具体情况选择合适的决策树算法。


下面是一个简单的例子,假设我们有一个数据集,其中包含5个样本,每个样本有两个特征(色泽和根蒂),以及一个类别(好瓜或坏瓜):

色泽 根蒂 类别
青绿 蜷缩 好瓜
乌黑 蜷缩 好瓜
乌黑 硬挺 坏瓜
青绿 硬挺 坏瓜
浅白 蜷缩 坏瓜

首先,我们需要计算数据集的熵:

H ( D ) = − 3 5 log ⁡ 2 3 5 − 2 5 log ⁡ 2 2 5 = 0.971 H(D)=-\frac{3}{5}\log_2\frac{3}{5}-\frac{2}{5}\log_2\frac{2}{5}=0.971 H(D)=53log25352log252=0.971

然后,对于每个特征,我们需要计算其信息增益:

  • 对于色泽特征:(浅白时特征的信息熵为0,所以省略)

I G ( D , 色泽 ) = 0.971 − 3 5 ( − 2 3 log ⁡ 2 2 3 − 1 3 log ⁡ 2 1 3 ) − 2 5 ( − 1 2 log ⁡ 2 1 2 − 1 2 log ⁡ 2 1 2 ) = 0.019 IG(D, 色泽)=0.971-\frac{3}{5}(-\frac{2}{3}\log_2\frac{2}{3}-\frac{1}{3}\log_2\frac{1}{3})-\frac{2}{5}(-\frac{1}{2}\log_2\frac{1}{2}-\frac{1}{2}\log_2\frac{1}{2})=0.019 IG(D,色泽)=0.97153(32log23231log231)52(21log22121log221)=0.019

  • 对于根蒂特征:

I G ( D , 根蒂 ) = 0.971 − 3 5 ( − 1 3 log ⁡ 2 1 3 − 2 3 log ⁡ 2 2 3 ) − 2 5 ( − 1 2 log ⁡ 2 1 2 − 1 2 log ⁡ 2 1 2 ) = 0.271 IG(D, 根蒂)=0.971-\frac{3}{5}(-\frac{1}{3}\log_2\frac{1}{3}-\frac{2}{3}\log_2\frac{2}{3})-\frac{2}{5}(-\frac{1}{2}\log_2\frac{1}{2}-\frac{1}{2}\log_2\frac{1}{2})=0.271 IG(D,根蒂)=0.97153(31log23132log232)52(21log22121log221)=0.271

因此,根蒂特征的信息增益最大,我们选择根蒂特征作为当前节点的划分特征,将数据集划分为两个子集:

  • 根蒂为蜷缩的子集:{青绿, 蜷缩, 好瓜}和{乌黑, 蜷缩, 好瓜}
  • 根蒂为硬挺的子集:{乌黑, 硬挺, 坏瓜}和{青绿, 硬挺, 坏瓜}和{浅白, 蜷缩, 坏瓜}

对于根蒂为蜷缩的子集,所有样本属于同一类别(好瓜),因此将该子集作为叶节点;对于根蒂为硬挺的子集,我们需要递归地进行步骤2-3,选择信息增益最大的特征进行划分。在这个例子中,我们可以选择色泽特征作为下一个划分特征,因为它是唯一一个还没有被使用过的特征。最终得到的决策树如下:

根蒂
├── 蜷缩: 好瓜
└── 硬挺
    ├── 青绿
    │   └── 色泽
    │       ├── 浅白: 坏瓜
    │       └── 青绿: 坏瓜
    └── 乌黑: 坏瓜

这个决策树可以用于预测新的样本的类别。例如,如果我们有一个新的样本,它的色泽为乌黑,根蒂为蜷缩,我们可以按照决策树的路径进行判断,最终得到它的类别为好瓜。

以下是一个简单的Python实现ID3算法的示例代码:

import math

def entropy(data):
    """
    计算数据集的熵
    """
    count = {}
    for d in data:
        label = d[-1]
        if label not in count:
            count[label] = 0
        count[label] += 1
    entropy = 0
    for c in count.values():
        p = c / len(data)
        entropy -= p * math.log2(p)
    return entropy

def split_data(data, axis, value):
    """
    根据给定特征和特征值划分数据集
    """
    new_data = []
    for d in data:
        if d[axis] == value:
            new_d = d[:axis] + d[axis+1:]
            new_data.append(new_d)
    return new_data

def choose_feature(data):
    """
    选择最优特征
    """
    num_features = len(data[0]) - 1
    base_entropy = entropy(data)
    best_info_gain = 0
    best_feature = -1
    for i in range(num_features):
        feature_values = [d[i] for d in data]
        unique_values = set(feature_values)
        new_entropy = 0
        for value in unique_values:
            sub_data = split_data(data, i, value)
            p = len(sub_data) / len(data)
            new_entropy += p * entropy(sub_data)
        info_gain = base_entropy - new_entropy
        if info_gain > best_info_gain:
            best_info_gain = info_gain
            best_feature = i
    return best_feature

def majority_label(labels):
    """
    返回出现次数最多的标签
    """
    count = {}
    for label in labels:
        if label not in count:
            count[label] = 0
        count[label] += 1
    sorted_count = sorted(count.items(), key=lambda x: x[1], reverse=True)
    return sorted_count[0][0]

def create_tree(data, features):
    """
    创建决策树
    """
    labels = [d[-1] for d in data]
    if len(set(labels)) == 1:
        return labels[0]
    if len(data[0]) == 1:
        return majority_label(labels)
    best_feature = choose_feature(data)
    best_feature_name = features[best_feature]
    tree = {best_feature_name: {}}
    del(features[best_feature])
    feature_values = [d[best_feature] for d in data]
    unique_values = set(feature_values)
    for value in unique_values:
        sub_features = features[:]
        sub_data = split_data(data, best_feature, value)
        tree[best_feature_name][value] = create_tree(sub_data, sub_features)
    return tree

if __name__ == '__main__':
    data = [
        [1, 1, 'yes'],
        [1, 1, 'yes'],
        [1, 0, 'no'],
        [0, 1, 'no'],
        [0, 1, 'no'],
    ]
    features = ['no surfacing', 'flippers']
    tree = create_tree(data, features)
    print(tree)

输出结果为:

{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

这个决策树可以解释为:

  • 如果没有浮出水面,则不会吸氧,预测结果为“不会游泳”;
  • 如果浮出水面,则可能会吸氧,需要进一步判断是否有鳍;
  • 如果有鳍,则预测结果为“会游泳”;
  • 如果没有鳍,则预测结果为“不会游泳”。

C4.5算法

C4.5算法是一种决策树算法,是ID3算法的改进版本。C4.5算法在ID3算法的基础上进行了优化,主要包括以下几个方面:

  1. C4.5算法能够处理连续型属性,而ID3算法只能处理离散型属性。

  2. C4.5算法采用信息增益比来选择最优划分属性,而ID3算法只采用信息增益。

  3. C4.5算法能够处理缺失值,而ID3算法不能处理缺失值。

  4. C4.5算法采用剪枝技术来避免过拟合,而ID3算法没有剪枝技术。

C4.5算法的主要思想是通过递归地将数据集划分为更小的子集,直到所有子集都属于同一类别或者达到预定的停止条件。在划分数据集的过程中,C4.5算法采用信息增益比来选择最优划分属性,同时使用剪枝技术来避免过拟合。

C4.5算法的具体步骤如下:

  1. 构建决策树的根节点,将所有训练样本放入根节点。
  2. 对于每个非叶子节点,计算每个属性的信息增益比,选择信息增益比最大的属性作为划分属性。
  3. 根据划分属性将训练样本分成若干个子集,每个子集对应一个子节点。
  4. 对于每个子节点,如果所有训练样本都属于同一类别,则将该节点标记为叶子节点,并将该类别作为叶子节点的类别;否则,递归地对该子节点进行步骤2-4,直到所有叶子节点都被标记。
  5. 对生成的决策树进行剪枝,避免过拟合。
  1. 为什么要用信息增益率
    信息增益的方法已经可以选出划分属性了,为什么还要有信息增益率,这不是增加大家的学习成本吗,莫非信息增益有什么缺陷?

    确实有缺陷。

    如果各个属性的值的个数比较类似,缺陷并不明显
    比如:场地{室内、室外},风力{大风、小风},属性值都只有两个
    如果各个属性的值的个数差异较大,会发现信息增益偏向值个数多的属性
    比如:场地{室内、室外},风力{台风、狂风、大风、小风、微风、无风},属性值一个是两个一个是六个
    举个例子,如果我们把图中 id 列,也当成属性来划分,会发现计算出的信息增益比场地划分还大。这也很好理解,因为样本 id 各不相同,相当于划分后每个分支(仅有一个样本)的分类都确定了,信息增益自然最大。但这并不能反映决策树的泛化能力。

    所以为了纠正信息增益偏向值个数多的属性这个缺陷,C4.5 决策树提出了信息增益率。

  2. 什么是信息增益率
    很容易想到,既然信息增益偏向值个数多的属性,那我们就给值多的属性进行"惩罚"。

    先看一下信息增益率的公式:
    信息增益率计算公式为:

    G a i n _ r a t i o ( D , A ) = G a i n ( D , A ) I V ( A ) Gain\_ratio(D, A) = \frac{Gain(D, A)}{IV(A)} Gain_ratio(D,A)=IV(A)Gain(D,A)

    其中, G a i n ( D , A ) Gain(D, A) Gain(D,A)表示数据集 D D D在属性 A A A上的信息增益, I V ( A ) IV(A) IV(A)表示属性 A A A的固有值,计算公式为:

    I V ( A ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ log ⁡ 2 ∣ D i ∣ ∣ D ∣ IV(A) = -\sum_{i=1}^{n}\frac{|D_i|}{|D|}\log_2\frac{|D_i|}{|D|} IV(A)=i=1nDDilog2DDi

    其中, n n n为属性 A A A的取值个数, D i D_i Di D D D中在属性 A A A上取值为 i i i的样本子集, ∣ D ∣ |D| D为数据集 D D D的样本总数。

    可以看出IV的公式很像熵的公式,由熵的性质可知,分布越分散熵越大,所以这里值的个数越多IV(A)越大,对于增益率分母越大值越小,所以信息增益率可以起到"惩罚"值个数多的属性的目的。

C4.5算法对于连续型属性的离散化处理主要有以下几个步骤:

  1. 对于每个连续型属性,将其按照从小到大的顺序排序。

  2. 对于每个相邻的属性值,计算其中点值,作为一个候选的分割点。

  3. 对于每个候选的分割点,将数据集按照该点进行分割,并计算分割后的信息增益。

  4. 选择信息增益最大的分割点作为最终的分割点。

  5. 将数据集按照最终的分割点进行分割,并将连续型属性转化为离散型属性,分别表示小于等于分割点和大于分割点两个取值。

你可能感兴趣的:(算法,机器学习,决策树)