Day 9 :随机森林调参与时间序列交叉验证
📋 目录
- 随机森林核心超参数详解
- 超参数对模型的影响
- 调参策略与顺序
- 时间序列交叉验证
- 网格搜索与随机搜索
- 学习曲线与验证曲线
- 过拟合诊断
第一部分:随机森林核心超参数详解(1.5小时理论)
1.1 超参数分类
| 类别 | 参数 | 作用 | 影响 |
|---|---|---|---|
| 模型复杂度 | n_estimators |
树的数量 | 越多越稳定 |
| 树结构 | max_depth |
最大深度 | 控制过拟合 |
| 分裂条件 | min_samples_split |
分裂最小样本数 | 正则化 |
| 叶节点 | min_samples_leaf |
叶节点最小样本数 | 平滑预测 |
| 特征选择 | max_features |
特征子集大小 | 增加多样性 |
| 采样 | bootstrap |
是否自助采样 | 通常为True |
1.2 n_estimators(树的数量)
定义:随机森林中决策树的数量。
原理:
- 每棵树独立训练,通过投票/平均得到最终结果
- 根据大数定律,树越多,方差越小
数学性质 :
Error=Bias2+Variance+Noise \text{Error} = \text{Bias}^2 + \text{Variance} + \text{Noise} Error=Bias2+Variance+Noise
增加 n_estimators 主要降低方差,不影响偏差。
参数影响:
| n_estimators | 训练时间 | 预测时间 | 内存 | 性能 |
|---|---|---|---|---|
| 太少(<50) | 快 | 快 | 小 | 不稳定 |
| 适中(100-200) | 中等 | 中等 | 中等 | 良好 |
| 太多(>500) | 慢 | 慢 | 大 | 边际收益递减 |
选择策略:
python
# 观察OOB误差随n_estimators的变化
oob_scores = []
for n in range(10, 301, 10):
rf = RandomForestClassifier(n_estimators=n, oob_score=True)
rf.fit(X_train, y_train)
oob_scores.append(rf.oob_score_)
# 选择OOB误差收敛时的n_estimators
1.3 max_depth(最大深度)
定义:每棵树的最大深度。
原理:
- 深度越大,树越复杂,越容易过拟合
- 限制深度是最直接的正则化方法
参数影响:
| max_depth | 模型复杂度 | 过拟合风险 | 训练时间 |
|---|---|---|---|
| 小(3-5) | 低 | 低 | 快 |
| 中(10-20) | 中 | 中 | 中等 |
| 大(None) | 高 | 高 | 慢 |
选择策略:
python
# 观察不同深度下的训练/测试误差
depths = range(3, 31, 3)
train_scores, test_scores = [], []
for depth in depths:
rf = RandomForestClassifier(max_depth=depth)
rf.fit(X_train, y_train)
train_scores.append(rf.score(X_train, y_train))
test_scores.append(rf.score(X_test, y_test))
# 选择测试误差最低的深度
1.4 min_samples_split(分裂最小样本数)
定义:内部节点再划分所需的最小样本数。
原理:
- 值越大,树越难分裂,模型越简单
- 防止模型学习局部噪声
参数影响:
| min_samples_split | 分裂次数 | 树大小 | 过拟合风险 |
|---|---|---|---|
| 小(2) | 多 | 大 | 高 |
| 中(5-20) | 中 | 中 | 中 |
| 大(>50) | 少 | 小 | 低 |
选择策略:
python
# 从小值开始,逐步增加
min_samples_split_values = [2, 5, 10, 20, 50, 100]
1.5 min_samples_leaf(叶节点最小样本数)
定义:叶节点所需的最小样本数。
原理:
- 与min_samples_split类似,但作用于叶节点
- 确保每个叶节点有足够样本,避免过拟合
与min_samples_split的区别:
| 参数 | 作用节点 | 对树的影响 |
|---|---|---|
| min_samples_split | 内部节点 | 限制分裂 |
| min_samples_leaf | 叶节点 | 限制叶节点大小 |
1.6 max_features(特征子集大小)
定义:每次分裂时随机选择的特征数量。
原理:
- 增加树的多样性
- 防止强特征主导所有树
常用设置:
| 任务 | 推荐值 | 说明 |
|---|---|---|
| 分类 | sqrt(n_features) |
默认值 |
| 回归 | n_features/3 |
默认值 |
| 特征少 | None |
使用所有特征 |
| 高维数据 | log2(n_features) |
增加随机性 |
第二部分:超参数对模型的影响
2.1 单个参数的影响分析
python
# 参数影响矩阵
#
# 欠拟合 ←──────────────→ 过拟合
#
# n_estimators: 小 ←→ 大
# max_depth: 小 ←→ 大
# min_samples_split: 大 ←→ 小
# min_samples_leaf: 大 ←→ 小
# max_features: 小 ←→ 大
2.2 参数交互作用
| 参数组合 | 效果 |
|---|---|
max_depth小 + min_samples_split大 |
强正则化,可能欠拟合 |
max_depth大 + min_samples_split小 |
弱正则化,可能过拟合 |
n_estimators大 + max_depth小 |
稳定且不易过拟合 |
2.3 偏差-方差权衡
text
高偏差(欠拟合) 最优 高方差(过拟合)
←─────────────────────────────────────────→
增加 max_depth ────────────────────────────────→
增加 n_estimators ────────────────────────────→
增加 min_samples_split ←───────────────────────
增加 min_samples_leaf ←───────────────────────
第三部分:调参策略与顺序
3.1 推荐调参顺序
text
第1步: 固定其他参数,确定 n_estimators
└── 观察OOB误差收敛点
第2步: 调整 max_depth
└── 找到最佳深度范围
第3步: 调整 min_samples_split 和 min_samples_leaf
└── 进一步正则化
第4步: 调整 max_features
└── 微调特征随机性
第5步: 联合调优
└── 使用网格搜索/随机搜索
3.2 粗调 vs 精调
| 阶段 | 参数范围 | 步长 | 目的 |
|---|---|---|---|
| 粗调 | 大范围 | 大 | 找到最优区域 |
| 精调 | 小范围 | 小 | 找到最优值 |
3.3 调参注意事项
- 避免数据泄露:只用训练集调参
- 使用交叉验证:评估泛化能力
- 记录实验:保存每次调参结果
- 关注边际收益:性能提升不明显时停止
第四部分:时间序列交叉验证
4.1 为什么不能用普通K折?
普通K折的问题:
- 随机打乱数据,破坏时间顺序
- 用未来数据训练,过去数据验证(前视偏差)
python
# 错误做法 ❌
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True) # 随机打乱
4.2 TimeSeriesSplit原理
工作方式:
text
Fold 1: Train [0:100] | Test [100:120]
Fold 2: Train [0:120] | Test [120:140]
Fold 3: Train [0:140] | Test [140:160]
Fold 4: Train [0:160] | Test [160:180]
Fold 5: Train [0:180] | Test [180:200]
特点:
- 训练集始终在测试集之前
- 测试集不重叠
- 训练集大小递增
python
# 正确做法 ✅
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
4.3 TimeSeriesSplit参数
| 参数 | 说明 | 默认值 |
|---|---|---|
n_splits |
分割次数 | 5 |
max_train_size |
最大训练集大小 | None |
test_size |
测试集大小 | None |
gap |
训练集和测试集之间的间隔 | 0 |
4.4 带间隔的TimeSeriesSplit
python
# 防止数据泄露,设置间隔
tscv = TimeSeriesSplit(n_splits=5, gap=5) # 训练集和测试集间隔5天
# 示意:
# Fold 1: Train [0:100] | Gap [100:105] | Test [105:125]
4.5 时间序列交叉验证的变体
| 变体 | 描述 | 适用场景 |
|---|---|---|
| 滚动窗口 | 固定窗口大小 | 非平稳数据 |
| 扩展窗口 | 窗口不断增大 | 数据量小 |
| 带间隔 | 防止短期依赖 | 高频数据 |
第五部分:网格搜索与随机搜索
5.1 GridSearchCV(网格搜索)
原理:遍历所有参数组合,找到最佳参数。
python
from sklearn.model_selection import GridSearchCV
param_grid = {
'max_depth': [10, 20, 30],
'min_samples_split': [2, 5, 10]
}
# 总共 3×3 = 9 种组合
grid_search = GridSearchCV(rf, param_grid, cv=5)
grid_search.fit(X_train, y_train)
优点 :保证找到最优组合
缺点:计算量大(组合爆炸)
5.2 RandomizedSearchCV(随机搜索)
原理:随机采样参数组合,而非遍历。
python
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint
param_dist = {
'max_depth': randint(10, 50),
'min_samples_split': randint(2, 20)
}
# 可以指定n_iter控制搜索次数
random_search = RandomizedSearchCV(rf, param_dist, n_iter=20, cv=5)
优点 :效率高,适合大参数空间
缺点:可能错过最优组合
5.3 搜索策略选择
| 场景 | 推荐方法 |
|---|---|
| 参数少(<10种组合) | GridSearchCV |
| 参数多(>50种组合) | RandomizedSearchCV |
| 参数连续分布 | RandomizedSearchCV |
| 追求最优 | GridSearchCV + 分步搜索 |
5.4 分步搜索策略
python
# 第1步:粗调,大范围
param_grid1 = {'max_depth': [5, 10, 20, 30, None]}
# 第2步:精调,小范围
param_grid2 = {'max_depth': [10, 12, 14, 16, 18, 20]}
# 第3步:联合调优
param_grid3 = {
'max_depth': [12, 14, 16],
'min_samples_split': [2, 4, 6, 8]
}
第六部分:学习曲线与验证曲线
6.1 学习曲线(Learning Curve)
定义:展示模型性能随训练集大小的变化。
作用:
- 判断欠拟合/过拟合
- 判断增加数据的收益
解读:
text
训练误差高,验证误差高 → 欠拟合
训练误差低,验证误差高 → 过拟合
两者都低且接近 → 良好拟合
6.2 验证曲线(Validation Curve)
定义:展示模型性能随单个参数的变化。
作用:
- 找到参数的最佳范围
- 观察参数对过拟合的影响
python
from sklearn.model_selection import validation_curve
train_scores, test_scores = validation_curve(
rf, X_train, y_train,
param_name='max_depth',
param_range=[3, 5, 10, 15, 20, 30],
cv=5
)
6.3 学习曲线 vs 验证曲线
| 曲线类型 | X轴 | 目的 |
|---|---|---|
| 学习曲线 | 训练集大小 | 判断数据需求 |
| 验证曲线 | 参数值 | 判断参数影响 |
第七部分:过拟合诊断
7.1 诊断方法
| 方法 | 指标 | 过拟合信号 |
|---|---|---|
| 训练vs测试误差 | 准确率差 | 训练>>测试 |
| OOB评分 | OOB vs 测试 | OOB低于测试 |
| 学习曲线 | 误差差距 | 差距随数据增大 |
| 验证曲线 | 参数影响 | 复杂度过高 |
7.2 过拟合应对策略
- 增加正则化 :
- 减小max_depth
- 增大min_samples_split
- 增大min_samples_leaf
- 增加数据 :
- 收集更多历史数据
- 数据增强
- 减少特征 :
- 特征选择
- 降维(PCA)
- 降低模型复杂度 :
- 减少n_estimators(边际效应)
- 减小max_features