【SIGNATE】マイナビコンペLoser's Solution
今回参加したSIGNATEの学生限定マイナビコンペについて振り返りを書きます
302チーム中最終34位と情けない結果に終わったものの、一応頑張ったんだぞって形跡を残したかったので、戒めとして記録を残したいと思います。
記事の構成
- コンペ概要
- 試したこと
- 反省
コンペ概要
コンペのタスクは外部データ使用アリの東京23区賃貸物件の賃料予測でした
おおよその賃料は10~20万円前後ですが、一部含まれている高級物件では100万円弱のものもあり、一番高いもので250万円の物件がtrainデータに含まれていました。
またtrain, test内には同一建物の物件情報が含まれており、同一建物であることを上手く特徴量にすることが必要でした
・評価指標
本コンペでの評価指標はRMSE(Root Mean Squared Error)
RMSEは外れ値の影響を受けやすい指標です。
誤差の二乗(の平均のルート)をスコアにするので、大きく予測を外しうる超高額物件を全力で当てにいく必要がありました
例:予測誤差が与えるスコアへの影響
100個の物件で2万の誤差 = 1つの物件で20万の誤差
・Kaggle本の存在
これはコンペとは直接関係ないですが、コンペ期間中になんでも書いてある本こと「Kaggle で勝つデータ分析の技術」が発売されました。
僕も買って読みましたが、TLを見た様子だと全人類買っていたので、定石は全て試し、他人がやっていないアイデア特徴量や、ドメインに特化した特徴量、モデルの組み合わせが必要だと感じました
以上をまとめて本コンペでの争点は主に次の4点だったと思います
- 同一建物の有効活用
- 外部データの使用
- 外れ値の取り扱い
- アイデア特徴量
この4点を踏まえながら以降は自分がコンペ期間中に試したことを書いていきます
以下Loser's Solutionです
試したこと
前処理
・単語の分割
3LDK → [3, LDK]
2階/12階建 → [2, 12]
東京都港区赤坂a-b-c → [港区, 港区赤坂, 港区赤坂a]
間取りは順序変数に(R < K < DK < LK , LDK)
所在階のカラムは書き方として以下の3パターンありました
- ◯階/◯階建
- /◯階建
- ◯階建
◯階建としか書かれていないものは一戸建てらしきものが多かったので一戸建てフラグを作りました。これはgroupbyで効きました
・記入ミスの訂正
同一建物の中で明らかに値段がおかしいものや、賃料/面積の値が高すぎる、低すぎるものについては修正することで手元のCVがちゃんとしたものになりました。
特徴量作成
基本的な特徴量
・単語ごとにOne-Hot
・Tfidf
・count encoding
・数値データをビニングしてカテゴリ化
・groupby
・四則演算(数字はとりあえず割る、引く。統計量取ってからも割る引く)
・その他色々
家賃ドメイン
特徴量生成にあたり家賃に関するドメイン知識を調査しました。
家賃情報について書かれたサイトはいくつかありますが、以下の考え方を参考にし、直接賃料を出す特徴量作りを目指しました。
賃料 = 単位面積の賃料 × 面積 × 方角倍率 × 階数倍率
方角:南向きが高くて北向きが安い
階数:上に行くほど高い
これらに加えて建物構造等の特徴量はカテゴリとしてではなく順序変数として扱いました。
またこのコンペの前に行われていたSIGNATEの土地コンペの上位解法を参考にバスと徒歩の距離スケールを合わせました。
(この辺りの事前知識と前処理と簡単な特徴量のみ作った際のfeature importanceから面積、位置情報が重要な特徴量だと感じたので、新たな特徴量を作ったらとりあえず面積と混ぜ、位置情報は建物から区まで様々な粒度で作るよう意識しました。)
同一建物の特定
同一建物の中でも表記揺れが多かったため、NULLが少ないカラムの表記揺れしにくい部分をIDに使いました。
建物ID = 所在地の◯丁目部分まで + 建物階数 + 築年数の年数部分
建物IDは同一建物内での回帰、target encoding、fold作成に使用しました。
回帰については、同一建物なら単位面積の賃料は同じだろうという仮定のもと建物ごとに、面積と階数情報だけを使ってモデルを作成しました。
ただ意外と本筋のLGBMでそこそこ予測ができていて、線形回帰は全体として精度が中途半端だったので使い所を持て余していました。
(ここでの回帰はtrainのRMSEをみて精度が悪いやつは使わない、外したら困る超高額物件だけ結果を用いる等でも良かったのかなと終わってみて思います。)
外部データの使用
外部データは緯度経度に加え、下記の2つのサイトから取得しました。
・地価データ
・駅の利用者数
・区ごとの一畳辺りの家賃【円】
・区ごとの昼夜人口比【%】
作った特徴量
・地価データ×面積
・家賃×面積, 方角, 階数 (駅の利用者数で重み付け)
・駅利用者数/駅からの距離
・住所、区、駅の緯度経度をGMM
・etc...
外れ値の扱い
今回のコンペと同様に評価指標がRMSEで外れ値の扱いが問題となっていたKaggleのEloコンペでの解法、特にえじさんのblogを参考にしました。
Eloの上位解法の中に、事前に外れ値予測の2値分類モデルを作成してから、予測結果を特徴量に加えるものがあり、そのアイデアを参考にしました。
マイナビコンペでは外れ値(ここでは賃料上位90%以上くらいのもの)の中でも取りうる値の幅が広かったので、一旦回帰モデルで予測して、予測結果を閾値で分けて3つに分けました。
0:上位85%まで
1:上位15%(賃料17万円以上)
2:上位0.2%(65万以上)
ただ、3値分類は最終日に取り組んだため良い閾値に調整できずに手元の結果と、LBとの結果に大きな乖離が生まれる結果となりました。
この辺りLBとの相関を見ながら調整する必要のあるものは序盤から試すべきでした*2
その他特徴量
・地価が高い地域からの距離
( http://tokyokante.b8.coreserver.jp/ 公益社団法人東京都不動産鑑定士協会HPより)
東京都の地価分布は中央区, 千代田区, 港区あたりを中心としてそこから離れていくにつれて下がっているようだったので、
「東京駅、池袋駅、渋谷駅、新宿駅、銀座、白金台」からの距離・角度の特徴量を作成しました。
これらはそこそこ効いて、一番効いたのは池袋駅からの距離でした。
・target encoding
賃料のtarget encodingはleakすらせず全然ダメで、単位面積の賃料でのtarget encodingは効きました。
・ モデル
使用したのはLGBM
foldの切り方は所在地でStratified-Kfold
objective:poisson
試したモデルは下記の通りです。
・外れ値ありで学習(手元cv:12000~14000)
・外れ値なしで学習、外れ値部分は外れ値モデルで補完
・target encodingアリのモデル(手元cv:15000前後)
・外れ値ありで学習、建物IDが同じものは建物毎の線形回帰の結果を補完
パラメータの調整はnykergotoさんの記事を参考に各モデルごとに調整しました*3
最終submitはそれぞれの結果をstackingしてtrain, testで建物の被りがあるものは線形回帰の結果で補完したものを選択しました。
・結果
結果として選んだsubはPublic:50~60位、Plivate:34位でした
最終日に作った特徴量(外部データ周り、外れ値) を入れることで手元のスコアは大きく上がりましたが、LBとの相関が取れておらず最後までスコアは伸び悩みました。
原因は外れ値予測特徴量の分布じゃないかと思うんですが、出してみないと分からないのでlate submissionさせて欲しい...
やり残したこと、試したかったこと
・目的変数を[0, 1]にしてxentoropy
・pseudo-labeling
・T-GAN
・LGBM以外のモデル
反省点
・特徴量でもモデルの面でも優先度の高いものから試して、毎日上限まで意味のあるサブミットすべき
・先人が効いたと書いてるものは全部やる
・(特徴量のindexずれ、効いていた特徴量の入れ忘れなどの)ミスに対応できるように実験結果を綺麗に残す*4
以上です。次はkaggle頑張ります。
書いてたやつをそのまま載せただけですがコードはgithubにあります
*1:過去に参加した、Sport Analyst Meetup(https://spoana.connpass.com/)の概要欄「スポーツデータを分析したいけどデータがない人向けのデータ取得方法」の項目にデータセットの主な収集先がまとめられており、sport関係なく参考になると思います政府統計もここで見つけました
*2:train, testでの3値の分布の違いに気づいたのがコンペ終了直前でどうにもならず辛い思いをしまいた。
*3:困ったことがあればとりあえずnykergoto’s blogを見れば半分は解決する印象があります。お世話になっています
*4:日付、使用した特徴量、パラメータ、各foldでの予測値あたりは一つのファイルにまとめたい気持ちが募りました