特徴選択のデータリークを実測: 交差検証の外で選んだだけで、純粋な乱数から精度100%が出た
約14分で読めます

特徴選択のデータリークを実測: 交差検証の外で選んだだけで、純粋な乱数から精度100%が出た


「交差検証をしているのに、本番では全く当たらないモデル」の話は、機械学習をやっていれば一度は聞いたことがあると思う。原因としてよく挙げられるのがデータリーク——テストデータの情報が、何らかの形で訓練プロセスに漏れてしまうことだ。中でも有名なのが「特徴選択を交差検証のでやってしまう」パターンで、マイクロアレイの遺伝子発現解析の時代から警告され続けている古典的な落とし穴だ(Ambroise & McLachlan, 2002)。

ただ、私はこの話をいつも「気をつけましょう」という標語としてしか知らなかった。実際にやらかしたとき、精度は何%水増しされるのか。データの次元数や選ぶ特徴の数で、その水増しはどう変わるのか。そして「前処理を全データでやるのもリーク」とよく言われるが、それは特徴選択のリークと同じくらい危険なのか。数字で見たことが一度もなかったので、真の信号が一切ないデータ——つまり純粋な乱数——を使って、幻の精度がどこまで出るのかを実測してみた。

実験に使ったコードの全文はGitHubに置いています

実験設計: 乱数の特徴と乱数のラベルから「当たる」モデルを作る

材料は2つだけ。n=100サンプル × p次元の標準正規乱数の特徴行列XXと、それとは完全に独立に生成したランダムな2値ラベルyyだ。XXyyの間に真の関係は一切存在しないので、どんなに正しく評価しても、汎化精度の期待値は0.5(コイン投げ)にしかならないはずだ。逆に言えば、0.5を大きく超える精度が出たら、それは全部リークによる幻ということになる。真値がゼロだと分かっているからこそ、水増し分を1点の曇りもなく測れる。

このデータに対して、次の3条件で5-fold層化交差検証(分類器はロジスティック回帰)の精度を測った。

  • (A) 特徴選択リーク: 全データを使ってラベルとの相関の絶対値が大きい上位kk個の特徴を選び、その後で交差検証する。標準化はfold内で正しく行う
  • (B) 正しいCV: 特徴選択も標準化も、交差検証の各foldの訓練側のデータだけで行う
  • (C) 標準化リーク: 標準化(StandardScaler)だけを全データで先にfitし、特徴選択はfold内で正しく行う。「前処理を全データでやるリーク」の害の大きさを測る対照実験

条件(A)は、論文やKaggleカーネルで本当によく見る手順だ。「まず相関の高い特徴に絞ってから、交差検証で評価しました」——一見丁寧な仕事に見えるが、特徴を選ぶ段階でテストfoldになるはずのラベルまで見てしまっている

これを、特徴数ppを100から100,000まで(対数で7段階)、選ぶ特徴数kkを10から1,000まで(5段階)振り、各セルで乱数シードを20個変えて平均した。

結果1: pを増やすほど、幻の精度は上がっていく

まずk=10k=10(上位10特徴を選ぶ)に固定して、特徴数ppを振った結果がこれだ。

横軸に特徴数pを100から100,000までログスケールで取り、縦軸に5-fold交差検証精度を取った折れ線グラフ。オレンジの線(特徴選択を全データでやったリークあり条件)はp=100で精度0.68から始まり、pが増えるにつれ右肩上がりに伸びてp=100,000で0.88に達する。青の線(すべてfold内で行う正しいCV)と緑の破線(標準化だけ全データで行うリーク条件)はほぼ完全に重なり、全域で偶然の水準0.5の点線の周りに張り付いている。各線の周りには20シードの標準偏差の帯が描かれている

データは純粋な乱数なのに、リークあり(オレンジ)はp=100p=100の時点ですでに平均0.676。そしてppを増やすほど幻の精度は上がり続け、p=100,000p=100,000では平均0.883(シードによっては0.93)に達した。一方、同じデータ・同じ分類器で選択をfold内に移しただけの正しいCV(青)は、全域で0.49〜0.52と偶然の水準に張り付いている。

「次元を増やすほど水増しがひどくなる」のは、偶然の相関の最大値がppとともに伸びるからだ。次元の呪いを実測した回では高次元で距離が潰れる話をしたが、今回は同じ高次元が逆に「偶然の当たり」を大量に供給する側に回っている。1つの特徴とラベルの標本相関は、真の相関がゼロでもn=100n=100なら標準偏差約1/n=0.11/\sqrt{n}=0.1で揺らぐ。pp個の候補から最大値を取ると、その値はおよそ2lnp/n\sqrt{2\ln p / n}で成長する——p=100,000p=100,000なら0.48程度の「見かけ上の強い相関」が偶然だけで出てしまう。全データで選択する手順は、この偶然の当たりくじをpp枚の中から探し出してくる作業に他ならない。

結果2: p×kのヒートマップに広がる「精度1.000」の領域

次にppkkの全組み合わせを見る。ここが今回一番驚いた結果だった。

縦にスタックした2枚のヒートマップ。上の(A)は特徴選択を全データでやってから交差検証したリークあり条件、下の(B)は特徴選択をfold内の訓練データだけでやる正しいCV。どちらも横軸が特徴数p(100から100,000の7段階)、縦軸が選択する特徴数k(10から1,000の5段階)で、各セルに20シード平均の交差検証精度が数字で書かれ、オレンジの濃淡(薄い=0.5付近、濃い=1.0)で塗られている。上のリークあり条件はp=100・k=10の0.68から右上に向かって濃くなり、p≧10,000かつk≧316の領域は精度1.00のセルが並ぶ。ただしk=pとなる対角のセル(p=100・k=100、p=316・k=316、p=1000・k=1000)だけは0.51〜0.52と白く抜けている。下の正しいCVのヒートマップは全セルが0.48〜0.55の範囲で薄いままになっている

上のヒートマップ(リークあり)の右上、p10,000p\geq10{,}000かつk316k\geq316の領域では、交差検証精度が1.000——つまり100サンプル全問正解——になっている。p=10,000,k=316p=10{,}000, k=316のセルは、20シードのすべてで一度もミスなく1.000だった。もともと「精度90%が出てしまう」という想定でこの実験を始めたのだが、水増しは90%では止まらなかった。ただの乱数から、交差検証を(見かけ上)完璧に通過するモデルが安定して作れてしまう。

そしてもう1つ、このヒートマップには面白い「抜け」がある。k=pk=pとなる対角のセル——つまり全特徴を選ぶ(=実質何も選択しない)場合——だけは、p=100p=100で0.505、p=316p=316で0.522、p=1,000p=1{,}000で0.511と、きれいに偶然の水準へ戻るのだ。リークの正体が「テストラベルを使った選別という行為」そのものであることが、この対角線にはっきり現れている。選別がなければ、同じ手順でも幻は生まれない。

結果3: 分布ごと見る — 正しいCVとリークの間に開いていく溝

シード平均だけでなく、60シードぶんの精度の分布そのものがppとともにどう動くかもアニメーションにした(k=10k=10固定)。

k=10に固定し、特徴数pが100から100,000まで13段階で増えていくアニメーション。横軸は5-fold交差検証精度、縦軸はシード数(全60)のヒストグラムで、青が正しいCV(fold内で選択)、オレンジがリークあり(全データで選択)。p=100の時点で既に青の分布は0.5の破線を中心に山を作り、オレンジの分布は0.59〜0.79の範囲にあってほとんど重ならない。pが増えるにつれオレンジの山だけがどんどん右へ滑っていき、p=100,000では0.81〜0.96の範囲に達する。青の山は最後まで0.5周辺から動かない。タイトルには現在のpとリークあり平均精度が表示される

p=100p=100の時点で、2つの山はすでに大きく離れている(リークあり側の60シードの最小値は0.59で、正しいCV側でそこに届いたのは60シード中7つだけ)。そしてppが増えると、オレンジの山だけが右へ右へと滑っていく。p=100,000p=100{,}000では両者は1シードも重ならないところまで完全に分離し、リークありの精度は最悪のシードでも0.81、最良では0.96に達する(正しいCV側の最大は0.71)。「運悪くリークしても、たまたま低い精度が出て気づける」という救済はほぼ期待できないことが分布から読み取れる。

対照実験: 「標準化を全データでやるリーク」はほぼ無害だった

「同じ数字を見ているのに結論が逆になる」という点ではSimpsonのパラドックスの回と同じ種類の罠だが、あちらが集計単位の問題だったのに対し、こちらは手順の順番だけで起きる。さて、リークと聞いてもう1つよく槍玉に挙がるのが「StandardScalerを交差検証の外でfitしてしまう」パターンだ。scikit-learnのドキュメントでもPipelineを使えと繰り返し警告される。では、その害は特徴選択リークとどのくらい違うのか。

縦にスタックした2枚の散布図。どちらも横軸が正しいCVの精度、縦軸がリークありCVの精度で、同じデータ・同じ設定のペアを全条件(p×k×20シード)について1点ずつ打ち、グレーの破線でy=xの対角線が引かれている。上の散布図(特徴選択リーク、オレンジ)では点の大群が対角線から大きく上に浮き上がり、精度1.0の上端に張り付く点も多数ある。対角線上に乗っているのはk=pで選択が無意味になる一部の点だけ。下の散布図(標準化リーク、緑)では全ての点がy=xの対角線にぴったり張り付いた細い帯になっていて、上下への系統的なズレが見えない

結果は肩透かしと言っていいレベルだった。全640条件(p×k×20シード)で標準化リークあり/なしの精度差を取ると、平均+0.0001、差の標準偏差0.013、最大でも0.08。つまり水増し効果は平均的には検出限界以下で、個々の条件で見てもfold分割の揺らぎと区別がつかない。特徴選択リークが同じ比較で平均+0.396(最大+0.64)の水増しを生んだのとは、桁が2つ以上違う。

理由を考えれば当然ではある。標準化が全データから盗めるのは各特徴の平均と分散という「yyと無関係な情報」だけで、しかも訓練foldだけで推定した値とほとんど同じ値にしかならない。一方、特徴選択リークはテストfoldのラベルそのものを使って特徴を選別している。同じ「リーク」という名前で呼ばれていても、ラベル情報が漏れるリークと、特徴の分布情報が漏れるリークでは、害の大きさがまるで違う。「Pipelineを使わないコードは全部ダメ」と一律に断罪するより、「その処理はyyを見ているか?」を問う方が、危険度の見積もりとしてはずっと筋がいい。

正直に書いておくべきこと

  • 正しいCVの精度も0.5ちょうどにはならない。 セル平均は0.483〜0.546の範囲で揺れた(全体平均0.511)。n=100n=100の交差検証1回の精度は標準偏差にして0.05前後揺らぐので、この程度のズレは期待通りの雑音だ。p=3,162p=3{,}162の行が軒並み0.53〜0.54と高めに見えるのも、同じ20個のデータセットをkkを変えて使い回しているため行内の値が相関しているせいで、意味のある構造ではない。
  • 「標準化リークは無害」はこの設定での話。 特徴が行儀のよいガウス乱数で、分類器がスケールにほぼ不変なロジスティック回帰、という条件下の結果だ。裾の重い特徴や外れ値、nnがさらに小さい場合、あるいは目的変数を使う前処理(ターゲットエンコーディングなど)ではこの結論は使えない。今回の実験が示すのは「前処理リークが常に無害」ではなく、「リークの害はリークの種類によって桁違いに異なる」ことだ。
  • 分類器はロジスティック回帰のみ、選択基準は相関のみ。 勾配ブースティングでの選択リークや、相互情報量ベースの選択などは測っていない。ただし水増しの主因は分類器ではなく「pp個の中から偶然の当たりを選べること」なので、傾向は大きくは変わらないと考えている(これは実測していない推測だ)。
  • 交差検証の分割数(5-fold固定)やラベルの偏りの影響も振っていない。

手を動かして意外だったこと

一番の想定外は、水増しの上限だった。始める前は「乱数から精度90%が出たら記事になる」と思っていたのだが、実際にはp10,000p\geq10{,}000k316k\geq316の広い領域で精度は1.000に到達し、20シードの1つも欠けることなく全問正解が続いた。100サンプルを5つのfoldに分けて、どのfoldをテストにしても100発100中——リークした選別が作る「偶然の当たり特徴の寄せ集め」は、私が思っていたよりはるかに強力な暗記装置だった。

もう1つはkkの効き方だ。やる前は「選ぶ特徴を増やせば、1個あたりの偶然相関は弱くなるから水増しは薄まる」と直感していたが、逆だった。p=100,000p=100{,}000ではk=10k=10の0.883よりk=316k=316の1.000の方がひどい。弱い偶然相関でも、テストラベルを見て選ばれた特徴を316本束ねれば、ロジスティック回帰は完璧な暗記を組み上げてしまう。それでいてk=pk=pまで増やした瞬間に幻は消滅する。「選ぶ数を増やすほど悪化するが、全部選ぶと無害」という非単調な形は、ヒートマップを描いて初めて腹落ちした。

そして対照実験の標準化リークが、ここまで完全に無害とは思っていなかった。実験前は「特徴選択より小さいが、目に見える程度の水増しはあるだろう」と予想していたので、平均+0.0001という数字は予想と違った点として正直に記録しておく。

まとめ

  • n=100の純粋なガウス乱数と独立なランダムラベル(真の精度の上限は0.5)に対し、特徴選択を交差検証の外で行うと、5-fold CV精度はp=100p=100でも平均0.676、p=100,000p=100{,}000では0.883(k=10k=10)に達した
  • 選ぶ特徴数を増やすと水増しはさらに悪化し、p10,000p\geq10{,}000k316k\geq316の領域では20シードすべてでCV精度1.000——乱数から全問正解のモデルが安定して作れた
  • ただしk=pk=p(全特徴を選ぶ=選択しない)にすると精度は0.505〜0.522と偶然の水準に戻った。害の正体はテストラベルを使った「選別という行為」そのものだった
  • 同じ設定で標準化だけを全データで行うリークの水増しは平均+0.0001(最大0.08)と検出限界以下で、特徴選択リークの平均+0.396とは桁違いだった。「リークは全部同じように危険」ではなく、そのステップがyyを見ているかどうかが危険度の分かれ目だった
  • 幻の精度はppとともに2lnp/n\sqrt{2\ln p/n}のペースで伸びる偶然相関の最大値に支えられており、「特徴が多いほど、リークしたときの見かけの成績はむしろ良くなる」——高次元データほど、この落とし穴は深くなる