基于ID3算法的决策树分类模型

本文介绍了ID3算法的概念、优缺点,详细讲解了信息熵、条件熵和算法伪代码。接着,通过Python代码展示了如何实现ID3算法,包括信息熵计算、特征选择和决策树构建。最后,提供了一个实例验证算法的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

一、ID3算法是什么?

二、算法详解

2.1 信息熵

2.2 条件熵

2.3 伪代码

三、算法复现

3.1 导入基本库

3.2 信息熵函数

3.3 无特征可用,返回实例集中最多的类别

3.4 返回最大信息增益对应的特征列

3.5 分支节点切割

3.6 递归构建决策树

3.7 美观输出决策树

3.8 预测

四、实例验证

4.1 获取数据集

4.2 调用算法

4.3  进行预测

总结


提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

用于理解决策树模型,并以此进行复现

一、ID3算法是什么?

ID3(Iterative Dichotomiser 3)算法是一种用于构建决策树的经典算法,由Ross Quinlan在1986年提出。下面是关于ID3算法的优点和缺点:

优点:
        1. 简单易懂:ID3算法使用信息增益作为特征选择的准则,其基本思想直观易懂,容易理解和实现。
        2. 高效快速:ID3算法采用自顶向下递归构建决策树,每次选择信息增益最大的特征进行划分,因此算法执行速度相对较快。
        3. 可处理多类别特征:ID3算法能够处理多类别的分类问题,不限制特征的取值类型。

缺点:
        1. 对缺失数据敏感:ID3算法不能直接处理缺失数据,当训练集存在缺失数据时,会导致特征选择受到影响,进而影响生成的决策树模型。
        2. 容易过拟合:ID3算法倾向于选择具有较多取值的特征进行划分,这样容易导致产生复杂的决策树模型,可能出现过拟合的情况,特别是当训练数据噪声较大时。
        3. 不支持连续特征:ID3算法的特征选择只考虑了离散特征,对于连续特征,需要进行离散化处理才能应用于ID3算法。

需要注意的是,ID3算法是决策树构建算法的基础,并且被后续的C4.5和CART算法等进一步改进和优化。因此,实际应用中可以根据具体情况选择更适合的决策树算法。

二、算法详解

2.1 信息熵

信息熵(Entropy)是信息论中用来衡量信息量的概念。在决策树算法中,信息熵常用于衡量数据集的纯度和混乱程度,从而进行特征选择。 信息熵的计算公式如下: $$ \text{Entropy}(D) = -\sum_{i=1}^{c} p_i \log_2(p_i) $$ 其中,$D$表示数据集,$c$表示数据集中的类别数量,$p_i$表示数据集中属于第$i$个类别的样本占比。$\log_2$表示以2为底的对数。 计算信息熵时,需要统计各个类别样本在数据集中的占比,并将其带入上述公式进行计算。信息熵的取值范围介于0和1之间,熵越高表示数据集越混乱。 通过计算不同特征划分后的子集的信息熵,并比较其减少的程度,可以选择信息熵减少最大的特征作为最佳划分特征,用于构建决策树的节点。通过这样的递归划分和特征选择,可以构建出具有较高分类能力的决策树模型。

 2.2 条件熵

假设训练集中某个属性有 n个属性值,则会产生 n 个分 支,第m(m=1,2,…,n)个分支包含了取该属性值的所有样本。 若训练集中有U 个样本,第 m个分支包含了 V_m个,则该结 点的权重为 V_m/U,即样本数越多的分支结点影响越大。那么 经过划分后条件熵为

$$ N=\sum_{n}^{m}\frac{V_m}{U}I_m $$

其中I_m是第m个分支的信息熵。

2.3 伪代码

函数 ID3(数据集 D, 特征集 A)
    创建节点 node
    if 数据集 D 中所有实例属于同一类别 C:
        将 node 标记为 C 类别叶节点
        返回 node
    if 特征集 A 为空集:
        将 node 标记为数据集 D 中实例数最多的类别叶节点
        返回 node
    选择最优特征 best_feature = 通过计算信息增益选择最大的特征
    将 node 标记为选择的最优特征 best_feature
    for best_feature 的每个取值 value:
        令 data_subset = 根据 best_feature 的取值将数据集 D 分割成子集
        if data_subset 为空集:
            创建叶节点,并将其标记为数据集 D 中实例数最多的类别叶节点
            将该节点加到 node 作为子节点
        else:
            递归调用 ID3(data_subset, A - {best_feature}),并将返回的子树根节点加到 node 作为子节点
    返回 node

三、算法复现

3.1 导入基本库

import numpy as np
import copy 

3.2 信息熵函数

def entropy(labels):                                                    # 计算数据集的信息熵

    unique_labels, label_counts = np.unique(labels, return_counts=True) # 获取目标变量的唯一值以及统计次数
    total_count = len(labels)                                           # 总样本量个数
    prob = label_counts / total_count                                   # 该唯一值的占比
    ent = -np.sum(prob * np.log2(prob))                                 # 计算信息熵
    return ent

3.3 无特征可用,返回实例集中最多的类别

def majority_vote(labels):                                              # 多数表决确定叶节点标签
                             
    unique_values, counts = np.unique(labels, return_counts=True)       # 使用numpy.unique()函数统计每个元素的出现次数
    majority_label = unique_values[np.argmax(counts)]                   # 找到出现次数最多的元素
    return majority_label

3.4 返回最大信息增益对应的特征列

def choose_best_feature(data):                                          # 选择最佳划分特征,返回索引
    
    labels   = data[:,-1]                                               # 获取当前样本集的目标变量,固定-1表示最后一列是标签
    base_entropy = entropy(labels)                                      # 获取当前样本集的信息熵

    best_info_gain = 0.0                                                # 设定初始信息增益为0
    best_column  = -1                                                   # 设定初始最优特征列为-1

    for index in range(data.shape[1]-1):                                # 获取当前样本集的每一列
        unique_values = np.unique(data[:,index])                        # 获取当前样本集的第index列的唯一值

        new_entropy = 0.0                                               # 当前index列的条件熵初始设为0
        sub_data = data[:,[index,-1]]                                   # 获取子数据集(仅包含两列):第index列,目标变量

        for value in unique_values:                                     # 遍历第index列的所有特征值
            label_i = sub_data[sub_data[:,0]==value,1]                  # 根据特定的特征值value划分出的样本子集,并只获取目标变量这一列
            new_entropy += len(label_i)/len(labels) * entropy(label_i)  # 计算index列的特征值value对应的节点的条件熵,并进行累加
        info_gain = base_entropy - new_entropy                          # index列的信息增益 = 当前样本集的信息熵-index列的条件熵


        if info_gain > best_info_gain:                                  # 获取信息增益最大对应的index列
            best_info_gain = info_gain
            best_column = index

    return best_column                                                  # 返回信息增益最大对应的index列

3.5 分支节点切割

def split_data(data,index_column,value_column):                         # 给定index列,以及其某个特征值value
    # 筛选满足条件的样本
    filtered_data = data[data[:, index_column] == value_column]         # 获取index列中所有特征值为value的样本
    return np.delete(filtered_data, index_column, axis=1)               # 剔除index列,并返回

3.6 递归构建决策树

def create_decision_tree(data,columns):    # data是numpy格式,包含目标变量
                                           # 目标变量索引。从0开始,且固定为最后一列
                                           # columns为列名称
    
    labels   = data[:,-1]
    # 如果数据集中的所有实例属于同一类别,则返回该类别
    if len(set(labels)) == 1:
        return labels[0]
    # 如果没有特征可用,返回实例集中最多的类别
    if data.shape[1] == 1:                 
        return majority_vote(labels)
    

    best_column_index = choose_best_feature(data)     
                                                      # 获取的是信息增益最大的特征列对应的索引

    bestcolumn=columns[best_column_index]             # 依据索引获取特征列名称
    decision_tree = {bestcolumn: {}}                  # 构建当前节点下的决策树
    del(columns[best_column_index] )                  # 列名称列表剔除已选取的最优特征
    
    uniqueVals=set(data[:,best_column_index])         # 获取已选取的最优特征的唯一值

    for value in uniqueVals:                          # 依据已选取的最优特征的唯一值,进行数据切割,并进行下一节点的树构建
        sub_columns = copy.deepcopy(columns)
        decision_tree[bestcolumn][value] = create_decision_tree(split_data(data, best_column_index, value), sub_columns)
    return decision_tree

3.7 美观输出决策树

def print_decision_tree(decision_tree, indent=''):
    # 遍历并输出决策树
    
    # 当前节点为叶节点时,直接输出结果
    if isinstance(decision_tree, str):
        print(indent + decision_tree)
        return

    # 当前节点为内部节点时,继续遍历子节点
    for key, value in decision_tree.items():
        print(indent + key + ":")
        if isinstance(value, dict):
            print_decision_tree(value, indent + '  ')
        else:
            print(indent + '  ' + value)

3.8 预测

def DecisionTree_predict(decision_tree, Columns, test_sample):
    root_feature = list(decision_tree.keys())[0]  # 获取根节点的特征
    root_dict = decision_tree[root_feature]  # 获取根节点的取值对应的子树
    
    root_feature_index = Columns.index(root_feature)  # 获取根节点特征在特征列表中的索引
    for value in root_dict:  # 遍历根节点取值对应的子树的所有可能取值
        if test_sample[root_feature_index] == value:  # 如果测试样本的特征值与当前取值相等
            if isinstance(root_dict[value], dict):  # 如果该取值对应的子树还是一个字典(非叶子节点)
                class_label = DecisionTree_predict(root_dict[value], Columns, test_sample)  # 递归向下查询子树
            else:  # 如果该取值对应的子树是一个标签(叶子节点)
                class_label = root_dict[value]  # 将该标签作为分类结果
            return class_label  # 返回分类结果

四、实例验证

4.1 获取数据集

def createDataSet():    # 创造示例数据
    dataSet=[['青绿','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],
             ['乌黑','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],
             ['乌黑','蜷缩','浊响','清晰','凹陷','硬滑','好瓜'],
             ['青绿','蜷缩','沉闷','清晰','凹陷','硬滑','好瓜'],                
             ['青绿','稍蜷','浊响','清晰','稍凹','软粘','好瓜'],               
             ['乌黑','稍蜷','浊响','稍糊','稍凹','软粘','好瓜'],                
             ['乌黑','稍蜷','浊响','清晰','稍凹','硬滑','好瓜'],
             ['乌黑','稍蜷','沉闷','稍糊','稍凹','硬滑','坏瓜'],
             ['青绿','硬挺','清脆','清晰','平坦','软粘','坏瓜'],
             ['浅白','蜷缩','浊响','模糊','平坦','软粘','坏瓜'],
             ['青绿','稍蜷','浊响','稍糊','凹陷','硬滑','坏瓜'],  
             ['浅白','稍蜷','沉闷','稍糊','凹陷','硬滑','坏瓜'],
             ['乌黑','稍蜷','浊响','清晰','稍凹','软粘','坏瓜'],
             ['青绿','蜷缩','沉闷','稍糊','稍凹','硬滑','坏瓜']]
    labels = ['色泽','根蒂','敲声','纹理','脐部','触感',"目标"]  #六个特征+1个特征列
    return dataSet,labels
data,Columns = createDataSet()
data = np.array(data)

4.2 调用算法

columns = copy.deepcopy(Columns)
decision_tree = create_decision_tree(data,columns)
print_decision_tree(decision_tree) # 输出决策树结果

4.3  进行预测

testSample=['浅白','硬挺','清脆','模糊','平坦','硬滑']  # 待测样本
DecisionTree_predict(decision_tree,Columns,testSample)

总结

依据ID3算法,进行复现。在复现中,尽可能所有运算只通过numpy实现,减少for循环的调用,做到减少运算量,加快运算结果。

### 关于 UniApp 框架的推荐资源与教程 #### 1. **Uniapp 官方文档** 官方文档是最权威的学习资料之一,涵盖了从基础概念到高级特性的全方位讲解。对于初学者来说,这是了解 UniApp 架构和技术细节的最佳起点[^3]。 #### 2. **《Uniapp 从入门到精通:案例分析与最佳实践》** 该文章提供了系统的知识体系,帮助开发者掌握 Uniapp 的基础知识、实际应用以及开发过程中的最佳实践方法。它不仅适合新手快速上手,也能够为有经验的开发者提供深入的技术指导[^1]。 #### 3. **ThorUI-uniapp 开源项目教程** 这是一个专注于 UI 组件库设计和实现的教学材料,基于 ThorUI 提供了一系列实用的功能模块。通过学习此开源项目的具体实现方式,可以更好地理解如何高效构建美观且一致的应用界面[^2]。 #### 4. **跨平台开发利器:UniApp 全面解析与实践指南** 这篇文章按照章节形式详细阐述了 UniApp 的各个方面,包括但不限于其工作原理、技术栈介绍、开发环境配置等内容,附带丰富的实例演示来辅助说明理论知识点。 以下是几个重要的主题摘选: - **核心特性解析**:解释了跨端运行机制、底层架构组成及其主要功能特点。 - **开发实践指南**:给出了具体的页面编写样例代码,展示了不同设备间 API 调用的方法论。 - **性能优化建议**:针对启动时间缩短、图形绘制效率提升等方面提出了可行策略。 ```javascript // 示例代码片段展示条件编译语法 export default { methods: { showPlatform() { console.log(process.env.UNI_PLATFORM); // 输出当前平台名称 #ifdef APP-PLUS console.log('Running on App'); #endif #ifdef H5 console.log('Running on Web'); #endif } } } ``` #### 5. **其他补充资源** 除了上述提到的内容外,还有许多在线课程视频可供选择,比如 Bilibili 上的一些免费系列讲座;另外 GitHub 和 GitCode 平台上也有不少优质的社区贡献作品值得借鉴研究。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值