C4.5决策树算法手算实战:从原理到分步计算详解

1次阅读
没有评论

共计 2480 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

为什么需要信息增益率?

决策树算法中,ID3 使用信息增益作为特征选择标准,但存在偏向取值多的特征的问题。比如有一个特征是 ”ID”,每个样本的 ID 都不同,按信息增益会选择这个特征,但这显然没有意义。

C4.5 决策树算法手算实战:从原理到分步计算详解

C4.5 引入了信息增益率来解决这个问题:

$$ GainRatio(D,A) = \frac{Gain(D,A)}{SplitInfo(D,A)} $$

其中 SplitInfo 是分裂信息,表示特征 A 将数据集 D 划分成多少份的信息量。这样即使一个特征取值很多,如果 SplitInfo 也很大,最终信息增益率也不会很高。

手算示例:天气预测数据集

我们使用经典的天气预测数据集,包含 4 个特征和 1 个目标变量(是否出去玩):

天气 温度 湿度 有风 出去玩
多云
正常
正常
多云 正常
正常
正常
正常
多云
多云 正常

第一步:计算信息增益率

  1. 计算初始信息熵:

$$ Ent(D) = -\frac{5}{14}\log_2\frac{5}{14} – \frac{9}{14}\log_2\frac{9}{14} ≈ 0.940 $$

  1. 以 ” 天气 ” 为例计算信息增益:

  2. 晴:5 个样本 (2 是,3 否)

  3. 多云:4 个样本 (4 是,0 否)
  4. 雨:5 个样本 (3 是,2 否)

$$ Ent(晴) = -\frac{2}{5}\log_2\frac{2}{5} – \frac{3}{5}\log_2\frac{3}{5} ≈ 0.971 $$

$$ Ent(多云) = 0 $$

$$ Ent(雨) ≈ 0.971 $$

$$ Gain(D, 天气) = 0.940 – (\frac{5}{14}×0.971 + \frac{4}{14}×0 + \frac{5}{14}×0.971) ≈ 0.246 $$

  1. 计算分裂信息:

$$ SplitInfo(D, 天气) = -\frac{5}{14}\log_2\frac{5}{14} – \frac{4}{14}\log_2\frac{4}{14} – \frac{5}{14}\log_2\frac{5}{14} ≈ 1.577 $$

  1. 信息增益率:

$$ GainRatio(D, 天气) ≈ \frac{0.246}{1.577} ≈ 0.156 $$

第二步:处理连续特征

对于 ” 温度 ” 这样的连续特征,C4.5 的做法是:

  1. 将温度值排序:[低, 低, 低, 中, 中, 中, 中, 高, 高, 高, 高, 高]
  2. 计算相邻值的中间点作为候选分割点
  3. 对每个分割点计算信息增益率
  4. 选择信息增益率最大的分割点

经计算,温度的最佳分割点是 ” 中 ”,将温度分为≤中和 > 中两组。

第三步:递归构建决策树

选择信息增益率最大的特征作为当前节点的分裂特征,然后对每个子节点递归执行上述过程,直到:

  • 所有样本属于同一类别
  • 没有剩余特征可供划分
  • 节点样本数小于预定阈值

Python 代码验证

from sklearn.tree import DecisionTreeClassifier
import pandas as pd

# 准备数据
data = {
    'Outlook': ['Sunny','Sunny','Overcast','Rainy','Rainy','Rainy','Overcast','Sunny',
               'Sunny','Rainy','Sunny','Overcast','Overcast','Rainy'],
    'Temp': ['High','High','High','Medium','Low','Low','Low','Medium',
            'Low','Medium','Medium','Medium','High','Medium'],
    'Humidity': ['High','High','High','High','Normal','Normal','Normal','High',
                'Normal','Normal','Normal','High','Normal','High'],
    'Windy': [False,True,False,False,False,True,True,False,
             False,False,True,True,False,True],
    'Play': ['No','No','Yes','Yes','Yes','No','Yes','No',
            'Yes','Yes','Yes','Yes','Yes','No']
}

df = pd.DataFrame(data)

# 特征编码
df = pd.get_dummies(df, columns=['Outlook','Temp','Humidity','Windy'])

# 训练模型
clf = DecisionTreeClassifier(criterion='entropy', max_depth=3)
clf.fit(df.drop('Play',axis=1), df['Play'])

# 可视化决策树
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
plt.figure(figsize=(12,8))
plot_tree(clf, feature_names=df.drop('Play',axis=1).columns, 
          class_names=['No','Yes'], filled=True)
plt.show()

避坑指南

  1. 连续值分割点选择
  2. 不要简单地取所有可能的中值,应该先对特征值排序
  3. 分割点应该位于不同类别样本的交接处

  4. 信息增益率分母为零

  5. 当某个特征对所有样本取值相同时,SplitInfo 为 0
  6. 解决方法是可以直接忽略这种特征

  7. 预防过拟合

  8. 设置最小叶子节点样本数
  9. 限制树的最大深度
  10. 使用剪枝技术

思考题

  1. 比较 ID3、C4.5 和 CART 三种决策树算法在特征选择标准上的差异?
  2. 如果用基尼系数代替信息增益率,当前示例的决策树会有什么变化?

总结

通过这个完整的手算示例,我们详细了解了 C4.5 决策树算法的核心计算过程。关键是要理解信息增益率如何解决 ID3 算法的偏差问题,以及如何处理连续特征。实际应用中,我们通常直接调用现成的库实现,但掌握这些底层计算原理对于调试模型和理解结果非常重要。

正文完
 0
评论(没有评论)