SIGNATE マイナビ Student Cup 2019(マイナビコンペ、学生コンペ) Loser's Solution

某学生コンペに参加しました

この手のデータコンペにちゃんと参戦するのが初めてだったのですが,初めてなりにそこそこは頑張ったので,その結果を記録するとともに,これからデータコンペに参戦しようと考えている人の道標に少しでもなればいいと考えて今回の参戦記を残そうと思います.

コンペ概要

家賃を予測する問題でした.評価指標はRMSEということで外れ値の影響が大きい指標になっていました.また,この手の給料や家賃系は分布が右に歪んだ分布となるため,パラメトリックな手法を選択する場合はその補正をしなくてはいけないですね.

貧富の差を感じる分布です

f:id:MosaasoM:20191112184721p:plain
賃料の分布

結果

Private 12位でした.

f:id:MosaasoM:20191112185507p:plain

Public LBのときは30位くらいだったので,privateの方で結構上がりましたね.

参加724人,投稿302チームで,個人参加者だけで数えれば4位と初参戦にしてはそこそこいい感じなんじゃないでしょうか.

以下参戦記及び得た知見をまとめて行きたいと思います.

今回のマイナビコンペは,題材が悪く言えば単純,良く言えば教育的でオーソドックスなものだったので,Loser’s Solutionにあんまり面白い事もないと思いますが…

今回のコンペの個人的なポイントは以下かなと思っています.

1.同一物件の取り扱い
2.外れ値物件の取り扱い
3.外部データの使用

1については自分はあまり考慮できていませんでした.この点をしっかり考慮したらもっと順位上がったのかも知れないですね.
2についてはいくらかの工夫を試しましたが,うまくいったかはわかりません.(後述)
3については,そんなに面白いデータを持ってこれませんでした.ディスカッションで公開した分が全てです.

SIGNATEのこれは欠点だと思うんですが、ディスカッションに情報を共有するインセンティブが無に等しいです。ってか無です。
外部データはもっと色々なデータを使っている人がいると思うのですが…
手法とか特徴量はともかく、外部データやCVの工夫なんか位は最低限共有されるくらいのインセンティブを設けてもらわないと教育目的のコンテストとしてもどうなんでしょう…というお気持ちになります。
マイナビコンペはWInner's Solutionが公開されたり、ディスカッションが存在するというだけでほかコンペに比べてマシな方ってのは流石にいかがなものかと…
ただ,SIGNATEでは上のように解法共有などをほとんどしないために,それが秘密や権利をしっかり保持したい企業さんや省庁からの案件を獲得することにつながっていて,そこらへんのトレードオフなのでしょうね…

まぁ愚痴っててもしょうがないので参戦記をまとめます。

以下参戦記とか試したことです.

まずは作った特徴量系を全部ネタバラシしちゃおうと思います.

作った特徴量

基本データ系

2 所在地 : 区,市を抽出してlabel encoding
3 アクセス : 列が最寄り駅の路線で値が駅までの徒歩時間になるように→NMF
4 間取り : Rの数のカラムと,LDKSの有無をそれぞれ01で表現したカラムに
5 築年数 : 普通に築年数を取る
6 方角 : label encoding
7 面積 : 普通に面積をとる
8 所在階 : 所在階,建物階,地下の有無,
9 バス・トイレ : 列が設備で,01でそれの有無を表したようなデータに
10 キッチン : バス・トイレと同様
11 放送・通信 : バス・トイレと同様
12 室内設備 : バス・トイレと同様→NMF
13 駐車場 : それぞれ有無を01に
14 周辺環境 : バス・トイレと同様
15 建築構造 : label encoding
16 契約期間 : 定期契約かどうかと年数.定期契約は2019年8月基準で計算

外部データ系

緯度
経度
大きい駅6個(池袋駅新宿駅 ,渋谷駅,東京駅 ,上野駅,品川駅,新橋駅)への距離
大きい駅群への距離での最小値
緯度,経度による地価公示点の重みつきknn(k=3)
土地の高度
緯度経度によって,20万以上の物件をknn( 修正,Kmeansです)し,その中心への距離

Target Encoding系

区による集約(平均,中央地,最大,最小,最大―最小)
方角による集約
建物構造による集約
徒歩時間による集約
最寄り駅の路線による集約

掛け合わせの特徴量

面積/部屋数
面積×部屋数
面積―築年数
築年数―建物の階

作ったけど効かなかった特徴量

一軒家かどうか
市による集約
そのほか掛け合わせ系たくさん

あと,最終的にStackingしたので,Stackingにおいての諸々があるので簡単に書きます. Stackingに使用したモデル.

1層目のモデル

LGBM
XGBoost
RandomForest
Lasso回帰
knn
MLP(300ノード隠れ層3〜4くらい)

線形モデルを使用するときには,一部の特徴量をlabel encoding→One hot encodingにしています. Catboostも試していたんですが,あまり意味がなかったので後から外しました. ちなみにSingleモデルの性能だけで言えば今回はXGBoostが最強でした.

2層目のモデル

Lasso回帰

この最後の集約モデルはRidge,Lasso,ElasticNet,木モデル諸々とか試したんですが、Lassoが最も良かったです。

また,Stackingの際に

高級物件(賃料20万以上)のみで学習したモデル 普通物件(賃料30万以下)のみで学習したモデル 賃料を直接ではなく,賃料/面積を予測してから面積をかけるモデル

を多様性のために作っています. 最終SubmitはRandom seed Average (n=10くらい)しています.

1 開始〜2週間くらい first subあたり

赤丸のあたりの話です

f:id:MosaasoM:20191112185404p:plain
投稿とスコアのグラフ

この頃はひたすらデータを前処理していました.今回の賃料予測コンペは特徴量が数字ではなく文字列型になっているものが殆どで,前処理がかなり辛かったです.この時点では基本的な特徴量しか作っていませんでした.

オーソドックスに木ベースのモデルを使うことは決めていたので(個人的にニューラルネット系の経験や知識が足りなく,ニューラルネットでスコアが伸びたことがなかったので),木モデルに合わせた特徴量作成をしました.

サクッと流していますが,設備や風呂系の特徴をどうやって実装するかで意外と人によって個性が出たかも知れないですね.

最初のモデルをサブミットする頃は,次のような構成のモデルを作っていました.

f:id:MosaasoM:20191112185546p:plain

これはhttps://amalog.hateblo.jp/entry/elo-merchant-category-recommendation の記事を参考に考案したものです.

高級物件は凡人の価値観では測れない賃料をしているので(港区というだけで明らかに相場の数倍になったりする),お金持ちの価値観を持つモデルを作ることでこのあたりを対応できないかなといった次第です.

まぁ見ての通りあまりうまく行ってません.というのも高級物件のデータが少ないからですね.結局高級物件側のlossが減らせないので分割したモデルを作っても無意味ということになってしまいました.

ただ,この金持ち側を考慮したモデルを別に用意するという発想は後々Stackingしたときに効いてきました。

2 コンテスト中盤あたり

f:id:MosaasoM:20191112185648p:plain

このあたりでスコアがググンと伸びているのは,このあたりで緯度経度を使用してもよいというふうに運営側から明示されたからです.緯度経度が追加されるにあたって,次のような特徴量を追加しました.

・単純な緯度経度
・緯度経度でknnして近い数点の値段を追加→最終的にはstackingの一部に使用しています
・大きな駅(乗降客数上位10)の駅までの距離

このあたりの特徴量を追加することで少しずつスコアを伸ばして行きました. ただ,ここで問題が…

手元のCVのスコアと提出スコアが離れすぎているんです.

手元のCVでは18000前後のスコアなのに提出すると14000代になるのが怖すぎて,ちょっとCVや学習のときのfoldの切り方なんかを考えなくちゃいけないのかな…?とか考えていました.

が,研究とか諸々が忙しく,そのあたり全く手をつけられませんでした… 次回があればここらへん検討したいですね。

ちなみに,青のPublic LBスコアにオレンジで最終スコアを重ねたものがグラフを下に出します.

f:id:MosaasoM:20191112185759p:plain
オレンジがPrivateスコア、青がPublicスコア

実際この中盤頃に提出したモデル、は終盤ごろと比較するとpublic LBでの向上や低下とPrivateスコアの推移が一致しておらず,かなり乱数運に頼るようなモデルになっていたことがわかります.

ここでpublic LBに満足せず,ちゃんと手元のCVと向き合えたのが順位向上につながったのかなと思います.

3 コンテスト終盤

f:id:MosaasoM:20191112185839p:plain

中盤で発覚したCVとLBのズレについて,今更この一致を取る検証時間は取れないと判断して,ここから手元のCVのみを元にモデルの改善を行うことにしました.

まずは,特徴量の追加です. 木モデルの性質上,順序尺度さえ保たれれば,スケールに関係なくある程度特徴量が仕事をするのでは無いかと考えて, 面積×部屋数(高級な部屋ほどより大きくなるはず)のような, ある程度順序尺度が保たれそうな組み合わせの特徴量を生成して追加してはスコアを確認していました.

ここで様々特徴量を追加しましたが,結局有効だった特徴量は少ないです.今回のコンペは物理的な次元を持つ特徴量が少なく,それが原因なのかなぁ.

また,ここで運営からさらなる外部データの使用が認められたので,地価公示点データと標高データを追加しました.地価公示点はknnで最も近い3点の加重平均として導入しています.

ここらでtrainデータに関して出力と誤差を見てみると,やはり高級物件に関して誤差が大きそうだということがわかったので,これを少しでも減らせるような特徴量を考えていました.

その過程で賃料が30万円を超えるような物件は一部地域に集中していることがわかったので,緯度経度を元に賃料が30万円を超える物件を適当にk-meansでクラスタに分割し,それぞれのクラスタまでの距離を特徴量として追加しました. その他,label encodingしている特徴量を利用して,それを元に集計した賃料を特徴量として入れたりしました.

また,アクセスや室内設備を元に作った特徴量がかなりスパースであまり良くないと判断したため,これらをNMFで次元削減した特徴量に変更しました.

その他LDAによるトピックなどを追加しましたが,あまり大きな効果はなかったと思います.

これらの工夫でsingleモデルの手元のCVを18500→16600程度まで上げることができたので,最後にこれらを適当うまくstackingすることにしました.

Stackingの第一層に使用したのは,木モデルが主にXGBoost,LightGBM,RandomForestです.

これらのモデルについて,全データ,賃料>20万のデータ,賃料<30万のデータで学習させてこれらを特徴量として使いました.また,線形モデルとしてLasso回帰,適当に作った全結合ニューラルネット,その他のモデルとしてknnを使用しました.

Stackingの最終的なモデルはLasso回帰を選択しました.木モデルやRidge回帰なども試しましたが,Lassoが手元のスコアが最も良かったです.

ちなみにStackingはfold数3,4,10で試しましたが、基本的には大差なかったです. 処理速度を考えると4くらいでいいのかもしれません.

Single モデルのfeature_importanceはこんなかんじです. 地価公示点データがやっぱり効いていますが,冗談で作った面積-築年数が異常に効いていて心配です.これなくしたらスコア上がったりしてたんでしょうか…

f:id:MosaasoM:20191112190145p:plain

おわりに 今回のコンペでは次のサイト様に多大にお世話になりました.ありがとうございました. https://naotaka1128.hatenadiary.jp/entry/kaggle-compe-tips

はじめてのコンペ参戦ということでわからないことも多く,少々悔しい結果になりましたが,色々学べたので次やったらもう少しスコアは伸ばせそうです.

ただ,データコンペはかなり時間が取られるので,次出るとしても結構先になるかもですね…次はkaggleのに出てみたい.

コンペ終わってスキマ時間でざっと書いたので推敲も何もしていません.そのうちもっとわかりやすく加筆修正するかもです.(多分しない)