决策树 >> 随机森林
决策树简单示例:天气预测是否打网球
输入数据样本
天气 | 温度 | 湿度 | 有风 | 打网球 |
---|---|---|---|---|
晴 | 热 | 高 | 否 | 否 |
晴 | 热 | 高 | 是 | 否 |
阴 | 热 | 高 | 否 | 是 |
雨 | 适中 | 高 | 否 | 是 |
雨 | 冷 | 正常 | 否 | 是 |
雨 | 冷 | 正常 | 是 | 否 |
阴 | 冷 | 正常 | 是 | 是 |
晴 | 适中 | 高 | 否 | 否 |
晴 | 冷 | 正常 | 否 | 是 |
决策树构建过程
步骤1:计算根节点基尼指数
- 总样本:9个
- 打网球(是):5个
- 不打网球(否):4个
- 基尼指数 = 1 - (5/9)² - (4/9)² ≈ 0.493
步骤2:计算各特征分裂效果
-
天气特征(晴/阴/雨):
- 晴:3个样本(2否,1是)→ 基尼=1-(1/3)²-(2/3)²≈0.444
- 阴:2个样本(2是)→ 基尼=0
- 雨:4个样本(2是,2否)→ 基尼=0.5
- 加权基尼 = (3/9)×0.444 + (2/9)×0 + (4/9)×0.5 ≈ 0.333
-
湿度特征(高/正常):
- 高:4个样本(1是,3否)→ 基尼=0.375
- 正常:5个样本(4是,1否)→ 基尼=0.32
- 加权基尼 ≈ 0.343
-
有风特征(是/否):
- 是:3个样本(1是,2否)→ 基尼≈0.444
- 否:6个样本(4是,2否)→ 基尼≈0.444
- 加权基尼 ≈ 0.444
-
温度特征(热/适中/冷):
- 热:3个样本(1是,2否)→ 基尼≈0.444
- 适中:2个样本(1是,1否)→ 基尼=0.5
- 冷:4个样本(3是,1否)→ 基尼=0.375
- 加权基尼 ≈ 0.417
选择天气特征(加权基尼0.333最小,基尼减少量最大:0.493-0.333=0.16)
步骤3:构建决策树(第一层分裂)
graph TD
A[天气?]
A -->|晴| B[继续分裂]
A -->|阴| C[是]
A -->|雨| D[继续分裂]
步骤4:晴天气分支分裂
- 样本:3个(1是,2否)
- 计算各特征:
- 湿度高:2个(全否)→ 基尼=0
- 湿度正常:1个(是)→ 基尼=0
- 加权基尼=0 → 选择湿度特征
graph TD
A[天气?]
A -->|晴| E[湿度?]
A -->|阴| C[是]
A -->|雨| D[继续分裂]E -->|高| F[否]
E -->|正常| G[是]
步骤5:雨天气分支分裂
- 样本:4个(2是,2否)
- 计算各特征:
- 有风是:2个(全否)→ 基尼=0
- 有风否:2个(全是)→ 基尼=0
- 加权基尼=0 → 选择有风特征
graph TD
A[天气?]
A -->|晴| E[湿度?]
A -->|阴| C[是]
A -->|雨| H[有风?]E -->|高| F[否]
E -->|正常| G[是]
H -->|是| I[否]
H -->|否| J[是]
最终决策树
graph TD
Start[天气?]
Start -->|晴| Humidity[湿度?]
Start -->|阴| Yes1[是]
Start -->|雨| Windy[有风?]Humidity -->|高| No1[否]
Humidity -->|正常| Yes2[是]
Windy -->|是| No2[否]
Windy -->|否| Yes3[是]
决策规则总结
- IF 天气=阴 THEN 打网球=是
- IF 天气=晴 AND 湿度=高 THEN 打网球=否
- IF 天气=晴 AND 湿度=正常 THEN 打网球=是
- IF 天气=雨 AND 有风=是 THEN 打网球=否
- IF 天气=雨 AND 有风=否 THEN 打网球=是
预测过程示例
输入1:天气=阴,温度=热,湿度=高,有风=是
- 天气=阴 → 直接输出 是
输入2:天气=晴,温度=冷,湿度=正常,有风=否
- 天气=晴 → 进入湿度分支
- 湿度=正常 → 输出 是
输入3:天气=雨,温度=适中,湿度=高,有风=是
- 天气=雨 → 进入有风分支
- 有风=是 → 输出 否
决策树特点在本例体现
- 可解释性:决策路径清晰可见
- 特征选择:自动忽略不相关特征(本例中温度未参与决策)
- 处理混合特征:同时处理类别型(天气)和布尔型(有风)特征
- 高效决策:多数情况只需1-2次判断
实际应用中,决策树会处理更复杂的场景:
- 连续特征(如温度25.6℃)
- 缺失值处理
- 更精细的剪枝策略
- 特征重要性评估(本例中天气最重要)
随机森林:原理、示例与输入输出详解
🌳 核心原理
随机森林(Random Forest)是一种集成学习算法,通过组合多棵决策树提升预测性能。其核心思想是"三个随机":
- 随机样本:每棵树使用有放回抽样(Bootstrap)的训练子集
- 随机特征:每棵树分裂时只考虑随机子集的特征(通常√n_features)
- 随机树:构建多棵弱相关的决策树(通常100-500棵)
预测机制:
- 分类问题:所有树投票决定最终类别
- 回归问题:所有树输出平均值作为结果
📊 简单示例:泰坦尼克号生存预测
输入数据(部分)
乘客ID | 舱位 | 性别 | 年龄 | 票价 | 是否幸存 |
---|---|---|---|---|---|
1 | 3 | 男 | 22 | 7.25 | 0 |
2 | 1 | 女 | 38 | 71.3 | 1 |
3 | 3 | 女 | 26 | 7.92 | 1 |
… | … | … | … | … | … |
随机森林构建过程
-
创建3棵决策树(实际通常100+棵)
-
每棵树使用不同数据子集和特征子集:
- 树1:样本[1,2,3,5,7] + 特征[“舱位”,“性别”]
- 树2:样本[2,3,4,6,8] + 特征[“性别”,“年龄”]
- 树3:样本[1,4,5,6,9] + 特征[“舱位”,“票价”]
-
单棵树决策示例:
graph TD A[性别?] -->|女| B[幸存率90%] A -->|男| C[舱位?] C -->|1等| D[幸存率60%] C -->|其他| E[幸存率20%]
预测新乘客
输入:舱位=2等, 性别=女, 年龄=28, 票价=45
每棵树预测:
- 树1:特征[“舱位”,“性别”] → 性别=女 → 幸存
- 树2:特征[“性别”,“年龄”] → 性别=女 → 幸存
- 树3:特征[“舱位”,“票价”] → 舱位=2等(幸存率65%)→ 幸存
输出:3棵树全票通过 → 预测幸存
💻 代码实现(Python)
from sklearn.ensemble import RandomForestClassifier
import pandas as pd# 1. 加载数据
titanic = pd.read_csv('titanic.csv')
X = titanic[['Pclass', 'Sex', 'Age', 'Fare']] # 特征
y = titanic['Survived'] # 标签# 2. 预处理
X['Sex'] = X['Sex'].map({'male':0, 'female':1}) # 性别编码
X = X.fillna(X.mean()) # 填充缺失值# 3. 创建随机森林
rf = RandomForestClassifier(n_estimators=100, # 100棵树max_features='sqrt', # 每次分裂考虑√4=2个特征random_state=42
)# 4. 训练模型
rf.fit(X, y)# 5. 预测新乘客
new_passenger = [[2, 1, 28, 45]] # 2等舱/女性/28岁/票价45
prediction = rf.predict(new_passenger)
print("幸存预测:", "是" if prediction[0]==1 else "否")# 6. 特征重要性分析
importance = pd.Series(rf.feature_importances_, index=X.columns)
print("特征重要性:")
print(importance.sort_values(ascending=False))
输出结果
幸存预测: 是特征重要性:
Sex 0.572
Fare 0.201
Pclass 0.128
Age 0.099
dtype: float64
📌 关键环节解析
1. 输入处理
- 数值特征:年龄/票价直接使用
- 类别特征:性别转换为0/1
- 缺失值:用平均值填充(年龄列)
2. 训练过程
- 自助采样:创建100个训练子集(每个≈63%原始数据)
- 特征随机:每棵树分裂时随机选2个特征(√4=2)
- 并行建树:独立构建100棵决策树
3. 预测过程
- 新样本输入每棵树
- 每棵树输出预测结果(0/1)
- 统计100棵树的预测:
- 70棵树预测幸存 → 70%
- 30棵树预测遇难 → 30%
- 多数投票 → 最终预测"幸存"
4. 特征重要性计算
重要性 = (特征被用于分裂的次数) × (平均基尼减少量)
- 性别:在85棵树中作为首要分裂特征 → 高重要性
- 年龄:仅在少数树中参与分裂 → 低重要性
🎯 实际应用场景
-
金融风控
- 输入:收入、负债、信用历史等
- 输出:贷款违约概率
-
医疗诊断
- 输入:检验指标、症状、病史
- 输出:疾病预测
-
推荐系统
- 输入:用户行为、商品特征
- 输出:点击率预测
-
图像识别
- 输入:像素特征(HOG/SIFT)
- 输出:物体分类
优势总结:
- 自动处理混合类型特征
- 抗过拟合能力强
- 输出特征重要性
- 并行化效率高
- 无需特征缩放
决策树 vs 随机森林:全面对比解析
核心概念对比
特性 | 决策树 | 随机森林 |
---|---|---|
基本定义 | 单一树状决策模型 | 多棵决策树的集成(森林) |
构建方式 | 递归划分数据集 | 1. 有放回采样创建多数据集 2. 每棵树用随机特征子集 |
决策机制 | 单一路径决策 | 多棵树投票(分类)/平均(回归) |
过拟合倾向 | 高(易受噪声影响) | 低(树间差异降低过拟合风险) |
预测稳定性 | 低(数据微小变化导致不同树) | 高(多树平均减少方差) |
工作原理图解
决策树工作流程
graph TDA[输入数据] --> B{特征X ≤ 阈值?}B -->|是| C{特征Y ≤ 阈值?}B -->|否| D[类别B]C -->|是| E[类别A]C -->|否| F[类别C]
随机森林工作流程
关键差异深度解析
1. 特征处理差异
-
决策树:
全量考虑所有特征,选择最佳分裂点
风险
:可能被主导特征垄断 -
随机森林:
每棵树随机选择特征子集(通常√n_features)
优势
:挖掘次要特征价值,增强泛化能力
2. 数据使用差异
决策树 | 随机森林 | |
---|---|---|
数据使用 | 100%原始数据 | 自助采样(约63%样本) |
未使用数据 | 无 | OOB(袋外)样本 |
验证方式 | 需要独立验证集 | 用OOB样本验证 |
3. 性能对比实验(鸢尾花数据集)
指标 | 决策树 | 随机森林 |
---|---|---|
准确率 | 93.3% | 96.7% |
训练时间(ms) | 2.1 | 15.8 |
预测时间(μs) | 38 | 210 |
特征重要性稳定性 | 低 | 高 |
注:随机森林牺牲速度换取精度和稳定性
实际应用场景对比
何时用决策树?
-
模型可解释性优先
(如银行拒绝贷款需明确原因)# 可视化单棵树 from sklearn.tree import plot_tree plot_tree(model)
-
低计算资源环境
(嵌入式设备/实时系统) -
原型快速验证
(初步探索特征关系)
何时用随机森林?
-
预测精度优先
(医疗诊断/股价预测) -
高维特征数据
(基因数据/推荐系统) -
自动特征选择
# 获取特征重要性 rf.feature_importances_
联合使用示例:糖尿病预测
数据特征
特征 | 类型 | 说明 |
---|---|---|
Pregnancies | 数值 | 怀孕次数 |
Glucose | 数值 | 血糖浓度 |
BloodPressure | 数值 | 血压 |
BMI | 数值 | 身体质量指数 |
Age | 数值 | 年龄 |
代码实现对比
# 决策树实现
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(max_depth=3)
dt.fit(X_train, y_train)
print("单棵树准确率:", dt.score(X_test, y_test))# 随机森林实现
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100, # 100棵树max_features='sqrt', # 每次分裂考虑√8≈3个特征oob_score=True # 启用OOB评估
)
rf.fit(X_train, y_train)
print("随机森林准确率:", rf.score(X_test, y_test))
print("OOB分数:", rf.oob_score_) # 无偏估计
性能对比输出
决策树准确率: 0.74
随机森林准确率: 0.79
OOB分数: 0.77
特征重要性对比
# 决策树特征重要性
dt_importance = dt.feature_importances_# 随机森林特征重要性
rf_importance = rf.feature_importances_# 可视化对比
plt.figure(figsize=(10,5))
plt.subplot(121)
plt.bar(features, dt_importance)
plt.title('决策树特征重要性')
plt.subplot(122)
plt.bar(features, rf_importance)
plt.title('随机森林特征重要性')
关键发现:
- 决策树过度依赖Glucose(血糖)特征
- 随机森林更均衡考虑BMI和Age特征
进阶应用技巧
1. 决策树作为随机森林基学习器
# 自定义决策树作为基学习器
from sklearn.tree import DecisionTreeClassifier
base_tree = DecisionTreeClassifier(min_samples_leaf=5, class_weight='balanced'
)rf = RandomForestClassifier(n_estimators=50,base_estimator=base_tree # 使用定制树
)
2. 混合解释性方法
# 使用随机森林预测 + 决策树解释
rf_pred = rf.predict(X_test)# 提取代表性样本
from sklearn.tree import export_text
representative_sample = X_test[10:11]# 显示单棵树的决策路径
tree_rules = export_text(rf.estimators_[0], feature_names=feature_names)
print(f"样本预测路径:\n{tree_rules}")
3. 决策树调优指导
# 用随机森林确定最优深度
depths = range(1, 15)
accuracies = []for d in depths:rf = RandomForestClassifier(max_depth=d)rf.fit(X_train, y_train)accuracies.append(rf.oob_score_)optimal_depth = depths[np.argmax(accuracies)] # 找到最佳深度
技术选型指南
场景 | 推荐模型 | 原因 |
---|---|---|
需要解释单条预测原因 | 决策树 | 白盒模型,决策路径清晰 |
高精度预测 | 随机森林 | 集成降低方差 |
数据包含大量噪声 | 随机森林 | 多树平均抵消噪声影响 |
实时系统(<10ms响应) | 决策树 | 单树预测速度快 |
特征重要性分析 | 随机森林 | 重要性评估更稳定 |
处理高维稀疏数据 | 随机森林 | 特征随机选择防止过拟合 |
最佳实践:先用决策树快速探索数据关系,再用随机森林构建最终模型,通过
rf.feature_importances_
指导特征工程,最终用单棵决策树解释关键预测。