8.2 切分、交叉验证与不确定性:验证结构必须模拟部署结构
模型工坊把同一台设备的日志随机分进五折,得到几乎完美的结果。情报官换成新设备测试,性能骤降。问题不是折数太少,而是训练折已经见过每台验证设备的“指纹”。
交叉验证只有在切分单位与部署边界一致时才有意义。随机 K 折、分层 K 折、GroupKFold 和时间回放估计的是不同泛化任务。
本课目标
- 从部署总体选择 random、group 或 temporal split;
- 把所有 learned preprocessing 放入 fold 内;
- 区分模型选择、性能估计与最终 test;
- 正确理解 CV 均值、折间标准差和置信区间;
- 使用 nested CV 与 paired comparison 控制选择偏差。
1. 切分是在定义“新数据”
几个常见部署问题:
| 部署问题 | 验证中应隔离什么 |
|---|---|
| 同分布新独立样本 | 随机行(iid 假设近似成立) |
| 新用户/新设备/新医院 | 整个 group |
| 已有用户的未来行为 | 时间,可能允许历史用户出现 |
| 新用户的未来行为 | group 与 time 都要隔离 |
| 新地区/新站点 | location/domain |
先写部署问题,再选 splitter。不能因为 cv=5 方便,就反过来声称模型能泛化到新设备。
2. Train、Validation、Test 职责不同
- train:拟合模型参数与 fold 内前处理;
- validation/inner CV:选择特征、模型、超参数、校准与阈值;
- test/outer fold:评估已冻结的整个选择流程。
只要看过 test 结果后改变任何选择,test 就参与了开发。一次性 test 的价值来自流程约束,不来自文件名。
对持续迭代产品,可按时间维护滚动 backtest 与最终 shadow/champion–challenger 评估;不要长期反复“保留”一份已被全团队记住结果的 test。
3. Stratification 是工程措施,不恢复 iid
StratifiedKFold 尽量保持每折类别比例,能避免稀有类在某折完全消失并降低某些指标波动。但它不会解决:
- 同用户跨折泄漏;
- 时间穿越;
- 空间/机构相关性;
- 重复样本;
- 标签窗口重叠。
有 group 且希望近似保持类别比例,可考虑 StratifiedGroupKFold,但 group 不重叠优先于完美比例;组数、大小和类分布可能使理想分层根本不可行。
4. Group split 的统计单位是 Group
同一病人多次就诊、同一设备多条日志、同一文档多个片段通常相关。若目标是新 group 泛化,所有同 group 行必须在同一折。
评估与区间估计也应尊重 group:一万个日志来自十台设备,并不等于一万个独立样本。可同时报告:
- micro/row-weighted 指标;
- macro/group-equal 指标;
- group 分布与最差/低分位表现;
- leave-one-site/group-out sensitivity。
选择哪种加权取决于部署总体:未来流量按行发生,还是每家机构等权。
5. 时间切分要处理标签成熟与 Gap
时间模型不能用未来训练过去。还要考虑 feature window 与 label horizon:
feature window ---- cutoff ---- label horizon
train labels mature | gap | validation features/labels若预测“未来 30 天故障”,训练末尾样本的标签要等 30 天才成熟。Train 与 validation 间可能需要 embargo/gap,防止重叠窗口或延迟标签穿越。
TimeSeriesSplit 提供 expanding-window 和 gap 等机制,但默认假定行已按时间排序,且其等间隔说明关系到折间指标可比性。真实系统还可能需要 rolling window、固定测试时长、季节覆盖和 group-time 双重约束。
6. 所有 Learned Transform 都在 Fold 内 Fit
泄漏不只来自 target encoding。以下步骤只要从数据估计参数,就属于训练过程:
- 缺失填补、缩放、winsorization;
- vocabulary、one-hot category set;
- PCA、feature selection;
- target/frequency encoding;
- resampling/SMOTE;
- calibration 和 threshold tuning;
- anomaly/cluster representation。
使用 Pipeline/ColumnTransformer 把它们放入 CV。即使 transform 不看 y,在全数据拟合也会让 validation distribution 影响 representation。
7. 一个 Group-aware 多指标评估骨架
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedGroupKFold, cross_validate
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
candidate = Pipeline([
("impute", SimpleImputer(strategy="median")),
("scale", StandardScaler()),
("model", LogisticRegression(max_iter=2_000)),
])
cv = StratifiedGroupKFold(
n_splits=5,
shuffle=True,
random_state=42,
)
result = cross_validate(
candidate,
X,
y,
groups=device_id,
cv=cv,
scoring={
"roc_auc": "roc_auc",
"average_precision": "average_precision",
"neg_log_loss": "neg_log_loss",
},
return_train_score=True,
return_estimator=True,
n_jobs=-1,
)当前 sklearn 是否启用 metadata routing 会影响 groups 的传法;项目应固定版本并按官方 API 调整。更重要的是先验证每折 group 交集为空,而不是只相信 splitter 名称。
8. 折间标准差不是置信区间
K 个 CV 分数不是 K 个独立同分布实验:训练集高度重叠,验证集也来自同一有限数据。mean ± std 描述这组 split 的离散程度,不能直接当总体性能的 95% confidence interval。
不确定性来源至少包括:
- 有限测试样本;
- 数据切分;
- 模型初始化/随机训练;
- 超参数搜索选择;
- 标签误差与延迟;
- 未来分布漂移。
报告一个小数点后三位的均值,不会消除这些来源。
9. Bootstrap 必须重采正确单位
对冻结模型的独立 test,可 bootstrap test units 估计 metric sampling uncertainty。若同一用户有多行,应 cluster bootstrap 用户,而不是独立抽行;时间序列可用 block bootstrap,但 block 长度本身是建模选择。
Rare event 指标可能出现 bootstrap sample 没有正例、分布高度偏斜。应报告有效 replicate、interval 方法、抽样单位,并检查 percentile/BCa 等方法的适用性。
Bootstrap interval 只覆盖指定抽样机制下的有限样本不确定性,不覆盖未来 drift、隐藏泄漏和不断试模型造成的选择偏差。
10. 比较模型要使用 Paired Evidence
两个模型在同一 test 样本上的误差相关。比较差值:
$$ \Delta=M_A-M_B, $$
并对同一行/group 的 paired predictions 重采样,通常比给两个独立区间更有力。分类准确率可考虑 McNemar,AUC 有专门方法,通用指标可 paired bootstrap/permutation,但都要满足相应独立单位假设。
统计显著不等于业务重要。预先定义最小有意义差异、非劣界或成本门槛;同时检查运行时间、校准与群体影响。
11. Nested CV 评估的是“选择流程”
普通 GridSearchCV 在开发集内部做 CV,再在一份未触碰 test 上评估,是 holdout test 设计,不叫 nested CV。
Nested CV 有两层循环:
- outer split 留出本轮评估数据;
- 只在 outer-train 内运行 inner search;
- 用选出的流程预测 outer-test;
- 聚合所有 outer-test 结果。
它估计“若在类似训练数据上重新调参,这套选择流程表现怎样”。样本少且调参很多时很有价值,但计算昂贵,outer folds 也不是完全独立实验。
12. Learning Curve 回答数据还是模型受限
在多个训练规模上重复完整 fit,并用固定验证协议比较 train/validation loss:
- 两者都差且接近:可能 representation/容量不足或目标噪声大;
- train 好、validation 差:可能 variance/泄漏后修正/分布差异;
- validation 随数据持续改善:更多同分布数据可能有价值;
- 曲线平台:继续收集同类数据的边际收益可能小。
每个规模都要保持 group/time 结构,且 transform 重新 fit。不能从单次随机子样本画平滑线后过度解释。
常见误区
- K=5/10 天然可靠:折数由独立单位、类数、成本和估计目标决定。
- StratifiedKFold 解决类别不平衡的一切:它只控制折内比例。
- CV 标准差就是误差条:折相关,不能直接当置信区间。
- 无监督前处理可在全数据拟合:进入 pipeline 后同样泄漏。
- GridSearchCV 自带 nested CV:只有显式 outer loop 才是 nested。
练习
- 为“新设备”和“已有设备未来故障”分别画切分边界。
- 检查每折 train/validation group 交集和时间顺序。
- 比较全数据缩放与 fold 内缩放造成的估计差异。
- 对同一 test predictions 做 row bootstrap 与 group bootstrap。
- 实现 outer group CV + inner search,比较 non-nested 结果。
小结
验证方法不是折数模板,而是部署条件的模拟器。独立单位、时间、标签窗口和前处理共同决定切分;CV 均值与标准差只是有限证据。Nested CV、paired comparison 和正确单位的 bootstrap 能回答更严格的问题,但不能替代对未来漂移的监控。
下一课把这套验证结构放进模型选择:搜索空间、预算、early stopping、校准和阈值都要在 inner loop 内完成。