本文来自「大千AI助手」技术实战系列,专注用真话讲技术,拒绝过度包装。
ID3(Iterative Dichotomiser 3) 是机器学习史上的里程碑算法,由Ross Quinlan于1986年提出。它首次将信息论引入决策树构建,奠定了现代决策树的理论基础。本文将深入剖析其数学本质与实现细节。
往期文章推荐:
- 20.用Mermaid代码画ER图:AI时代的数据建模利器
- 19.ER图:数据库设计的可视化语言 - 搞懂数据关系的基石
- 18.决策树:被低估的规则引擎,80%可解释性需求的首选方案
- 17.实战指南:用DataHub管理Hive元数据
- 16.一键规范代码:pre-commit自动化检查工具实战指南
- 15.如何数据的永久保存?将信息以加密电磁波形式发射至太空实现永久保存的可行性说明
- 14.NLP已死?大模型时代谁在悄悄重建「语言巴别塔」
- 13.撕掉时序图复杂度:Mermaid可视化极简实战指南
- 12.动手实践:LangChain流图可视化全解析
- 11.LangChain LCEL:三行代码构建AI工作流的秘密
- 10.LangChain执行引擎揭秘:RunnableConfig配置全解析
- 9.避坑指南:Windows下pygraphviz安装全攻略
- 8.Python3安装MySQL-python踩坑实录:从报错到完美解决的实战指南
- 7.Git可视化革命:3分钟学会用Mermaid+AI画专业分支图
- 6.vscode常用快捷命令和插件
- 5.AI制图新纪元:3分钟用Mermaid画出专业类图
- 4.3分钟搞定数据可视化:Mermaid饼图终极指南
- 3.5分钟玩转Swagger UI:Docker部署+静态化实战
- 2.记录下blog的成长过程
- 1.再说一说LangChain Runnable接口
一、核心思想:用信息增益量化特征价值
核心问题:如何选择最优划分特征?
ID3的答案:选择能使信息增益最大化的特征
信息熵(Entropy):混乱度的度量
定义系统 S S S中样本类别的混乱程度:
E n t r o p y ( S ) = − ∑ i = 1 c p i log 2 p i Entropy(S) = -\sum_{i=1}^{c} p_i \log_2 p_i Entropy(S)=−i=1∑cpilog2pi
- c c c:类别总数(如二分类时c=2)
- p i p_i pi:类别 i i i在 S S S中的比例
熵值解读:
- 熵=0:所有样本属于同一类(完全纯净)
- 熵=1(二分类时):两类样本各占50%(最混乱)
示例:硬币正反面概率均为0.5时, E n t r o p y = − ( 0.5 log 2 0.5 + 0.5 log 2 0.5 ) = 1 Entropy = - (0.5\log_20.5 + 0.5\log_20.5) = 1 Entropy=−(0.5log20.5+0.5log20.5)=1
信息增益(Information Gain)
定义特征 A A A对数据集 S S S的划分效果:
G a i n ( S , A ) = E n t r o p y ( S ) − ∑ v ∈ V a l u e s ( A ) ∣ S v ∣ ∣ S ∣ E n t r o p y ( S v ) Gain(S, A) = Entropy(S) - \sum_{v \in Values(A)} \frac{|S_v|}{|S|} Entropy(S_v) Gain(S,A)=Entropy(S)−v∈Values(A)∑∣S∣∣Sv∣Entropy(Sv)
- V a l u e s ( A ) Values(A) Values(A):特征 A A A的取值集合(如“天气”的特征值={晴,雨,阴})
- S v S_v Sv: A A A取值为 v v v的子集
决策规则:选择使 G a i n ( S , A ) Gain(S, A) Gain(S,A)最大的特征作为当前节点
二、算法运作机制:步步拆解
输入与输出
- 输入:离散型特征数据集(ID3不支持连续特征)
- 输出:一棵多叉决策树(每个分支对应特征的一个取值)
递归构建流程
def ID3(S, features):if 所有样本属于同一类别C:return 叶节点(类别C)if 特征集为空:return 叶节点(S中最多的类别)# 核心步骤:计算每个特征的信息增益best_feature = argmax_{A ∈ features} [Gain(S, A)]创建节点Node(标注best_feature)# 遍历最佳特征的每个取值for value in values(best_feature):Sv = S中best_feature=value的子集if Sv为空:添加叶节点(标注S中最多的类别)else:子节点 = ID3(Sv, features - {best_feature}) # 递归调用Node添加分支(value → 子节点)return Node
三、实例推演:天气预报数据集
天气 | 温度 | 湿度 | 风力 | 是否打球 |
---|---|---|---|---|
晴 | 高 | 高 | 弱 | 否 |
晴 | 高 | 高 | 强 | 否 |
阴 | 高 | 高 | 弱 | 是 |
雨 | 中 | 高 | 弱 | 是 |
雨 | 低 | 正常 | 弱 | 是 |
步骤1:计算根节点熵值
- 总样本数:5
- 打球(是):3,不打球(否):2
- E n t r o p y ( S ) = − ( 3 5 log 2 3 5 + 2 5 log 2 2 5 ) ≈ 0.971 Entropy(S) = -(\frac{3}{5}\log_2\frac{3}{5} + \frac{2}{5}\log_2\frac{2}{5}) ≈ 0.971 Entropy(S)=−(53log253+52log252)≈0.971
步骤2:计算各特征信息增益
以“天气”为例:
- 晴:2个样本 → 全部“否” → E n t r o p y ( S 晴 ) = 0 Entropy(S_{晴}) = 0 Entropy(S晴)=0
- 阴:1个样本 → 全部“是” → E n t r o p y ( S 阴 ) = 0 Entropy(S_{阴}) = 0 Entropy(S阴)=0
- 雨:2个样本 → 全部“是” → E n t r o p y ( S 雨 ) = 0 Entropy(S_{雨}) = 0 Entropy(S雨)=0
- G a i n ( S , 天气 ) = 0.971 − [ 2 5 × 0 + 1 5 × 0 + 2 5 × 0 ] = 0.971 Gain(S, 天气) = 0.971 - [\frac{2}{5}×0 + \frac{1}{5}×0 + \frac{2}{5}×0] = 0.971 Gain(S,天气)=0.971−[52×0+51×0+52×0]=0.971
同理计算其他特征:
- G a i n ( S , 温度 ) ≈ 0.571 Gain(S, 温度) ≈ 0.571 Gain(S,温度)≈0.571
- G a i n ( S , 湿度 ) ≈ 0.971 Gain(S, 湿度) ≈ 0.971 Gain(S,湿度)≈0.971
- G a i n ( S , 风力 ) ≈ 0.020 Gain(S, 风力) ≈ 0.020 Gain(S,风力)≈0.020
选择“天气”或“湿度”作为根节点(增益均为0.971)
四、ID3的局限性:算法缺陷深度分析
-
多值特征偏好问题
- 极端案例:若用“ID编号”作为特征
- 每个样本独占一个分支 → E n t r o p y ( S v ) = 0 Entropy(S_v)=0 Entropy(Sv)=0
- G a i n ( S , I D ) = E n t r o p y ( S ) Gain(S, ID)=Entropy(S) Gain(S,ID)=Entropy(S)(增益最大)
→ 导致毫无泛化能力的过拟合树
-
连续特征处理缺失
无法直接处理如“温度=25°C”的连续值,需先离散化 -
缺失值敏感
未定义特征缺失时的处理机制 -
剪枝功能缺失
原始ID3不提供防止过拟合的剪枝策略
重要结论:这些缺陷直接催生了改进算法C4.5(引入信息增益率和剪枝)
五、Python实现核心代码
import numpy as np
from collections import Counterdef entropy(y):"""计算信息熵"""hist = np.bincount(y)ps = hist / len(y)return -np.sum([p * np.log2(p) for p in ps if p > 0])def information_gain(X, y, feature_idx):"""计算指定特征的信息增益"""parent_entropy = entropy(y)# 按特征取值划分数据集unique_vals = np.unique(X[:, feature_idx])child_entropy = 0for val in unique_vals:mask = X[:, feature_idx] == valchild_y = y[mask]weight = len(child_y) / len(y)child_entropy += weight * entropy(child_y)return parent_entropy - child_entropyclass ID3Node:def __init__(self, feature=None, children=None, label=None):self.feature = feature # 划分特征索引self.children = children # 字典:{特征值: 子节点}self.label = label # 叶节点的类别标签def id3(X, y, features):# 终止条件1:所有样本同类别if len(np.unique(y)) == 1:return ID3Node(label=y[0])# 终止条件2:无可用特征if len(features) == 0:majority_label = Counter(y).most_common(1)[0][0]return ID3Node(label=majority_label)# 选择最佳划分特征gains = [information_gain(X, y, feat) for feat in features]best_idx = np.argmax(gains)best_feat = features[best_idx]# 创建新节点node = ID3Node(feature=best_feat, children={})# 递归构建子树remaining_feats = [f for f in features if f != best_feat]for val in np.unique(X[:, best_feat]):mask = X[:, best_feat] == valX_sub, y_sub = X[mask], y[mask]if len(X_sub) == 0: # 子集为空majority_label = Counter(y).most_common(1)[0][0]node.children[val] = ID3Node(label=majority_label)else:node.children[val] = id3(X_sub, y_sub, remaining_feats)return node
六、历史意义与现代应用
划时代贡献:
- 首次将信息论引入机器学习特征选择
- 奠定决策树递归分割的框架范式
- 启发后续C4.5/CART等里程碑算法
现代应用场景:
- 医学诊断系统(症状→疾病路径清晰可解释)
- 金融反欺诈规则提取(符合监管透明度要求)
- 工业故障树分析(物理意义明确的决策逻辑)
本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术!