无声的泄漏
泄漏是指测试行的信息在被评分之前就到达了模型。显眼的形式很容易避免(用明天的价格构造特征)。无声的形式藏在预处理里:你用所有行去挑选最佳列、做缩放或填补缺口,然后才为交叉验证划分。每个测试折都已经影响了这个选择,分数因此偏高。特征选择是最大的元凶,因为一百个噪声列在任何样本里总有几个看起来有预测力;如果在全部数据上挑选,测试折在一定程度上就被“恰好拟合这些折”的列预测了。结构性的解决办法是 Pipeline:把整个管道交给 cross_val_score,它会在每个训练窗口上重新拟合缩放、选择和模型,然后才对测试窗口打分。
本实验有意提出一个很难的问题:60 个其他资产的昨日收益能否预测 SPY 今天是否上涨?几乎没有什么可发现的。有泄漏的评估(在全部行上用 SelectKBest(f_classif, k=5),再做 TimeSeriesSplit 交叉验证)得到 AUC 0.534。诚实的评估(缩放器、选择器和逻辑回归放在一条管道里,每个窗口重新拟合)得到 0.512。二者之间的 0.022 纯属泄漏。你还可以看里面:cross_validate(model, X, y, cv=..., return_estimator=True) 返回已拟合的管道,estimator.named_steps['select'].get_support(indices=True) 列出每个折选中的列。五个折里只有一列每次都被选中,这就是对噪声做选择的样子。用管道算出的分数你能为之辩护;“对所有数据先做一点预处理”之后算出的分数则不能。
- 先划分,再学习:缩放、选择和填补都应放在交叉验证循环之内。
- Pipeline 是防泄漏的护栏:把整个管道交给
cross_val_score,每一步都会在每个训练窗口上重新拟合。 - 看看每个折选了什么:在折与折之间变化的列是噪声,而不是信号。
实验:评分内容
- 有泄漏的评估15 分
- 管道10 分
- 诚实的评估15 分
- 每个折的选择20 分
- 泄漏的大小10 分
- 真实数据的比较30 分