第1回 国土交通省 地理空間情報データチャレンジ ～国土数値情報編～の振り返り

[SIGNATE][SIGNATE]で開催された[第1回 国土交通省 地理空間情報データチャレンジ ～国土数値情報編～][1484] モデリング部門に参加しました。その際の取り組みをまとめてみました。

## 1. 第1回 国土交通省 地理空間情報データチャレンジ ～国土数値情報編～ モデリング部門について

国土交通省が主催として初めて開催されたデータコンペです。本コンペでは、国土交通省が整備するオープンデータ「国土数値情報」と民間企業のデータを活用し、不動産の賃料・賃貸価格の予測モデルを構築するものとなっています。

コンペで使用するtrain/testのデータは、株式会社LIFULLが提供する全国の賃貸マンション・アパートの賃料であり、民間企業のデータとしては、株式会社ゼンリンが提供するZENRIN Maps APIや株式会社ネットデータの土地バンクを活用することができます。なお、ルールにより事前に示された外部データ以外は使用することができません。

また、今回データ分析・モデル開発環境として、データブリックス・ジャパン株式会社よりDatabricksが、Snowflake合同会社よりSnowflakeが提供されていました。以前、SIGNATEで開催されていた[第2回 金融データ活用チャレンジ][1337]でもDatabricksが提供されており、それを使って分析し、[いろいろな機能に感動しました][55019880f7f351d2b15b](その際はDatabricks/Microsoft/ナレッジコミュニケーション賞をいただき、会社にもDatabricksのご紹介いただいたのですが...、まぁ会社で使えることには今のところなっていないです)

ということで、素晴らしい分析環境が提供されても、その後に使えないのではなぁということで、今回は、Databricks・Snowflakeいずれも使うことなく、自前で頑張ることにしました。
DBは、自宅で動かしているlocalのUbuntuにdockerで構築したSQL Server 2019です。 


## 2. データ分析とデータの利用について

素晴らしい分析環境もそうですが、外部データもデータコンペ後に使えないのではなぁ〜ということで、今回はコンペの趣旨に沿って「国土数値情報」のみを活用する方針を決めました。

### 2.1 データ分析

地理情報を活用したコンペであるため、foliumやplotlyを使って、地図上にマッピングしましたが、あまりEDA的なことは実施しませんでした。これは、評価指標がRMSEである(RMSEになると、結局のところ件数が多く高額な賃料を抱える東京都の推定に引っ張られてしまうためです。この点では、国土数値情報を活用したコンペとしては気づきが得難いなと思うところで、MAPEにした方がより面白いのではないかと感じました)こともあり、首都圏の東京都港区や渋谷区の高級賃貸を中心に確認していきました。以下、データを調べての気付きです。

#### 2.1.1 賃料・提供データについての分析

0. 月の賃料が4000万円以上という明らかに誤っているものが含まれていました。これをそのまま学習に含めると、tree系のモデルはすぐにearly_stoppingで止まってしまいました。このため、当該レコードは除くこととしました
1. 昨今インバウンド需要で、爆騰しているニセコなどの高額賃貸などについて確認しましたが、高額の賃貸物件と思われるようなものはありませんでした(コンドミニアムのようなもので販売され、賃貸物件としては一般に掲載されるものはないということでしょうか？)
2. 長野県の軽井沢町や沖縄県の宜野湾市で比較的高い物件が存在していることが確認できました
3. 高額な賃貸には、デベロッパーとして森ビル・三井不動産・三菱地所などが建設したタワマンと、外国人エグゼクティブ層向けの低層物件が存在していることが確認できました。外国人エグゼクティブ層向け物件は、200平方メートル以上あると思うのですが、3LDKとなっていても部屋が大きく作られています(以前、富裕層の方のお宅にお邪魔した時の印象では、ゲスト向けのためにバス・トイレ・洗面台が最低でも2箇所以上設置されていること、キッチンのコンロも4口以上あること、などはポイントかと考えました)。これが外れるとRMSEのため影響が大きいと思い、部屋数を専有面積で割って指標を作るなど、何らかの指標が作れないかと考えましたが、サンプル数が少ないことや間取りが特殊なこともあり、あまり時間が取れずと効果の関係から有効な手法には至りませんでした。なお、`tag_id`(タグ情報)・`statuses`(設備情報)にあるコンロ４口以上とか、相関があるかと思いましたが、こちあらはダメでした。設備情報には、バスが2以上という情報がありませんでしたが、この様な情報があれば何か相関など出せるのではないかと思いました
4. 狭小であっても賃料が高い物件も含まれていました。具体的に個別の内容を確認すると、学生寮やシェアハウスなどがそれに該当し、部屋そのものは小さくとも、部屋の外の共用部が充実していたり、食事や家電が付いていたりするものでした。これらは、サービス付きアパートメントに近いものと捉えられるのではないでしょうか。今回、**シェアハウス**や**スチューデント**などが含まれるものを学生寮・下宿先というフラグをつけることとしました。自分がまだ、学生の頃はガチの下宿もまだ存在していましたし、学生会館的なものもあったんですが、今はこんな感じなのだなあと感じました
5. 高額物件順に物件を見ていたところ、コンシェリア新橋の`bukken_id = 1070950033777`のようにバスなしで巨大な1Kがたまに存在していました。この`bukken_id = 1070950033777`をよく見てみると、`room_floor	= -1`で`snapshot_window_angle = NULL`となっていました。このことから、これは誤りではなく地下1階の店舗向け物件であると考えました。これにより、本データには住居用の賃貸物件だけでなく、店舗や事務所向けの物件が含まれていると判断しました。trainデータを観察すると、この様な物件がそれなりに存在していましたが、testデータには似たようなものは少ないように感じられました。このため、巨大な1Kで、周辺の物件と比較して、平方メートルあたりの賃料が高いものについては、住居用ではなく賃料を高くなるものとして、trainデータから一部除外することとし、testデータでは特段処理を実施しないものとしました
6. `statuses`(設備情報)にメゾネットという項目が存在していますが、どうやらかなりこちらの情報がない場合で、`room_floor`と`room_kaisuu`が一致しないものもが存在し、その様なものはメゾネットタイプと思われるものが見つかりました。このため、この情報を特徴量としました
 


### 2.2 使用した国土数値情報

0. [地価公示][地価公示](L01-24): 利用できる地点の数が単純に多いという理由で、2024年度の地価を利用しました。用途区分に`000: 住宅地`, `003: 宅地見込地`, `005: 商業地`, `009: 工業地`, `013: 林地`がありますが、全て利用することにしました。特徴量として利用する際には、次のものを利用しました
    * 最近傍の公示価格をそのまま利用
    * 最近傍の建築可能面積(`建ぺい率 * 容積率 * 公示価格`)
    * 最も距離が近いもの上位3地点の公示価格を逆距離加重して算出
1. [1kmメッシュ別将来推計人口（H30国政局推計）][1kmメッシュ別将来推計人口（H30国政局推計）](1km_mesh_2018): 2020年度の人口推計値のうち使用することとし、2020年男女計0～14歳人口(PTA_2020), 2020年男女計15～64歳人口(PTB_2020), 2020年男女計65歳以上人口（PTC_2020）, 2020年男女計75歳以上人口（PTD_2020）, 2020年男女計80歳以上人口
（PTE_2020）とおよびその人口比率を用いました。
2. [医療機関][医療機関](P04_2020): 歯科医院の数はコンビニエンスストアより多いという話がありました。このため、コンビニエンスストアの情報はありませんが、有力な特徴量となるのではないかと考えました。当初は、この様な情報を作成する際に、1kmメッシュ別将来推計人口と組み合わせて、人口で割り、指標にしようとしましたが効果がでなかったため、物件の地点から直接求める様に変更し、半径2km以内の診療所、病院、歯科医院の件数をカウントしました。 
3. [小学校区][小学校区](A27_23): 以前、「千代田区立番町小学校は、名門公立小学校として、有名政治家などの子息(死語?)とご学友になるため、わざわざ引越してくる人がいるんですよ。」という話を聞き、小学校区にも相関があるのではないかと考えました。提供データには、`school_ele_name`(小学校名)という項目がありましたが、データを見ると、さほど近くもないのに有名私立小学校(e.g. 慶應義塾幼稚舎)が記載されていたりするなど、そのまま利用することができないものであったこともあります。特徴量としては、小学校の学校コードと距離を使用しました。このデータ使用する際に、他のデータは少し違い、次の点に注意が必要でした。
    * 全ての地方公共団体がデータを提供しているわけではないため、学区情報がない自治体が存在する(e.g. 品川区)
    * 地点によっては、学区が選択制となっているため、複数の小学校に通うことができる。この場合は、仕方がないので、(直線距離で)距離が近いものとしました。
4. [学校][学校](P29_23): 教育施設の充実度として、半径2km以内の小学校、中学校、中等教育学校、高等学校、大学、義務教育学校、幼稚園・こども園の数をそれぞれカウントしました。
5. [駅別乗降客数][駅別乗降客数](S12-23): 提供されたデータの駅名に限らず、不動産物件情報サイトって、よく最寄りの駅ではなくて、近めの主要駅(バスターミナルとかがある駅？)が記載されているじゃないですか、あれだと使いにくいなと考えて、駅別乗降客数を使用しました。しかし、このデータを使って棟情報と駅との距離を3km以内とし、最も近い駅の`S12_001g`を特徴量としました。(大きく取ると直線距離で道路状況などが一切考慮されず誤差が大きくなるため、このようにしてみました)が、あまり効果は得られないように感じました。次に示すような、このデータは鉄道に関する知識がないとダメで、少し扱いにくかったです。
    * 路線ごとに基づく駅のため、東京駅は12駅に分かれている。東海道新幹線・東北新幹線・東海道線・東北線・総武線・京葉線・東京地下鉄4号線丸ノ内線
    * 営業上は、中央線や京浜東北線となっているが、中央線の東京駅から神田駅までは東北線で、京浜東北線は、東京駅を境に東海道線と東北線となっているため、東海道線と東北線がたくさん出現する。
このため、駅と駅まで距離だけを特徴量として使い、乗降客数は使用するのは断念しました。乗降客数や路線全体の乗降客数などは使えると大変良いのではないかとおもったのですが、そこまで行き着けなかったのは残念でした。

### 2.3 検討したが使用しなかった国土数値情報

* [福祉施設][福祉施設]: 人口推計と保育園の数を組み合わせて利用することを検討しました。参照した2023年度のデータを可視化したところ、自分が住んでいる横浜市の部分がほとんど空白地帯となっており、情報がないことに気がつき利用を断念しました。後ほど確認したところ、2015年度では、横浜市の情報も含まれていましたが、ここ数年度で保育施設は大きく拡充されていること・急速な少子化と相まって定員が充足せず、閉園しているところも出てきていることもあり、古いデータは参考にならないのではないかと考えて利用しないこととしました
* [人口集中地区(DID)][人口集中地区]: 1kmメッシュと近い内容になるのではないか、カテゴリー変数で処理した郵便番号や市区町村コードとさほど大差はでないのかと考えて可視化した後に利用しないこととしました。後ほど考えてみると、郵便番号や市区町村コードをそのまま使用すると、CatBoostでは、とてもtreeが細分化されてしまい、大変重くて時間がかかるため(実際に学習時間が数時間以上かかっていました)、速度的なパフォーマンスの観点から、郵便番号や市区町村コードと人口集中地区(DID)を組み合わせると有効だったのではないかと思い、こちらは反省すべき点でした

## 3. モデルの開発

平方メートルあたり賃料を目的変数としました。このため、専有面積が極端に大きい・小さいなどの誤った数字である場合、大きく賃料がズレてしまうこと、欠損があるとそもそも賃料が算出できないこと、これらより`unit_area`(専有面積)ではなく`house_area`(建物面積/専有面積(代表))を使用することにしました。多くの方が`unit_area`を使ったのではないかと思いますが、次の2点

1. `house_area`に欠損がないこと
2. `unit_area` ≒ `house_area`であったこと

から、学習に用いるtrainデータは、`house_area`をベースにしました。やはり、建物面積/専有面積(代表)であることから、丹念に`house_area`, `unit_area`や`room_count`や`tag_id`などの関係性から調べて、手作業で修正しました。今、考えると、`COALESCE(unit_area, house_area)`とするべきであったと思います。

* 特徴量は、まず提供データの151の変数から99を選択しました。市区町村コードや郵便番号については、カラムが分かれてたため、結合した上でカテゴリー変数にするなどしました
* `tag_id`は使用せず、`statuses`は、切り出して全て`1`又は`NULL`の変数としました。件数が少ないものほぼ全件あるものについても除外せず全て利用しました
* 国土数値情報として使用することを決めた6ソースからの特徴量を追加しました
* その他は、データ分析より得られた情報から
    * メゾネットタイプと考えられるものを変数か
    * タワマンの中でも高そうな森ビルリビングの`building_id`をラベリングしたもの
    * シェアハウス・学生寮と考えられるラベル

これらを学習用の変数として準備し、LightGBMとCatBoostそれぞれ4-Foldのクロスバリデーションを二つのseedで用意して、4モデルを作成しました。
さらに、合計4モデルの出力をXGBoostのgblinearを使い、スタッキングすることとしました。

### 3.1 後処理

#### 前回データの活用

テストデータには、学習用データと同じ`unit_id`の物件が含まれることから、その場合には、当該`unit_id`の最も新しい賃料をそのまま紐づけることとしました。(33,118件) 中には、空室が埋まらないのか、値下げが繰り返されていたり、徐々に賃料が上がっているものもありましたが、ここは、割り切ってそのまま利用することにしました。

ここまでで、暫定スコア = 6,763.03, 最終スコア = 9,073.25となっていました。

#### 高額賃料の補正

クロスバリデーションによる高額賃貸物件の推定結果を確認すると、やや低めの金額となっていたことから、上位50件程度の推定値を確認し、全体的に5%程度かけることとしました。後処理を追加しました。

この補正処理で、暫定スコア = 6,713.17, 最終スコア = 8,878.69となりました。やはり、高額賃料の予測がどの程度あたるかで、このコンペのスコアが決まってくることがよくわかります。

作成したコードは、[githubのnotebook][notebook]をご覧ください。

## 4. 最後に

今回、いろいろと国土数値情報を活用して今回のコンペ、10位以内に入れいるといいなと思っていたのですが、後半あまり取り組む時間がなくなったこと、モデルがあまり良いものではなく学習に非常に時間がかかったことから、かなり手作業な後処理に逃げてしまったことはやはり順位があがらない結果になってしまいました(15位)。面積・賃料にも誤りが多々見つかりましたが、それ以上に、総戸数や階数などは、かなり間違いが含まれており、これらはタワマンなどの賃料推定の妨げになっていたのではないかと思います。そういった中で、今回、試すことができなかったもので、最もデータがおかしいものに効くのは、用途地域データではないかと思っていました。建蔽率や容積率の情報は、当然賃貸物件としては、あまり記載されないものと思われますので、これを使い、階数や建築可能面積があり得ないものを補正することができるはずだと考えました。

https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A29-2019.html

今まで国土数値情報は、[位置参照情報][位置参照情報]を少し使っただけだったのですが、今回のコンペにおいて、実際の不動産賃貸物件とその賃料データが分析を通じて、国土数値情報は大変高品質かつ使いやすいデータが公開されているのだということを強く認識しました。中には、オープンではないもののさまざまな協力によって公開されているものある点もすごいと思います。
運営に携わっている皆様、今回はコンペそのものだけにとどまらず、大変学びがある内容であり、さまざまな面で、大変感激いたしました。誠にありがとうございます。


[SIGNATE]: https://signate.jp 
[1484]: https://signate.jp/competitions/1484
[1337]: https://signate.jp/competitions/1337 
[55019880f7f351d2b15b]: https://qiita.com/kMUTOU/items/55019880f7f351d2b15b

[福祉施設]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-P14-2023.html
[人口集中地区]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A16-2020.html
[駅別乗降客数]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-S12-2022.html
[学校]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-P29-2023.html
[1kmメッシュ別将来推計人口（H30国政局推計）]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-mesh1000h30.html
[小学校区]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A27-2023.html
[地価公示]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-L01-2024.html
[医療機関]: https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-P04-2020.html
[位置参照情報]: https://nlftp.mlit.go.jp/cgi-bin/isj/dls/_choose_method.cgi
[notebook]: https://github.com/kMUTOU/gis_milt_challenge