别再死记公式了!用Python手写信息增益,5分钟搞懂决策树怎么选特征
·
用Python实战信息增益:5步拆解决策树特征选择逻辑
决策树算法中,特征选择直接决定了模型的性能上限。很多初学者虽然能背诵信息增益的公式,却在面对真实数据集时不知如何将其转化为代码逻辑。本文将用Python从零实现信息增益计算,结合鸢尾花数据集演示决策树如何量化特征重要性。
1. 信息熵:不确定性测量的黄金标准
信息熵是理解信息增益的基石。想象你正在玩一个猜数字游戏:如果数字范围是1-1000,每次猜测只能得到"大了"或"小了"的反馈,那么最有效的策略就是二分查找。信息熵正是量化这种不确定性的数学工具。
在分类问题中,熵的计算公式为:
import numpy as np
def entropy(labels):
_, counts = np.unique(labels, return_counts=True)
probabilities = counts / len(labels)
return -np.sum(probabilities * np.log2(probabilities))
这个简单函数揭示了几个关键点:
- 当所有样本属于同一类别时(纯节点),熵为0
- 当类别均匀分布时,熵达到最大值
- 使用对数底数2是为了让单位变为比特
用鸢尾花数据集做个实验:
from sklearn.datasets import load_iris
iris = load_iris()
print(f"整体熵值: {entropy(iris.target):.4f}") # 输出:1.5850
2. 信息增益:特征选择的量化指标
信息增益衡量的是使用某个特征进行划分后,系统不确定性的减少程度。其核心计算公式为:
信息增益 = 父节点熵 - 加权子节点熵和
让我们实现一个完整的特征评估函数:
def information_gain(feature, labels):
parent_entropy = entropy(labels)
# 计算每个特征值的权重和子熵
unique_values = np.unique(feature)
weighted_entropy = 0
for value in unique_values:
mask = feature == value
subset_labels = labels[mask]
weight = len(subset_labels) / len(labels)
weighted_entropy += weight * entropy(subset_labels)
return parent_entropy - weighted_entropy
在鸢尾花数据集上测试花瓣宽度特征:
petal_width = iris.data[:, 3]
print(f"花瓣宽度信息增益: {information_gain(petal_width, iris.target):.4f}")
3. 决策树中的特征选择实战
实际决策树算法会评估所有特征的信息增益。我们模拟这个过程:
def best_feature(X, y):
gains = [information_gain(X[:, i], y) for i in range(X.shape[1])]
return np.argmax(gains), gains
best_idx, all_gains = best_feature(iris.data, iris.target)
print(f"最佳特征索引: {best_idx}") # 输出:2(花瓣长度)
print("各特征增益值:", [f"{g:.4f}" for g in all_gains])
典型输出结果:
最佳特征索引: 2
各特征增益值: ['0.3333', '0.3333', '1.5850', '1.4183']
这个结果说明:
- 花瓣长度(索引2)的信息增益最高
- 前两个特征(萼片尺寸)增益较低
- 最后一个花瓣宽度也有不错的表现
4. 信息增益的局限与改进
虽然信息增益很直观,但它存在偏向选择取值较多的特征的问题。解决方案包括:
增益率 :
def intrinsic_value(feature):
_, counts = np.unique(feature, return_counts=True)
probabilities = counts / len(feature)
return -np.sum(probabilities * np.log2(probabilities))
def gain_ratio(feature, labels):
ig = information_gain(feature, labels)
iv = intrinsic_value(feature)
return ig / iv if iv != 0 else 0
基尼系数 (CART树使用):
def gini(labels):
_, counts = np.unique(labels, return_counts=True)
probabilities = counts / len(labels)
return 1 - np.sum(probabilities ** 2)
三种指标对比:
| 指标 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 信息增益 | 直观易懂 | 偏向多值特征 | ID3算法 |
| 增益率 | 平衡多值特征 | 计算复杂 | C4.5算法 |
| 基尼系数 | 计算高效 | 对类别不敏感 | CART算法 |
5. 从理论到工程:生产环境中的优化
实际项目中,我们还需要考虑:
连续特征处理 :
def find_best_split(continuous_feature, labels):
unique_values = np.unique(continuous_feature)
thresholds = (unique_values[:-1] + unique_values[1:]) / 2
best_gain = -1
best_threshold = None
for thresh in thresholds:
discrete_feature = continuous_feature >= thresh
current_gain = information_gain(discrete_feature, labels)
if current_gain > best_gain:
best_gain = current_gain
best_threshold = thresh
return best_threshold, best_gain
缺失值处理策略 :
- 直接忽略含缺失值的样本
- 将缺失值作为特殊类别处理
- 根据已知值分布进行随机填充
在scikit-learn中的实现对比:
from sklearn.tree import DecisionTreeClassifier
# 使用信息增益等价的标准
clf_entropy = DecisionTreeClassifier(criterion='entropy')
clf_entropy.fit(iris.data, iris.target)
# 使用基尼系数
clf_gini = DecisionTreeClassifier(criterion='gini')
clf_gini.fit(iris.data, iris.target)
实际项目中,特征选择只是决策树构建的第一步。后续还需要考虑剪枝策略、多棵树集成等技术来提升模型性能。理解信息增益的计算本质,能帮助开发者更好地调试模型和解释结果。
更多推荐

所有评论(0)