静かな漏洩
リークとは、テスト行の情報が評価される前にモデルへ届くことです。分かりやすい形(明日の価格から作った特徴量)は避けやすいのですが、静かな形は前処理に潜みます。最良の列を選ぶ、スケーリングする、欠損を埋めるといった操作を全行で行い、そのあとで交差検証のために分割する場合です。どのテスト分割もすでに選択に影響しており、スコアは甘くなります。特徴量選択は最悪の犯人です。ノイズ列が100本あれば、どんな標本でも予測力があるように見える列が数本は必ずあります。それを全データで選ぶと、テスト分割はまさにその分割に合ったから選ばれた列によって部分的に「予測」されることになります。構造的な解決は Pipeline です。cross_val_score にパイプライン全体を渡せば、各学習期間でスケーリング・選択・モデルを学び直し、そのあとでテスト期間を採点します。
このラボは意図的に難しい問いを使います。他の60資産の前日リターンで、今日SPYが上がるかを予測できるか。見つかるものはほとんどありません。リークのある評価(全行で SelectKBest(f_classif, k=5)、その後 TimeSeriesSplit で交差検証)のAUCは 0.534、正直な評価(スケーラー・選択器・ロジスティック回帰を1つのパイプラインに入れ、各期間で学び直す)は 0.512 です。間の 0.022 は純粋なリークです。中身も見られます。cross_validate(model, X, y, cv=..., return_estimator=True) は学習済みパイプラインを返し、estimator.named_steps['select'].get_support(indices=True) で各分割が選んだ列が分かります。5分割のうち毎回選ばれた列は1本だけで、これがノイズに対する選択の姿です。パイプラインで計算したスコアは擁護できますが、「全体にちょっと前処理した」後のスコアはできません。
- まず分割、学習はそのあと:スケーリング、選択、補完はすべて交差検証のループの内側に置く。
- Pipelineはリーク防止の柵:
cross_val_scoreにパイプライン全体を渡せば、各段が学習期間ごとに学び直される。 - 各分割が何を選んだかを見る:分割ごとに変わる列はシグナルでなくノイズ。
ラボ:採点される内容
- リークのある評価15点
- パイプライン10点
- 正直な評価15点
- 各分割が選んだもの20点
- リークの大きさ10点
- 実データでの比較30点