Higu`s diary

大学院生の日記です。主にプログラミングとカメラについて。最近はデータ分析・Kaggleにハマっています

マイナビ × SIGNATE Student Cup2019に参加して9位でした

こんにちは、ひぐです。

先日マイナビ × SIGNATE Student Cupに参加し、9/342位になりました!
この記事ではどんな取り組みを行ったかを書きたいと思います。
なるべく本コンペに参加してない人にも内容がわかる記事にしたいと思います。

本コンペの基礎情報

マイナビ × SIGNATE Student Cupとは年に1度開かれる、学生のみが参加できるデータ分析のオンライン大会です。
お題とデータが渡され、機械学習を用いて目的変数を予測し精度を競う大会です。

本コンペのテーマは「東京都23区の賃貸物件の家賃予測」です。
各物件に対し、「面積、方角、所在階」などの情報が与えれ、そのデータを元に家賃を予測する、といった内容でした。

f:id:zerebom:20191108215858p:plain
引用:https://signate.jp/competitions/182

データ量はTrain,Testどちらとも3万程度でした。

本コンペの特徴

本コンペのデータは以下4つの特徴があり、これらをうまく取り扱うことが精度向上の鍵になったかと思います。

  • 外れ値がある上に、評価指標がRMSE
    目的変数である賃料は非常に右に裾が長い分布であり、最も高い物件の賃料は250万円もするものでした。
    評価指標がRMSE(二乗平均平方根誤差)であるため、これらの高級物件の誤差をいかに小さくするかが重要でした。

    f:id:zerebom:20191108224222p:plain
    目的変数の分布

  • データが汚い&数値ではなく文字データとして与えられている
    データがすぐに使える形で与えられていなかったため、正規表現等を駆使して情報を取り出す必要がありました。
    また、欠損値や書き間違いも多く含まれ、丁寧に処理する必要がありました。

  • Train,Testで同じようなデータが含まれている
    物件データの中には、同じアパートの別の部屋などが含まれており、 普通に学習するより、学習データと同じ値で埋めるほうが精度が高くなりました。

    f:id:zerebom:20191108224133p:plain
    同じようなデータ群

  • 外部データ使用可能
    このコンペでは外部データの使用が認められていました。
    土地データのオープンデータは非常に多く、どれをどのように使うかが大事になったかと思います。

弊チームの取り組み

最終的なPipelineは以下の通りです。

f:id:zerebom:20191109000508p:plain
Pipeline

基本的に「各物件のデータから推論より、同じ・似た物件データの賃料からキャリブレーションする」 というつもりで進めていました。

コンペ全期間の大まかな流れと精度の変化は以下の通りです。

  • 3人とも個別で学習(17000~16000程度)
  • チームマージしアンサンブル。LogをとってMAEで学習(15000程度)
  • K-meansで近傍データの作成(14500程度)
  • 住所の修正、単位面積あたりの賃料を推定(13000程度)
  • パラメータ調整、SeedAverage(12400程度)

特に住所の修正、単位面積あたりの賃料の推定が大きかったと思います。
順を追って説明します。

Plotlyを用いて予測誤差の原因を追求

簡単に予測モデルを作ってからは、出力誤差をPlotlyを用いて地図上にMapして、どういった物件が誤差が大きいか確認しました。
Plotlyはインタラクティブに描画されるため、ズームしながら一つ一つ確認できました。
詳しくはQiitaに記事を書いたので良ければ見てください↓
qiita.com

同じ住所なのに、違うアパートが含まれていること、
またそういった物件の誤差が大きいことを確認しました。

f:id:zerebom:20191108225251p:plain

欠損値、異常値補完

今回配布されたデータの物件の所在地には
A:「東京都〇〇区××n丁目x-yy」と正確に記載されているデータもあれば、
B:「東京都〇〇区××n丁目」と丁までしか含まれていないデータも多くありました。

これらを注意深く観察すると、同じアパート(賃料・面積などから判断)でも
Aの形で所在地が埋められてるデータもあればBの形のデータもあることがわかりました。

そこで、面積、所在階、室内設備などの複数条件が同じであれば、同一アパートとみなし、
Bの形で所在地が記載されているデータを同じ物件のAの形の所在地に変換しました。
図にするとこんな感じです。
f:id:zerebom:20191109115533p:plain

こうすることで住所や緯度経度をkeyとした集約特徴量が正確な値になり、精度が向上しました。

外部データの使用

今回収集した外部データは以下の通りです。
- 地価データ
- 駅データ
- 路線数
- 1日の利用者数
- 緯度経度

これらから作成した以下のデータは精度向上に寄与しました。
- 物件とその物件から最も近い駅の距離
- 物件から最も近い距離にある公開されている地価
- 上記の地価の2012年から2017年の変化率
- 六本木ヒルズからの距離

K-meansを用いた近傍データの使用

地域によって賃料が全然違うことから近傍データが効くと考えられました。
そこで、緯度、経度、築年数を元にK-meansでクラスタリングし、 このCategorycal変数から以下のような特徴量を作成しました。

  • 同一クラスタ内の平均地価(賃料/面積)
  • 同一クラスタ内の平均地価×自身の面積
  • 同一クラスタ内の平均地価と自身の地価の差分・比率
  • 同一クラスタ内の平均築年数と自身の築年数の差分・比率

差分や比率を入れることで、各物件がクラスタの中でどのような位置付けがわかります。

前処理を丁寧に行なったこともあり、強力な特徴量となりました。 築年数をk-meansの判断材料に入れることにより、より似た性質の物件を同じクラスタに入れることができました。

外れ値に強いモデルの作成

外れ値も外れ値でない値も正確に予測したかったため、
Logをとってmaeで学習をしました。

また、賃料は面積との相関が強かったため、単位面積あたりの賃料を予測するモデルも作成しました。
面積で割り、さらに築年数を考慮したクラスタリングで特徴量を作ることで、
賃料という立地×築年数×面積×その他要員という複雑な変数をモデルに理解させることができたと思っています。

最終予測結果はlightgbm、Kfold、k-meansのシードを1ずつ変えて
30シード×2モデル×10Foldの600個のモデルから作成しました。

k-meansのSeedによって大きく精度が変わってしまっていたのですが平均をとることで
大きくshakedownすることのない頑健な出力結果となりました。

チームでのコミニュケーション方法

チームメンバーはそれぞれ就活や修論で忙しかったため、
それぞれが進められるときに進めて行きました。

Github,Line,Trelloでやりとりを進めていたのですが、特にTrelloが便利でした。 25MB以下のファイルはほぼ無制限に共有できること、各人の取り組んでる内容、進捗状況がすぐにわかったので、非常にスムーズにコミニュケーションを取れました。

f:id:zerebom:20191108233928p:plain
使い倒されるtrello

参考にしたサイト

飯田コンペ上位手法 signate.jp

Lightgbmのパラメータ調整 nykergoto.hatenablog.jp

Kaggle本 Stacking, Validationの考えをしっかり学べました

感想・まとめ

良かった取り組み

  • チームを想定してコードを書いた
    早い段階でチームで関数の書き方にルールを作ったのでコードのマージが楽だった。(引数も返り値もtrain,testをまとめたDataFrameにする等)
    前処理担当、モデル担当、外部データ担当と分けることで責任感を持ちつつ作業ができた。

  • 一度使ったらおしまいのコードを書かないようにした。
    よく使う関数はクラス、関数化した(target_encoding,save_data,lgb_predictorなど)

  • Lightgbmのバージョンを上げる
    なんと精度が上がります

改善するべき取り組み

  • どんなコンペにも対応できる柔軟なPipelineコードを作っておく。
  • 実験のログをもっと綺麗にとる
  • lightgbmに詳しくなる(最後まで気づかなくて、max_depth=8,num_leaves=31とかだった)

まとめ

今までこれほど良い順位でコンペを終えられたことがなかったので嬉しい反面、
入賞する気概で取り組んでいたので9位という結果は非常に悔しいです。

個人で取り組むと、だれてしまったり諦めてしまいがちなコンペもチームでやればモチベーションも上がる上に、
他の人のアイデアから異なるアイデアが浮かんだりと、アンサンブル学習の威力を実感でき、非常に楽しかったです。

最後3日で順位が20位くらい上がったこともあり、停滞期で諦めないことも大事だなと思いました。 (とはいえ、上位の人たちはずっと上位だったので地力の差も感じました)

今後は今回学んだことをしっかり復習してKaggleでメダルを取れるように頑張っていきたいと思います。 また研究や、企業でデータ分析を生かして社会に貢献できるようにも頑張りたいです。

それでは最後までご覧いただきありがとうございました!

よければTwitterのフォローもよろしくお願いします( ^ω^ )

google-site-verification: google1c6f931fc8723fac.html