机器学习 决策树
一、决策树模型
决策树是一种基于树形结构的监督学习算法,通过一系列规则(if-then条件)对数据进行分类或回归。其结构包含:
根节点:包含完整数据集的最顶层节点
内部节点:表示特征测试的分支决策点
叶节点:最终的分类/回归结果
2. 核心算法原理
(1) 特征选择准则
ID3算法(分类树):
使用 信息增益(Information Gain)选择特征
信息增益=H(D)−H(D∣A)信息增益=H(D)−H(D∣A)
其中 H(D)H(D) 是数据集的经验熵
C4.5算法:
改进ID3,采用 增益率(Gain Ratio)避免偏向多值特征
增益率=信息增益特征固有值增益率=特征固有值信息增益
CART算法(分类与回归):
分类:使用 基尼系数(Gini Index)
Gini=1−∑k=1Kpk2Gini=1−∑k=1Kpk2
回归:最小化 均方误差(MSE)
(2) 剪枝策略
预剪枝:在树生长过程中提前停止(如限制深度、设置最小样本数)
后剪枝:先生成完整树,再自底向上剪枝(如代价复杂度剪枝)
二、决策树特点:
特点 说明
可解释性 树结构直观,适合业务解释(优于黑盒模型如神经网络)
数据要求 可处理数值型和类别型特征,对缺失值敏感(需预处理)
计算复杂度 训练时间复杂度:O(n×m×logn)O(n×m×logn)(n样本数,m特征数)
过拟合风险 容易生成过深树,需通过剪枝/随机森林等方法控制
三、实际应用场景
分类问题
银行:信用评分模型
医疗:疾病诊断(如乳腺癌良恶性判断)
回归问题
房价预测
销售额预估
特征重要性分析
通过计算特征在树中的分裂次数或信息增益量,评估特征贡献度
四、优缺点:
优点 缺点
无需特征缩放 对噪声数据敏感
可处理非线性关系 容易过拟合(需剪枝)
支持多输出任务 不稳定(数据微小变化可能导致树结构剧变)
五、实际实现:

通过一系列条件判断是否给予贷款。
通过特征映射建立数字与业务含义的对应关系(如0=青年, 1=中年, 2=老年)
规则提炼:
批准贷款的典型路径:
有自己的房子=是 → 直接批准
有自己的房子=否 + 有工作=是 → 批准
拒绝贷款的典型路径:
有自己的房子=否 + 有工作=否
代码实现:import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
from sklearn.metrics import classification_report, confusion_matrix
import matplotlib.pyplot as plt
# 设置中文字体显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 特征映射字典
feature_mapping = {
'年龄段': {0: '青年', 1: '中年', 2: '老年'},
'有工作': {0: '否', 1: '是'},
'有自己的房子': {0: '否', 1: '是'},
'信贷情况': {0: '一般', 1: '好', 2: '非常好'},
'类别': {0: '拒绝贷款', 1: '批准贷款'}
}
# 加载数据函数
def load_data(file_path):
"""从txt文件加载数据,最后一列为标签"""
data = np.loadtxt(file_path, delimiter=',')
X = data[:, :-1] # 特征
y = data[:, -1] # 标签
return X, y
# 文件路径(根据实际位置修改)
dataset_path = r"C:dataset.txt"
testset_path = r"C:testset.txt"
# 加载数据
try:
X_train, y_train = load_data(dataset_path)
X_test, y_test = load_data(testset_path)
except FileNotFoundError as e:
print(f"文件加载失败,请检查路径: {e}")
exit()
# 特征名称(按数据列顺序)
feature_names = ['年龄段', '有工作', '有自己的房子', '信贷情况']
class_names = list(feature_mapping['类别'].values())
# 创建决策树模型(基于基尼系数)
clf = DecisionTreeClassifier(
criterion='gini', # 分裂标准
max_depth=3, # 最大深度
min_samples_split=2, # 节点分裂最小样本数
random_state=42 # 随机种子
)
# 训练模型
clf.fit(X_train, y_train)
# 可视化决策树
plt.figure(figsize=(16, 10))
plot_tree(clf,
feature_names=feature_names,
class_names=class_names,
filled=True, # 填充颜色
rounded=True, # 圆角边框
impurity=True, # 显示不纯度
proportion=True) # 显示样本比例
plt.title("贷款审批决策树(基于基尼系数)")
plt.show()
# 输出文本形式的决策规则
tree_rules = export_text(clf, feature_names=feature_names)
print("决策树规则:\n" + tree_rules)
# 在测试集上评估
y_pred = clf.predict(X_test)
print("\n测试集性能评估:")
print(classification_report(y_test, y_pred, target_names=class_names))
print("\n混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
# 测试样本详细分析
def explain_prediction(sample_idx):
"""解释单个样本的预测过程"""
sample = X_test[sample_idx]
print(f"\n测试样本 {sample_idx} 详细分析:")
print("特征值:")
for i, name in enumerate(feature_names):
print(f" {name}: {feature_mapping[name][int(sample[i])]}")
print(f"\n实际类别: {feature_mapping['类别'][int(y_test[sample_idx])]}")
print(f"预测类别: {feature_mapping['类别'][int(y_pred[sample_idx])]}")
print("类别概率:", clf.predict_proba([sample])[0])
# 决策路径
print("\n决策路径:")
feature = clf.tree_.feature
threshold = clf.tree_.threshold
node_indicator = clf.decision_path([sample])
leaf_id = clf.apply([sample])[0]
path = []
for node_id in node_indicator.indices[node_indicator.indptr[0]:
node_indicator.indptr[1]]:
if leaf_id == node_id:
continue
if sample[feature[node_id]] <= threshold[node_id]:
threshold_sign = "<="
else:
threshold_sign = ">"
path.append(
f"{feature_names[feature[node_id]]} {threshold_sign} {threshold[node_id]:.2f}"
)
print(" -> ".join(path))
# 分析测试集第一个样本
explain_prediction(0)
# 特征重要性分析
print("\n特征重要性:")
importance = pd.DataFrame({
'特征': feature_names,
'重要性': clf.feature_importances_
}).sort_values('重要性', ascending=False)
print(importance)
运行截图:

性能报告:
precision recall f1-score support
拒绝贷款 1.00 1.00 1.00 3
批准贷款 1.00 1.00 1.00 4
特征重要性:
特征 重要性
2 有自己的房子 0.60
1 有工作 0.40
0 年龄段 0.00
3 信贷情况 0.00
更多推荐
所有评论(0)