共计 1954 个字符,预计需要花费 5 分钟才能阅读完成。
决策树作为最直观的机器学习算法之一,因其模型可解释性强、接近人类决策过程的特点,成为分类问题中的入门首选工具。今天我们就用 Python 手把手实现经典改进版本——C4.5 算法。

为什么选择 C4.5 而不是 ID3?
C4.5 在 ID3 基础上做了两个关键改进:
- 用信息增益比替代信息增益,解决 ID3 对取值多属性的偏好问题
- 增加对连续特征的处理能力
信息增益比的计算分三步走:
- 先计算信息增益 $Gain(D,a)$
- 再计算属性 a 的固有值 $IV(a)$(类似熵的计算)
- 最后求比值 $Gain\_ratio(D,a) = \frac{Gain(D,a)}{IV(a)}$
Python 实现全流程
数据预处理关键步骤
处理连续值时,需要先排序然后寻找最佳分割点:
def choose_best_split(feature_values):
unique_vals = sorted(set(feature_values))
split_points = [(unique_vals[i]+unique_vals[i+1])/2
for i in range(len(unique_vals)-1)]
# 计算每个分割点的信息增益比
best_gain_ratio = 0
for point in split_points:
# 分割后计算信息增益比...
current_ratio = calc_gain_ratio(...)
if current_ratio > best_gain_ratio:
best_point = point
return best_point
递归建树核心逻辑
def create_tree(dataset, features):
# 终止条件 1:所有样本属于同一类别
if len(set(dataset[-1])) == 1:
return dataset[-1][0]
# 终止条件 2:没有可用特征
if not features:
return majority_vote(dataset[-1])
# 选择最佳划分特征
best_feature = select_best_feature(dataset)
tree = {best_feature: {}}
# 递归构建子树
for value in get_values(dataset, best_feature):
sub_dataset = split_dataset(dataset, best_feature, value)
tree[best_feature][value] = create_tree(sub_dataset,
features.remove(best_feature))
return tree
可视化决策树(使用 graphviz)
import graphviz
def visualize_tree(tree):
dot = graphviz.Digraph()
build_graph(dot, tree)
return dot
# 递归构建图节点
def build_graph(dot, tree, parent_node=None, edge_label=None):
if isinstance(tree, dict):
for node, branches in tree.items():
dot.node(str(id(node)), str(node))
if parent_node:
dot.edge(str(id(parent_node)), str(id(node)), label=edge_label)
for value, subtree in branches.items():
build_graph(dot, subtree, node, str(value))
else:
dot.node(str(id(tree)), str(tree), shape='box')
if parent_node:
dot.edge(str(id(parent_node)), str(id(tree)), label=edge_label)
避坑指南
过拟合与剪枝策略
- 预剪枝:在建树过程中通过验证集准确率决定是否继续分裂
- 后剪枝:先完全建树,再自底向上替换为叶节点观察准确率变化
缺失值处理三件套
- 计算信息增益比时忽略缺失样本
- 将缺失样本按不同分支权重分配
- 预测时如果遇到缺失特征,走概率最大的分支
类别不平衡解决方案
- 在计算信息量时采用加权熵
- 对少数类样本进行过采样
- 在验证时使用 F1-score 代替准确率
思考进阶方向
- 如果把分类改成回归,应该如何修改分裂标准?(提示:可以用方差替代熵)
- 对比随机森林中的决策树,单棵 C4.5 树有哪些优缺点?
- 当特征维度达到百万级时,哪些步骤会成为性能瓶颈?
完整代码已上传 GitHub 仓库(伪代码位置替换为实际链接),包含测试数据集和更详细的注释说明。建议在头歌平台创建项目时,可以先从较小的数据集开始验证核心算法,再逐步添加预处理和优化模块。
正文完
