AfSIS 反省会

Kaggleで行われていたAfrica Soil Property Prediction Channgleに参加して、結果は1233チーム中148位だった。
反省会です!!

ちなみに参加していなかった人には何を言っているか全く分からないと思いますのでご了承ください。

今回のコンペは、yag_aysさんも書いているけど、public LBとprivate LBで、かなり大きな順位変動があって、public LB1位だった人が500位台まで飛んだり、上位を狙うのは極めて難しい内容だった。ただこれは結果が出る前から明らかだったことで、それを見越してprivate LBで上位に入るように考えていたんだけど、いろいろ予想が外れてしまい失敗してしまった。

オレの予想と現実の違い

予想
  • private 1位は0.46くらい
  • (この間に多くても20人くらい)
  • オレは0.48〜0.50くらい
  • Abhishekのコードは0.55以上
現実
  • private 1位は0.46892
  • (この間に150人くらい)
  • オレは0.50290
  • Abhishekのコードは0.50558

現実は厳しい!!

だいたい以下のようなことを考えていた。

  • 自分の投稿やフォーラムの話、Sentinel LandscapeベースのCVからpublic LBより0.1くらい悪いスコアになるだろう
  • public LB上位(0.36~0.38)のうち何人かは本当にうまくいっていて残るだろうから1位は0.46くらい
  • 自分の投稿は、Sentinel LandscapeベースのCVで0.48くらい、public LBの計算に使われている簡単なデータセットはprivateから除かれるのでこれよりちょっと悪くなるだろう
  • AbhishekのコードはSentinel LandscapeベースのCVで0.61、locationベースのCVで0.56くらいという話があったので(自分では検証していない!!)よくても0.55くらいだろう
  • 参加者の多くは、Abhishekのコードをベースにしているので0.5には届かないだろう

多くの人はprivate LBで爆死するので、爆死しないように気をつけておけばそれほど頑張らなくても上位に入れるだろうと考えていたんだけど、この予想が外れ、Abhishekのコードがなんと0.50というスコアを持っていたため、そこから少しでも改善できた人達150人くらいに抜かれてしまった。

反省点としては、他の人が勝手に爆死することを期待したり、Kaggleの天才データサイエンティスト達を舐めてたりといったふざけた態度でのぞまず、自分のスコアを上げる方向で頑張るべきだった。マル。

自分のソリューション

ちなみに自分の方法は以下のような感じだった。

  1. spectra特徴からCO2の領域を削除
  2. spectraにfirst derivative filterを適用
  3. spectraをPCA Whiteningで160次元に圧縮
  4. 圧縮したspectra特徴, spatial特徴(衛星から取ったやつ), depth(表層か下層か)を入力可能な特徴とする
  5. huber loss functionのneural networkで回帰
  6. neural networkのアーキテクチャやハイパーパラメーターはSentinel Landscapeに基づくCVで良い結果が出るように調節する (spatial特徴を使うか使わないか、depthを使うか使わないかの組み合わせも含めて)

1は、ホストが推薦していたことで、やったほうが結果もよかったのでやった。
2は、CVではやってもやらなくてもほぼ違いはなかったので迷ったけど、データをプロットしてみるとデータごとに異なる謎の直流成分(定数のズレ)が入っていて、どういう理由で入ったのか分からないけど、おそらくホスト側でデータを正規化したときに入ったんじゃないかと思ったのと、ホストが用意しているベースラインのベンチマークコードではfirst derivativeを使っていて、これを使うと直流成分は消えるので、消したほうが安心だろうと思って適用することにした。
3もやるか迷ったものだけど、正規化のパターンとして

  • z-socre
  • ZCA Whitening
  • PCA Whitening (512,256,160,128 component選択)

を試してみて、z-socreは一番結果が悪かったので無しで、ZCAとPCAはほんのちょっとだけZCAのほうがよかった。ただ、今回のデータは学習データが約1000件で入力が約8000次元あるので、できるなら圧縮したほうがいいだろうと思っていたのと、入力次元を少なくするとneural networkの学習時間がかなり短くなので、実験回数が増やせて、この微かな差は挽回できるのではないか、と考えて160次元に圧縮することにした。
結果からするとこれは失敗だった。ZCAバージョンも投稿していたんだけど、private LBではZCAバージョンのほうが微かによくて(0.4991)、こっちを選んでいれば95位くらいだった。(そんな変わらない)

4.はspectra特徴だけで学習するか、spatialやdepthも含めるかという話だけど、これは目的変数ごとに検証した結果以下のようにした。
Ca: spectra
P: spectra + depth
pH: spectra + spatial + depth
SoC: spectra + spatial + depth
Sand: spectra + depth

5.は、この問題には非線形回帰がよいことはちょっとやってみれば分かることで、非線形回帰ができるモデルとして自分の得意なneural networkを選んだ。重要なのは損失関数で、MSEではなくHuber lossを使うことにした。これは、学習データの目的変数に明らかに大きすぎる外れ値っぽいデータが少しだけ入っていて、MSEを最小化するとその影響がすごく出てしまうので、ロバストにしたほうがいいだろうということで選んだ。CVでもMSEよりHuber lossのほうが良い結果が出ていた。
ちなみにSupport Vector Regression(Abhishekのコード)が良い結果を出していた理由も、損失関数にsquared lossを使っていないことだと思っていて、というか、SVRで良い結果が出るという話が出たあとで、なぜSVRだけ良い結果が出るのか考えた結果、ε-sensitive lossのおかげだろうと思ったので、自分もそれに習って性質が似ていてneural networkで扱いやすそうなHuber lossを使ってみることを思いついた。

6.は一番重要なところで、CVのfoldをランダムサンプリングではなく、Sentinel Landscapeという単位を壊さないように分けるようにする。
これが重要な理由は、データページに書いてある。

The training and test data have been split along Sentinel Landscape levels because we are primarily interested in predicting soil properties at new Sentinel Landscapes.

http://www.kaggle.com/c/afsis-soil-properties/data

学習データとテストデータは、Sentinel Landscape levelsで分けられていると明確に書いてある。Sentinel Landscapeは土壌をサンプリングした時の一番大きい空間単位で、

60 Sentinel Landscapes
16 Sampling Clusters per Sentinel Landscape
10 Sampling Plots per Sampling Cluster
2 composite Soil Samples (topsoil & subsoil) per Sampling Plot

と書かれている。つまりこのコンペのデータは、階層構造を持っているので、データ単位でランダムサンプリングして同一Sentinel Landscape内のデータを学習/テストに分けてCVしてしまうと、最終スコアリングに使われる学習/テストと異なる条件になってしまって、おそらく同一Sentinel Landscapes内でオーバーフィッティングしていたほうがいいスコアを出すデータセットができてしまう。なので、CVでは、同一Sentinel Landscape内のデータが学習とテストに分かれないように注意してfoldを分ける必要がある。
ちなみに各データがどのSentinel Landscapeに属するかを表すIDは振られていないので(データの説明に書くならふれよ!!と思った)、TMAPという項目をキーとして使う。TMAPは年間降水量かなにかの変数だけど、衛星から取ったデータの空間解像度の悪さからこの値をキーとしてデータをまとめるとほぼSentinel Landscapeの単位でまとめれるという議論がフォーラムであって、その話をしている人達はかなり信頼できる人達だったので、オレもこれを使うようにした。

コンペ後のフォーラムを見ると、上位のほうがみんなSentinel LandscapeベースのCVをしていたってことはないようだけど、ただ少なくともlocationベース(同じ位置から取られたSubsoil/Topsoilのデータが学習/テストで別れないようにする)でやらないと、オーバーフィッティングしてたほうが高いスコアが出てしまうので、順位落とした人の多くは間違った条件のCVでハイパーパラメータを調節した結果、元になったAbhishekのコードよりも悪い結果になってしまったのでは、と思います。

最後にpublic LBが信頼できないだろうと思った理由。

  • 計算に使っているデータが少なすぎる(90件くらい)
  • CVに比べて異常によいスコア(public LB: 約0.40, CV: 約0.50、しかもこの超簡単なデータセットはprivate LBの計算から除外されるので、private LBはいっそう難しくなる)
  • CVと負の相関すらあるように見える!!
  • 信頼できそうな人達がみんな信頼できないと言っていた(重要)

追記

なんとかツリー系、入力が信号で説明変数間に強い相関があるのと、次元に対して学習データが少なすぎるのとで、変数選択がうまくいかなくて、決定木をベースとしたものは良い結果が出せなかったのでは、と思っているけど詳しくないので分かりません。
ただ100位以内の多くは、SVRGBMの結果を混ぜたものみたいです。