Re:不動産取引価格予測

評価指標をRMSLEと改めて開催します

賞金: 100,000 参加ユーザー数: 294 3年以上前に終了
コンペティション概要

2020年春開催の「不動産取引価格予測」コンペティションについて、評価指標をRMSLE(Root Mean Squared Logarithmic Error)として再度開催いたします。


背景課題・目的

2020/2/26-4/27実施の「不動産取引価格予測」コンペティションでは、多くの方々にご参加いただきました。

評価指標としてRMSEを用いた点については、「high-endの外れ値予測コンペになる」
全体0.5%の予測に注力したほうが良さそう」で、といったご指摘もあり、仰る通り、と多くの反省も得られました。

そこで今回、評価指標をRMSLEと変え、同じデータセットを用いて再度開催いたします。
評価指標の重要性について、再認識できるコンペとなりますと幸いです。


賞金

1位 100,000円
※ 対象者には、コンペティション終了後 メールにてご連絡いたします。

締切

2020年8月11日 0:00 JST

謝辞:chun1182様、勝手ながらトピック拝借させていただきました。

ダウンロード

データをダウンロードするにはログインまたはユーザー登録して下さい

概要

コンペに使用するデータは3つに分けられます。

  • 訓練データ(train_data.csv)
  • テストデータ(test_data.csv)
  • 参照用 公示価格データ(published_land_price.csv)

訓練データセットとテストデータセットにはそれぞれ356,344レコードと34,844レコードのサンプルが含まれています。
訓練データは、土地情報と取引金額の値が各レコードごとに記載されています。機械学習モデルの構築に使用してください。

テストデータセットでは、取引金額のデータは存在しません。テストデータセットを使用して、どの程度新しいデータに対してモデルが適合しているかを確認し、各不動産の取引金額を予測してください。

また、提出ファイルの例に関しては、評価方法のタグを参照してください。


データの形式

データセットのカラムは以下の通りになっています。


訓練データ
カラム名 説明
種類 不動産の種類
(「宅地(土地/土地と建物)」「中古マンション等」「農地」「林地」など)
「宅地(土地)」:土地のみの取引
定義は下記の通り
「宅地(土地と建物)」:土地と建物等を一括して取引
「中古マンション等」:区分所有物件(戸単位)の取引
地域 地域名を記載
(「住宅地」など)
市区町村コード 総務省「全国地方公共団体コード」http://www.soumu.go.jp/denshijiti/code.html
都道府県名 都道府県名を記載
(今回は全て東京都)
市区町村名 市町村名を記載
地区名 地区名を記載
最寄駅:名称 駅名を記載
最寄駅:距離(分) 最寄駅からの最短距離を記載
間取り 間取りを記載
(「1LDK」「1DK」など)
面積 単位(m2):土地の面積を記載
土地の形状 「宅地(土地)」「宅地(土地と建物)」について、土地のおおよその形状を「正方形」、「ほぼ正方形」、「長方形」、「ほぼ長方形」、「台形」、「ほぼ台形」、「不整形」、「ほぼ整形」、「袋地等」の別に表示
間口 「宅地(土地)」「宅地(土地と建物)」について、土地の接道幅(m)(土地が道路に接している長さ)を表示
50m以上の場合は、「50m以上」と表示。
間口が把握できないものは空欄
延床面積 単位(m2)
「宅地(土地と建物)」の上物(建物)について、延床面積(㎡)を表示
200㎡未満は「5㎡刻み」とし、200㎡以上は上位3桁目を四捨五入し上位2桁を表示
2,000㎡以上の大規模取引については「2,000㎡以上」と表示
10㎡未満の小規模取引については「10㎡未満」と表示
建設年 和暦+年で記載(H20,S25など)
「宅地(土地と建物)」の上物(建物)及び「中古マンション等」の建物について、当該建物の建築年を表示
1945年以前は「戦前」と表示。建築年が把握できないものは空欄
建物の構造 建物構造略号は次の通り、数字はその階層を示す
(地下階層がある場合、地上階層にはFを地下階層にはBを付与)
SRC:鉄骨鉄筋コンクリート造
RC:鉄筋コンクリート造
S:鉄骨造
LS:軽量鉄骨造
B:ブロック造
W:木造
用途 「宅地(土地と建物) 」の上物(建物)及び「中古マンション等」の専有部分について、利用の現況
複合用途の場合は列記しています。用途が把握できないものは、空欄になっています。
(「住宅」「事務所」「店舗」「工場」「倉庫」「作業場」「駐車場」「その他」など)
今後の利用目的 今後の利用目的が把握できているものについて利用目的を記載(「住宅」「店舗」「事務所」「工場」「倉庫」「その他」など)
前面道路:方位 標準地の側道の方位による区別を表示
(東/西/南/北/南東/南西/北西/北東)
前面道路:種類 道路の種類については、以下に区分して表示。
道路法上の道路は「国道」、「都道府県道」、「市町村道」等
土地区画整理事業施行地区内の道路は、「区画街路」
私人が管理する道で、いわゆる私道と称されているものは、「私道」
その他の道は、「道路」
前面道路:幅員 単位(m)
都市計画 1低専:第一種低層住居専用地域
2低専:第二種低層住居専用地域
1中専:第一種中高層住居専用地域
2中専:第二種中高層住居専用地域
1住居:第一種住居地域
2住居:第二種住居地域
準住居:準住居地域
近商:近隣商業地域
商業:商業地域
準工:準工業地域
工業:工業地域
工専:工業専用地域
田園住:田園住居地域
建ぺい率 「宅地(土地)」「宅地(土地と建物)」「中古マンション等」について、建ぺい率(%)を表示
容積率 「宅地(土地)」「宅地(土地と建物)」「中古マンション等」について、指定容積率(%)を表示
取引時点 西暦+四半期で記載
改装 「未階層」「改装済み」を記載
取引の事情等 特別取引の事情があれば記載
y 取引金額(1,000,000円)


政府公示資料
カラム名 説明
経度 単位(秒)(例:501376.613=139.2712816°=139°16’16.613”)
座標値は世界測地系
緯度 同上
所在地コード 総務省「全国地方公共団体コード」
http://www.soumu.go.jp/denshijiti/code.html
用途 000:住宅地
003:宅地見込地
005:商業地
007:準工業地
009:工業地
010:市街化調整区域内の現況宅地
013:市街化調整区域内の現況林地
連番 一連番号情報
年次 最新選定年次(西暦)
前年所在地コード 総務省「全国地方公共団体コード」
前年用途 000:住宅地
003:宅地見込地
005:商業地
007:準工業地
009:工業地
010:市街化調整区域内の現況宅地
013:市街化調整区域内の現況林地
前年連番 前年の一連番号番号
市区町村名 市区町村名の名称
住居表示 住居表示または地番
行政 総務省「全国地方公共団体コード」http://www.soumu.go.jp/denshijiti/code.html
地積 単位(m2)
利用の概況 住宅/店舗/事務所/銀行/旅館/給油所/工場/倉庫/農地/山林/医院/空地/作業場/原野/その他/用材/雑木の17項目について基準地・標準地の利用の現況を表示
それぞれの項目について
「1:用途地域を示すもの」
「0:それ以外」
を順に17桁の数字で表示
(例:利用現況が「店舗」の場合、「01000000000000000」と表示)
利用状況表示 「利用の現況」が“その他”の場合の利用状況(自由記述)
建物構造 建物構造略号は次の通り、数字はその階層を示す(地下階層がある場合、地上階層にはFを地下階層にはBを付与)
SRC:鉄骨鉄筋コンクリート造
RC:鉄筋コンクリート造
S:鉄骨造
LS:軽量鉄骨造
B:ブロック造
W:木造
施設 水道/ガス/下水の3項目
1:施設の整備されているもの
0:施設の整備されていないもの
をそれぞれの項目について順にセットする(例:水道及びガスの施設がある場合は「110」となる)
形状区分 基準値の形状による区別を表示(「台形」「不整形」など)
間口(比率) 間口幅と奥行き幅の比率
(短い方を基準値10とした際の比率)
奥行(比率) 間口幅と奥行き幅の比率
(短い方を基準値10とした時の比率)
階層(地上) 階層数
階層(地下) 階層数
前面道路区分 標準地の前面道路による区別を表示
(国道/都道/道道/府道/県道/市道/区道/町道/村道/私道/農道/林道/区画街路/道路)
前面道路の方位区分 標準地の前面道路の方位による区別を表示
東/南/西/北/南東/南西/北西/北東
前面道路の幅員 単位(×10cm)
前面道路の駅前区分 標準地の前面道路の駅前による区別を表示
(「駅前広場」など)
前面道路の舗装状況 標準地の前面道路の舗装状況を表示
(「未舗装」など)
側道区分 側道/三方路/四方路/一方路・準角地/背面道/その他
側道方位区分 標準地の側道の方位による区別を表示
(東/西/南/北/南東/南西/北西/北東)
交通施設との近接区分 標準地の交通施設との近接状況を表示
(近接/接面/駅前広場接面)
周辺の土地の利用の概況 周辺の土地の利用の現況
(自由記述)
駅名 最寄り駅名を記載
駅距離 単位(m)、最寄り駅からの最短距離を記載
用途区分 1低専:第一種低層住居専用地域
2低専:第二種低層住居専用地域
1中専:第一種中高層住居専用地域
2中専:第二種中高層住居専用地域
1住居:第一種住居地域
2住居:第二種住居地域
準住居:準住居地域
近商:近隣商業地域
商業:商業地域
準工:準工業地域
工業:工業地域
工専:工業専用地域
田園住:田園住居地域
防火区分 防火:防火地域
準防:準防火地域
都市計画区分 市街化:市街化区域
調区:市街化調整区域
非線引:市街化区域及び市街化調整区域以外の都市計画区域
都計外:都市計画区域外
準都計:準都市計画区域
森林区分 地森計:地域森林計画対象区域
公園区分 国立公(普通):国立公園地域
国立公(2種):国立公園地域第二種特別区域
国立公(3種):国立公園地域第三種特別区域
国定公(普通):国定公園区域
国定公(2種):国定公園第二種特別区域
国定公(3種):国定公園第三種特別区域
建蔽率 単位(%)
容積率 単位(%)
共通地点区分 TRUE:共通地点である
FALSE:共通地点ではない
選定年次ビット 1:選定対象年である場合
0:それ以外」をそれぞれの年次についてセット
(例:平成5年のデータの場合は、11年分・11桁のデータとなる)
‘年数(和暦)’+価格 年次での公示価格(円/m2)
造形移動+’年数(和暦)’ 選定状況/住所漢字/地積/利用の現況/建物構造/供給施設/駅からの距離/用途区分/防火区分/都市計画区分/森林区分/公園区分/建ぺい率/容積率の14項目に対応する14桁の数値で示した。
数値は当該年次の選定状況を下記の通り示した。
1:継続
2:標準地・基準地番号変更
4:新設・選定替えで当該年追加
選定状況以外の項目は
1:前年から変更あり
0:前年から変更なし
をそれぞれの項目について順にセットする
評価指標

不動産取引金額(y)について、実数値で予測してくだい。
モデルの予測性能は評価関数RMSLE(Root Mean Squared Logarithmic Error)で評価されます。

  (RMSLEの評価値)

$$
\sqrt{\frac{1}{n}{\sum_{i=1}^{n}{(\log (Pred_i+1)-\log (Act_i+1))^2}}}
$$

  • 評価値は0以上の値をとり、精度が高いほど小さな値となります。

提出ファイルの形式

回答用のsubmission.csvを用意する(エントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列(idとy以外)が含まれていた場合はエラーとなります。

提出ファイルは以下の列のみを必ず含んでください:

  • id(テストデータセットと同じ順序)
  • y(予測された取引金額)

以下は提出ファイルの例です。
id,y
0, 25
1, 30
2, 4.5
3, 7

コンペティションルール

■Open Review Competition

本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。


賞金対象ユーザー

コンペ終了後1週間以内:
トピックにて、学習過程の分かるコードの公開をお願いいたします。 (簡易解説までつけていただけると助かります。)

コード公開後3週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。


レビュアー(ユーザーの皆様)
コード公開後3週間: 公開コードを確認いただき、チーティングが疑われる場合は、トピックを通して質疑の投稿をお願いいたします。

レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。

■順位決定ロジック
  1. コンペ期間中はPublicリーダーボード(以下LB)により暫定評価を、最終結果についてはPrivate LBにより評価します。
    ※ Private LBはコンペ終了と同時に表示されます
  2. スコアが同値の場合は、早い日時に提出いただいたユーザーが上位となります。
  3. コンペ終了後であっても、不正が発覚の際は、対象ユーザーは失格となり、全体の順位が繰り上がります。
    順位繰上げにより賞金対象者となられた場合は、繰上げ日より一週間以内に、トピックにてコードを公開いただき、「Open Review Competition」と同様のフローにて順位を確定させていただきます。
■タイムライン

開始日 2020/06/26 0:00 JST
終了日 2020/8/11 0:00 JST

エントリー締め切り なし

■システム利用
  • 参加者ごとに1つのアカウントでご参加ください
  • チーム参加の場合は、最大5名までエントリー可能です
  • 1日あたり、最大5回までの提出が可能です
■禁止事項
  • ユーザー間での情報共有
    コンペティションに関連するコード・データを、チーム外のユーザーと共有することはできません。全参加者が利用できる場合に限り、共有可能です。
  • 外部データの使用
    本コンペティションの基本情報/データから取得できるデータのみを用いてチャレンジして下さい。コンペ外データを用いて学習されたモデルの使用も禁止とします。
    ただし、トピック上で、運営より承認された外部データのみ、活用を許可いたします。承認プロセスについては、「外部データの活用申請について」をご確認ください。
    「不動産取引価格予測」コンペティションで承認済みのデータについてはご利用いただけます。

※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。

■外部データの使用申請について

原則外部データ使用は禁止としておりますが、正解データの入手につながらない場合は、下記承認プロセスにより使用できることといたします

  1. トピックを作成し、取得元情報とデータ(格納先URLも可)を添付
  2. 運営にて判断・承認

注)ただし、コンペ終了まで10日をきってからの申請は禁止とします

■運営からのお願い

公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。


「Re:不動産取引価格予測」コンペティション参加規約

コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。

第1条(適用)

  1. 参加者(第2条に定義します。)は、コンペティションに参加した時点で、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に同意したものとみなされます。
  2. 本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールは、コンペティションの終了後も参加者に適用されます。

第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。

  1. 「本コンペ」とは、当社ウェブサイト上で開催されるAI開発又はデータ分析等に関するコンペティションのうち、本規約に紐づく特定のコンペティションを意味します。
  2. 「主催者」とは、当社またはユーザーのうち、本コンペを主催する者を意味します。また、本コンペが、当社の顧客又は提携先の企業、学校その他の団体等がスポンサードするものである場合は、当該団体等も主催者の定義に含まれます。
  3. 「参加者」とは、ユーザーのうち、主催者側以外の立場で本コンペに参加する方を意味します。
  4. 「成果物」とは、本コンペにおいて参加者により開発される学習済みモデル、そのソースコード及び乱数シード等の設定値を意味します。
  5. 「入賞者」とは、当社より本コンペに入賞した旨の通知を受けた参加者を意味します。
  6. 「知的財産権」とは、著作権(著作権法第27条及び第28条に定める権利を含みます。)、特許権、実用新案権、商標権、意匠権、その他のノウハウ及び技術情報等の知的財産権(それらの権利を取得し、又はそれらの権利につき登録等を出願する権利を含みます。)を意味します。

第3条(権利の帰属)

  1. 本コンペで発生した成果物に関する知的財産権は、参加者に帰属します。

第4条(入賞者の義務)

  1. 入賞者は、本コンペで公開した成果物を、MITライセンスを適用し、商用利用の許諾条項及び著作権人格権の包括的不行使条項をライセンス条項に付与した形式で、オープンソースソフトウェアとして公開する義務を負うものとします。その前提として、入賞者は、成果物について本項に基づく方法でオープンソース化する権利を有していることを当社に対して表明保証するものとします。
    ※第三者が、授業・研修・セミナー等で活用できるようにするための規約となります。ご理解のほどよろしくお願いいたします。
  2. 当社は、以下の3点の確認が完了した時点で、本コンペの賞金または商品を、入賞者に対して授与するものとします。
    1. 入賞者が、前項に基づいて成果物のオープンソース化を実施したこと
    2. 入賞者が、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に違反していないこと
    3. 当社が定める方法による本人確認
  3. 当社は、入賞者が第1項に基づいてオープンソース化した成果物を、自由に商用利用することができます。

第5条(禁止事項)

  1. 参加者は、本コンペにおいて、以下の各号のいずれかに該当する行為を行ってはならないものとします。
    1. クラッキングやチート行為、なりすまし、盗用等の不正行為
    2. 第三者の知的財産権その他の権利を侵害する内容ないし態様で、参加者公開事項を公開する行為
    3. 主催者(当社以外の者に限ります。)に対する直接連絡、相談、依頼、勧誘、勧誘対応等の活動(但し、当社を介して当社が認めた方法により行うものは除きます。)
    4. 本コンペにおいて、当該コンペと直接関係のない成果物等を提出すること
    5. 本規約における参加者としての地位又は参加者としての権利義務について、譲渡、移転、担保設定、その他の処分をすること
    6. その他、本規約、参加ルール及び利用規約に違反する行為
  2. 参加者が前項に規定する禁止行為を行ったと当社が認める場合、当社は、当該参加者に事前に通知することなく、当該参加者の本コンペにおける失格処分、当社サービスの全部又は一部の利用停止、ユーザー登録の抹消、その他当社が必要と判断した措置をとることができるものとします。

第6条(本コンペの変更、中断、終了等)

  1. 当社は、参加者に事前の通知をすることなく本規約に基づく本コンペの開催内容の変更、本コンペの一時的な中断又は終了を行うことができます。
  2. 当社は、本条に基づき当社が行った措置により生じた結果及び損害について、一切の責任を負わないものとします。

第7条(損害賠償)

  1. 参加者は、本コンペに関連して、自らの責に帰すべき事由により、当社、主催者その他の第三者に損害を与えた場合には、その一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。
  2. 参加者が本規約の規定に違反したことにより主催者(当社を除きます。)その他の第三者が当社に対して何らかの訴え、異議、請求等がなされた場合において、当社から処理の要請がなされたときは、参加者は自己の責任と費用負担において、当社に代わって当該第三者との紛争を処理するとともに、当社がかかる訴え、異議、請求等により被った一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。

第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。

第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。

(制定)2020年6月22日

FAQ

このコンペティションでは賞金はでますか?

はい。
最も精度の高い学習モデルを作成した優勝者には、賞金10万円を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。

チームで参加できますか?

可能です。チームページから作成いただけます。

どこでアカウントをつくればいいですか?

こちらから作成いただけます。

コンペティション参加にはアカウント登録が必要となりますのでご注意ください。

コードを提出するにあたって Seed を固定する必要はありますか?

Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。

このチュートリアルでは不動産取引データに対して

  • データの読み込み
  • データの確認と前処理
  • 重回帰モデルの作成、学習
  • モデルの評価
  • テストデータに対する出力

を行います。


環境

  • python 3.6.8
  • numpy 1.17.3
  • pandas 0.25.2
  • matplotlib 3.1.1
  • sklearn 0.21.3

データの読み込み

まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありえますが、pandasread_csv関数はその中でも機能が豊富で、扱いやすいためこれを使います。
これを使うと、csvデータを読み込み、pandas.DataFrameにして返してくれます。

import pandas as pd

path = "/content/drive/My Drive/competition/ProbSpace/real_estate/train_data.csv"
train_data = pd.read_csv(path)

また、DataFrameには.head()というメソッドが定義されています。このコードを呼び出すとDataFrame先頭の数行を確認可能です。

train_data.head()
id 種類 地域 市区町村コード 都道府県名 市区町村名 地区名 最寄駅:名称 最寄駅:距離(分) 間取り
1 中古マンション等 NaN 13101 東京都 千代田区 飯田橋 飯田橋 1 2LDK
2 中古マンション等 NaN 13101 東京都 千代田区 飯田橋 飯田橋 5 1K
3 中古マンション等 NaN 13101 東京都 千代田区 飯田橋 飯田橋 3 1LDK
4 中古マンション等 NaN 13101 東京都 千代田区 飯田橋 飯田橋 5 1R
5 宅地(土地と建物) NaN 13101 東京都 千代田区 飯田橋 飯田橋 3 NaN

データの確認と前処理

訓練データにおける取引金額がどのような分布になっているか見てみましょう。各階級ごとの度数をヒストグラムを用いてプロットするのが以下のコードです。

%matplotlib inline
import matplotlib.pyplot as plt
plt.hist(train_data['y'], bins=20)

8de1caf8-b75a-41ef-95c4-d9bbef778ad5.png

ヒストグラムとしては、グラフエリアの左側に1本だけ棒状グラフが出力されました。

ほぼ全てのレコードの取引金額が10,000未満であり、一部の少数のレコードが60,000近い値を取っているために、上記のように表示されました。

極端に他のレコードと値の異なるものは'外れ値'と言われ、回帰モデルに悪影響を及ぼす場合もあります。この'外れ値'をどのように扱うかは場合により異なります。

今回は、四分位法と呼ばれる外れ値の除外手法にもとづき取引金額90以上のレコードを除外しました。

#外れ値除外
train_data = train_data[train_data["y"] < (90)]
plt.hist(train_data['y'], bins=20)

fd221eae-a3f7-4ba7-8343-8a8d6339031b.png

外れ値を除外したヒストグラムでは20,000,000辺りが最も多く、よ
り低い金額側に偏った分布が見られました。

20,000,000より高価格帯の取引金額は、比較的高い金額まで広範囲に分布していることがわかりました。

続いて、下記のコードを使用して使用するデータ全体の概観を確認します。

train_data.info()

各項目について欠損値以外('non-null')の値がどの程度含まれているか把握できます。また、データの形式についてもここで判別可能です。

#RangeIndex: 319449 entries, 0 to 356343
#Data columns (total 28 columns):
#id         319449 non-null int64
#種類       319449 non-null object
#地域       163547 non-null object
#市区町村コード 319449 non-null int64
#
#               ~中略~
#
#最寄駅:距離(分)309720 non-null object
#建築年           252049 non-null object
#![46d9cc9e-e783-4695-a1ca-c91c4b642c42.png](https://probspace-prd.s3-ap-northeast-1.amazonaws.com/uploads/user/4eb36816c6ae29d9b579a743baab11f8/images/UserImage_142/46d9cc9e-e783-4695-a1ca-c91c4b642c42.png =300x)

'地域'は欠損値が多数含まれていることがわかりました。欠損値が多い列を説明変数として採用すると、作成したモデルの汎用性が低くなる可能性があります。

データの形式を見ると、数値についてはfloat64/int64型になっていることが確認できます。
不動産の取引金額との関係性が強いと考えられる'最寄駅:距離(分)''建築年'のデータ形式を見るとobject型となっていました。
回帰モデルの説明変数として扱うためには、数値に変換する必要がありそうです。

'最寄駅:距離(分)''建築年'について、.value_counts()を使用して、中に含まれている値とその個数を確認します。

pd.set_option('display.max_rows', 100)
print(train_data['最寄駅:距離(分)'].value_counts())
print(train_data['建築年'].value_counts)
#最寄駅:距離(分) 個数
#6              25479
#4              23136
#
#    ~中略~
#
#12             10455
#15             10146
#30分?60分       9541
#16              8987
#
#    ~中略~
#
#1H?1H30         1305
#22               756
#27               278

'最寄駅:距離(分)'では、'30分?60分'などの数値以外の値が一部含まれていましたので適当な値に置換して数値として処理できるようにします。

train_data['最寄駅:距離(分)'] = train_data['最寄駅:距離(分)'].replace('30分?60分','45')
train_data['最寄駅:距離(分)'] = train_data['最寄駅:距離(分)'].replace('1H?1H30','75')
train_data['最寄駅:距離(分)'] = train_data['最寄駅:距離(分)'].replace('1H30?2H','105')
train_data['最寄駅:距離(分)'] = train_data['最寄駅:距離(分)'].replace('2H?','120')
train_data['最寄駅:距離(分)'] = pd.to_numeric(train_data['最寄駅:距離(分)'], errors='coerce')

続いて、'建築年'の出力結果についても確認します。

#建築年        個数
#平成9年       5120
#平成8年       4881 
#昭和59年      4802
#
#    ~中略~
#
#昭和30年       305
#昭和36年       271
#戦前           256
#昭和35年       242

'建築年'は、'平成''昭和'などの和暦表記になっている他、'戦前'という表記も見られました。こちらも適当な西暦4桁に置換します。

train_data['建築年'] = train_data['建築年'].dropna()
train_data['建築年'] = train_data['建築年'].str.replace('戦前','昭和20年')
train_data['年号'] = train_data['建築年'].str[:2]
train_data['和暦年数'] = train_data['建築年'].str[2:].str.strip('年').fillna(0).astype(int)
train_data.loc[train_data['年号']=='昭和','建築年(西暦)'] = train_data['和暦年数'] + 1925
train_data.loc[train_data['年号']=='平成','建築年(西暦)'] = train_data['和暦年数'] + 1988

続いて、数値データの正規化を行い、平均0、標準偏差1になるように変換を行います。
今回は、'容積率(%)''建築年(西暦)'について正規化をしました。

import numpy as np

l = ['最寄駅:距離(分)','容積率(%)','建築年(西暦)']
for name in l:
  mean = np.nanmean(train_data[name], axis=0)
  std = np.nanstd(train_data[name], axis=0)
  train_data[name] = (train_data[name] - mean)/std
train_data.describe()

.describe()を使用して、基本統計量を確認できます。平均0、標準偏差1に正規化できていることを確認します。

#     最寄駅:距離(分) 容積率(%)  建築年(西暦)
#count  3.097200e+05    3.143390e+05    2.520490e+05
#mean   5.934281e-13    -2.655652e-13    7.684944e-16
#std    1.000002e+00    1.000002e+00    1.000002e+00
#min    -1.099437e+00   -1.342352e+00   -3.862005e+00
#25%    -6.033779e-01   -7.053855e-01   -7.269815e-01
#50%    -2.065307e-01    -3.869024e-01   2.937237e-01
#    ~後略~

予測モデルの作成,学習

モデルに投入する目的変数(y),説明変数(X)を作成します。予測モデルを学習させる上でnull値の含まれたレコードを除外します。

今回は、'最寄駅:名称''最寄駅:距離(分)''容積率(%)''建築年(西暦)'を説明変数として用いました。

#使用する説明変数・目的変数を代入
model_input = train_data[['最寄駅:名称','最寄駅:距離(分)','容積率(%)','建築年(西暦)','y']]

#説明変数・目的変数についてnull値を含むレコードを除外
model_input = model_input.dropna(how='any', axis=0) 

#目的変数と説明変数を代入
X = model_input[['最寄駅:名称', '最寄駅:距離(分)', '容積率(%)', '建築年(西暦)']]
y = model_input['y']

このデータにはいくつかのカテゴリカルデータが含まれているので今のままでは機械学習モデルで扱いづらいです。そこで、カテゴリカルデータに対してget_dummies関数を使いone-hot表現に変換することができます。

今回は、'最寄駅:名称'のみone- hot表現に変換しました。drop_first=Trueを使用することで、多重共線性を弱めることができます。

#one-hot表現へ変換
X = pd.get_dummies(X, drop_first=True)

いよいよ予測モデルの作成に入ります。
model.fit('説明変数','目的変数')と記述することでモデルの学習が可能となります。目的変数を説明変数の組み合わせで説明可能な回帰モデルを作成できます。

#scikit-learnライブラリをimport
import sklearn
from sklearn.linear_model import LinearRegression as LR

#線形回帰モデルのインスタンス化
model = LR()

#予測モデルの作成
model.fit(X, y)

作成したモデルの係数と切片を見てみましょう。
model.coef_で係数の一覧、.intercept_で切片を見ることができます。

#各説明変数の係数
coeff = pd.DataFrame(X.columns)
coeff.columns = ['説明変数']
coeff['係数推定'] = model.coef_
print(coeff)
#0  最寄駅:距離(分)            -1.937073
#1  容積率(%)                -6.352881
#2   建築年(西暦)              6.468335
#3   最寄駅:名称_お花茶屋       -33.78402
#4   最寄駅:名称_こどもの国(神奈川)      -2.508123e
#               ~後略~
[647 rows x 2 columns]
#回帰モデルの切片
model.intercept_
#58.86466422497909

各説明変数の係数を比較することで、どの説明変数がどれほどの影響を与えていたか把握することができます。

各説明変数は、係数の値が正に大きいほど取引金額に対して正の寄与をしており、反対に負に大きいほど取引金額に対して負の寄与をしていると言えます。

上記の出力結果を見ると、'建築年(西暦)'の係数の値が正に大きく、比較的近年に建てられた不動産であるほど取引金額が高いことがわかります。
'容積率(%)'では係数が負に大きく、敷地面積に対する延べ床面積の割合が大きいほど、取引金額は低くなることがわかります。


モデルの評価

テストデータに対する回帰モデルの当てはまりの良さの指標としては'決定係数'などの指標が用いられます。
決定係数の値は、.scoreで確認が可能です。
1に近いほど回帰式で予測された値が実際のデータに当てはまることを表します。

#決定係数
model.score(X,y)
#0.312906449494207

今回作成したモデルの決定係数は0.31程度でした。

また、コンペの評価指標となるRMSLEについても出力が可能です。
今回は、sklearn.metricsに含まれるmean_squared_log_errorメソッドを使用します。
RMSLEは平均化された誤差の対数差を示す指標であり、0に近いほど見積もられる予測誤差が小さく予測精度が高いことを表します。
モデルを元にした予測値は、model.predict('説明変数')で表します。

mean_squared_log_errorメソッドでは、変数に負の値が含まれる場合エラーが発生するため、今回は0より小さい予測値については、0に変換しています。

# RMSLE値の出力
import numpy as np
from sklearn.metrics import mean_squared_log_error
y_true = model_input['y']
y_pred = model.predict(X)
y_pred = np.where(y_pred < 0, 0, y_pred)
print(np.sqrt(mean_squared_log_error(y_true, y_pred)))
#0.5408554003477739

今回作成したモデルのRMSLEは0.541程度でした。


テストデータに対する出力

最後に、作成したモデルを使用してテストデータでの取引金額を予測します。

テストデータの説明変数については予め、上記でモデルに学習させたデータの説明変数と同様の前処理をする必要があります。

path_test = "/content/drive/My Drive/competition/ProbSpace/real_estate/test_data.csv"
test_data = pd.read_csv(path_test)

print(test_data['最寄駅:距離(分)'].value_counts())

#最寄駅:距離(分)の変換
test_data['最寄駅:距離(分)'] = test_data['最寄駅:距離(分)'].replace('30分?60分','45')
test_data['最寄駅:距離(分)'] = test_data['最寄駅:距離(分)'].replace('1H?1H30','75')
test_data['最寄駅:距離(分)'] = test_data['最寄駅:距離(分)'].replace('1H30?2H','105')
test_data['最寄駅:距離(分)'] = test_data['最寄駅:距離(分)'].replace('2H?','120')
test_data['最寄駅:距離(分)'] = pd.to_numeric(test_data['最寄駅:距離(分)'], errors='coerce')

#建築年を数値データとして処理
test_data['建築年'] = test_data['建築年'].dropna()
test_data['建築年'] = test_data['建築年'].str.replace('戦前','昭和20年')
test_data['年号'] = test_data['建築年'].str[:2]
test_data['和暦年数'] = test_data['建築年'].str[2:].str.strip('年').fillna(0).astype(int)
test_data.loc[test_data['年号']=='昭和','建築年(西暦)'] = test_data['和暦年数'] + 1925
test_data.loc[test_data['年号']=='平成','建築年(西暦)'] = test_data['和暦年数'] + 1988

l2 = ['最寄駅:距離(分)','容積率(%)','建築年(西暦)']
for name in l2:
  mean = np.nanmean(test_data[name], axis=0)
  std = np.nanstd(test_data[name], axis=0)
  test_data[name] = (test_data[name] - mean)/std 

#使用する説明変数・目的変数を代入
model_input_test = test_data[['最寄駅:名称','最寄駅:距離(分)','容積率(%)','建築年(西暦)']]

#説明変数・目的変数についてnull値を含むレコードを除外
model_input_test = model_input_test.dropna(how='any', axis=0) 

# 目的変数と説明変数を代入
X_test = model_input_test

# one hot表現へ変換
X_test = pd.get_dummies(X_test, drop_first=True)

モデルで使うデータとテストデータのカラム数が違うとエラーが発生するので、モデルの説明変数について事前に工夫が必要です。

今回は、学習データとテストデータで重複する説明変数のみを利用して学習と予測を実施します。

また、下記のコードでは訓練データで学習させた説明変数の中で、テストデータに含まれないについても列名を出力しています。

col_list = X.columns.tolist() 
col_test_list = X_test.columns.tolist()
col_joint = col_list + col_test_list
col_dup = [x for x in set(col_joint) if col_joint.count(x) > 1]

col_list_p = [x for x in set(col_joint) if col_list.count(x) == 0]
print(col_list_p)
#出力['最寄駅:名称_沢井']

'最寄駅:名称_沢井'は、取引金額に影響を及ぼす可能性がありますが、テストデータには含まれません。そのため、今回の予測の上ではモデルに学習させてもあまり意味はないと考え、学習させるデータから該当するレコードを除外しました。

その上で訓練データについて再度学習させて、モデルを作成します。

X_test=X_test[X_test['最寄駅:名称_沢井']!=1]

X_train_fix = X[col_dup]
X_test_fix = X_test[col_dup]

model.fit(X_train_fix, y)

先ほど使用したmodel.predict('説明変数')'説明変数'にテストデータの値を代入することで、テストデータの予測値を算出することができます。

下記のようにして、提出用のsubmission.csvを出力することが可能です。

test_predicted = model.predict(X_test_fix)
submit_df = pd.DataFrame({'y': test_predicted})
submit_df.index.name = 'id'
submit_df.index = submit_df.index + 1
submit_df.to_csv('submission.csv')

「Re:不動産取引価格予測」コンペティション参加規約

コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。

第1条(適用)

  1. 参加者(第2条に定義します。)は、コンペティションに参加した時点で、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に同意したものとみなされます。
  2. 本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールは、コンペティションの終了後も参加者に適用されます。

第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。

  1. 「本コンペ」とは、当社ウェブサイト上で開催されるAI開発又はデータ分析等に関するコンペティションのうち、本規約に紐づく特定のコンペティションを意味します。
  2. 「主催者」とは、当社またはユーザーのうち、本コンペを主催する者を意味します。また、本コンペが、当社の顧客又は提携先の企業、学校その他の団体等がスポンサードするものである場合は、当該団体等も主催者の定義に含まれます。
  3. 「参加者」とは、ユーザーのうち、主催者側以外の立場で本コンペに参加する方を意味します。
  4. 「成果物」とは、本コンペにおいて参加者により開発される学習済みモデル、そのソースコード及び乱数シード等の設定値を意味します。
  5. 「入賞者」とは、当社より本コンペに入賞した旨の通知を受けた参加者を意味します。
  6. 「知的財産権」とは、著作権(著作権法第27条及び第28条に定める権利を含みます。)、特許権、実用新案権、商標権、意匠権、その他のノウハウ及び技術情報等の知的財産権(それらの権利を取得し、又はそれらの権利につき登録等を出願する権利を含みます。)を意味します。

第3条(権利の帰属)

  1. 本コンペで発生した成果物に関する知的財産権は、参加者に帰属します。

第4条(入賞者の義務)

  1. 入賞者は、本コンペで公開した成果物を、MITライセンスを適用し、商用利用の許諾条項及び著作権人格権の包括的不行使条項をライセンス条項に付与した形式で、オープンソースソフトウェアとして公開する義務を負うものとします。その前提として、入賞者は、成果物について本項に基づく方法でオープンソース化する権利を有していることを当社に対して表明保証するものとします。
    ※第三者が、授業・研修・セミナー等で活用できるようにするための規約となります。ご理解のほどよろしくお願いいたします。
  2. 当社は、以下の3点の確認が完了した時点で、本コンペの賞金または商品を、入賞者に対して授与するものとします。
    1. 入賞者が、前項に基づいて成果物のオープンソース化を実施したこと
    2. 入賞者が、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に違反していないこと
    3. 当社が定める方法による本人確認
  3. 当社は、入賞者が第1項に基づいてオープンソース化した成果物を、自由に商用利用することができます。

第5条(禁止事項)

  1. 参加者は、本コンペにおいて、以下の各号のいずれかに該当する行為を行ってはならないものとします。
    1. クラッキングやチート行為、なりすまし、盗用等の不正行為
    2. 第三者の知的財産権その他の権利を侵害する内容ないし態様で、参加者公開事項を公開する行為
    3. 主催者(当社以外の者に限ります。)に対する直接連絡、相談、依頼、勧誘、勧誘対応等の活動(但し、当社を介して当社が認めた方法により行うものは除きます。)
    4. 本コンペにおいて、当該コンペと直接関係のない成果物等を提出すること
    5. 本規約における参加者としての地位又は参加者としての権利義務について、譲渡、移転、担保設定、その他の処分をすること
    6. その他、本規約、参加ルール及び利用規約に違反する行為
  2. 参加者が前項に規定する禁止行為を行ったと当社が認める場合、当社は、当該参加者に事前に通知することなく、当該参加者の本コンペにおける失格処分、当社サービスの全部又は一部の利用停止、ユーザー登録の抹消、その他当社が必要と判断した措置をとることができるものとします。

第6条(本コンペの変更、中断、終了等)

  1. 当社は、参加者に事前の通知をすることなく本規約に基づく本コンペの開催内容の変更、本コンペの一時的な中断又は終了を行うことができます。
  2. 当社は、本条に基づき当社が行った措置により生じた結果及び損害について、一切の責任を負わないものとします。

第7条(損害賠償)

  1. 参加者は、本コンペに関連して、自らの責に帰すべき事由により、当社、主催者その他の第三者に損害を与えた場合には、その一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。
  2. 参加者が本規約の規定に違反したことにより主催者(当社を除きます。)その他の第三者が当社に対して何らかの訴え、異議、請求等がなされた場合において、当社から処理の要請がなされたときは、参加者は自己の責任と費用負担において、当社に代わって当該第三者との紛争を処理するとともに、当社がかかる訴え、異議、請求等により被った一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。

第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。

第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。

(制定)2020年6月22日