有意水準5%で純情な感情

有意水準5%で純情な感情

データサイエンティスト見習いです。データ解析とかIoTとか。 技術ブログも書いてますhttps://qiita.com/okura__

signateのマイナビコンペ2019に出ました

初めてデータサイエンスのコンペに出ました(https://signate.jp/competitions/182)
kaggleのタイタニックをやったことはあって、雰囲気はなんとなくわかっていながらも、
敷居が高いように感じてリアルタイムにコンペに出たことはありませんでした
そんな時にsignateが学生限定のコンペをやるとのことで、これは絶好の機会と思い、参加しました
しかもテーブルデータということで(画像コンペ等と比較して)とっつきやすく、
計算資源が少ない僕でも参入しやすいことも参加した理由の一つです

多くの学びがあったので備忘録的に、また同じように敷居が高いと思ってる方向けにやったこととかを書いていこうと思います

僕のスキルは少し機械学習の勉強をして、機械学習の長期インターンで実務を少しやってるくらいです
noviceなので間違いやアドバイス等あればご教授いただけると嬉しいです

概要

コンペの概要は上のページを見ていただければわかると思いますが、
敷地面積や設備、立地等から目的変数である家賃を当てようというものです。評価指標はRMSEです
用意されている説明変数は15個とそんなに多くないものの、外部データ使用ありのコンペになってます
純粋なLBでの順位の他にアイデア賞という枠も用意されてるみたいなので、アイデア賞への投稿に多様性を出すためなんですかね

カーネルスタート

フォーラムの欄にEDAをあげてくれてる方がいたのでまずそれを足がかりとしました(初心者には大変ありがたいです、、、)
EDAから簡単な前処理、lightGBMで学習、サンプル提出のように
一連の流れが含まれていたので、このカーネルをベースとして最後までやってました
lightGBMは欠損値を埋めなくて良かったり、カテゴリ変数を指定できたりして使い勝手が良さそうで、
始まる前からlightGBM使おうとしてたのでありがたかったです
ちなみにカーネルにそって提出した予測のスコアはPublicで40000前後でした

特徴量作成

公開カーネルは前処理をしてなかったので、前処理をしつつ特徴量を作れそうなところを作っていきました

リソースの管理

初めてのコンペだったのでリソースの管理に苦心しました
後々困らないようにどのcsvがどの特徴量を追加したものか、
どの特徴量がカテゴリ変数なのか、各データセット,各パラメタでのスコアなどをメモしていました
ですが、あまり綺麗に整理できず、勘違いで無駄なことをして自分の首を閉めてました、、
次回コンペに出るときはディレクトリ構造と作業ログの残し方をちゃんと考えないとダメですね

関数化にこだわる

今まで重い処理を軽くしたり、可読性を高めたりする必要に迫られたことがありませんでした
ですが今回は作業の効率のため、コーディングスキル向上のために効率的なコードにこだわって書いてました

たとえばpandas.DataFrameはforではなくapplyで処理する、同じ処理を繰り返し行う時には関数定義して綺麗に処理するなどです
当たり前のことですが、意識するようになるとグッと効率が上がりました
ちなみにインターン先での業務でも効率が上がったのでハッピーでした

やったこと

具体的に前処理と特徴量生成でやったことについて話そうと思います。特別なことはしてません

  • str型→int(float)型に変更
  • カテゴリ変数はlabel encoderで処理
  • 一つのカラムに入ってる複数要素を複数カラムに展開
    • 設備等のデータ
    • 住所データ
    • 契約期間データ
  • 最寄りの施設までの距離作成

1,2個目は別に言うことないので飛ばします
一つのカラムに入ってる複数要素を複数カラムに展開はたとえば 東京都千代田区1-1を都道府県,市区町村,番地 に分けるみたいなことを意味してます
基本的にはあんまり効かない特徴量ばっかりになったんですけど、住所から作ったTownは feature importanceが2位の強い特徴量になりました
最寄りの施設までの距離作成は各施設の最寄りとの距離を特徴量として作りました。コンビニとスーパーは割と効きましたが、最後の提出には含みませんでした
正直遅れて参戦したこともあり、最低限の処理さえ未処理の特徴量もあったので、もう少しできることはあったかなと思います

別モデルに浮気

特徴量作成に限界を感じ(正確には飽きた)、選択するアルゴリズムの変更を試してみました

cat_boost

kaggle meetup tokyoの動画で、cat_boostというものを知りました (https://www.youtube.com/watch?v=4jd2XKALye0)
cat_boostは内部的にカテゴリ変数の組み合わせを作ってくれるらしくて、
laebl encodingで作ったカテゴリ変数がたくさんあったので試してみる価値はあるかなと思い、やってみました
使ってみた結果、スコアも上がらないし、学習にありえん時間がかかるので使うのはやめてしまいました
1位のチームはcat_boostを使ってたみたいなので、使ってる特徴量やパラメタの違いなんですかね(学習時間に関してはわからん)

ニューラルネットワーク

lightGBMのお供にNNがいいということもkaggle meetup tokyoの動画で知りました
Ensembleは別系統のアルゴリズムのものと組み合わせるといいらしいです
自分のなけなしの知識で3層のNNを組みましたが手元のスコアは26000で、
全然精度でず、、(その時のlightGBMはスコア22000くらい)
一応4:1くらいで混ぜてみるも当然スコアは上がらなかったのでこちらもお蔵入りしました
特徴量も対して入れてなくて、チューニングもしてなかったので、意外とちゃんとやれば使える程度にはなったかもしれません

ブレイクスルー

今まで書いてきたようにコツコツやってたんですが、ずーーーっとvalidスコアとPublicLBのスコアに乖離があることに悩んでました
評価指標がRMSEなので、testデータに外れ値が多いのかなとか思ってたんですが、
ある時急に学習時にカテゴリ変数を指定してないことを思い出しました
(一回カテゴリ変数を指定したんですが、カテゴリ数2のものを指定してもスコアは全く変わらず、
カテゴリ数1000~のものを指定したらスコアが悪化したので指定するのをやめてた)
そこでカテゴリ数~50のものを指定したら、validスコアは上がらないものの、PublicLBがガクッと下がり、validスコアにかなり近づきました
なんでカテゴリ変数を指定しないとvalidスコアとPublicLBに乖離が生まれるのかはわからないままです

2度目のブレイクスルー

築年数に外れ値があったのに気づかず(数字に変換した後に確認するの忘れてた)、
そういえば家賃も外れ値あったなーと思って外れ値の処理をしてました
家賃の外れ値を抜くとスコアが16000くらいに下がり、
signateちょろいわーとか思ってたらPublicでは24000で泣きそうになりました
実際には全然ブレイクスルーじゃなかったです
train_test_splitの割り方によって生じる精度の揺らぎかなと思って、
実装をめんどくさがってたクロスバリデーションを実装しました
多少揺らぎはましになったものの、外れ値の問題は解決せず、、、

twitterのTLみてたら、同じマンションの物件情報が
かなりたくさんあったらしくて、leakを考慮する必要あったらしいです
確かにleakしてると精度の過大評価になってvalidスコア<PublicLBのと辻褄が合います
さらにはこれを利用してtrainのデータと同じマンションのtestデータを埋めることもできたみたいです
みんな頭いいですね

やりたかったこと

時間が足りずにできなかったことがいくつかあります

前処理

アクセスの部分の処理にすごく悩んで結局時間足りなくてできませんでした
各物件に数が不定の最寄り駅とその路線情報がありました。カテゴリ数が500くらいあったので
one-hot-encodingするには多すぎるし、数も不定だからtarget encodingもlabel encodingも出来ないみたいな感じでした
そこで適切な処理かどうかはわかりませんが、各最寄り駅に対してtarget encodingをして、
その平均をとる操作ならできるかなーと思いました
ただ、target encodingはleakを防ぐような実装が必要で、
それを複数の最寄り駅に対して行う必要があり、コードがかけずに終わってしまいました
近々実装してみて効果を確認してみようと思います

NN

lightGBMと前処理を若干変える必要があり、コスパが悪そうなのでやめてしまいました
ですが、かけた労力の割にスコアが出ていたので、筋は悪くなさそうでした
こちらも近々実際にやってみたいです

緯度・経度情報

住所があったので緯度経度が取得できるはずなのでやりたかったんですが、
課金する必要があると小耳に挟んで、他にもやることはあったので
そちらを優先していたら時間ぎれになってしまってました
緯度経度を取れると面白い特徴量が作れるみたいなので
是非試してみたいです

学んだこと

そんな感じで不完全燃焼ながらも初めてのコンペをとても楽しめました 結果は302人中103位でした。実際は分母はもう少し小さいですが。

あまり納得の行かない悔しい結果でしたが、学べたことはとても多かったです

  • 前処理
    • 大量なデータの前処理の仕方
    • typoの処理
  • モデリング
  • コンペの雰囲気/流れ
    • leakは意識しよう(戒め)
    • スケジュール感
    • ユニークな特徴量の大切さ
      • 港区ポテンシャルとtwitterで調べてみてください
  • その他
    • ドキュメントの読み方を学んだ
      • lightGBMのドキュメントを読んだ
      • 苦手意識で避けていた
    • 実装力の大切さ
      • 実装で困ってると同じ土俵にも上がれない
    • 自分のレベル感を知れた

上位解法が出るのもすごく楽しみです
ぜひ次はkaggleに参戦しようと思います
間違いやご指摘、ご教授等ありましたら、是非twitterにてご連絡ください!(@takeru_okura)