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つに分けられます。
訓練データセットとテストデータセットにはそれぞれ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)で評価されます。
$$
\sqrt{\frac{1}{n}{\sum_{i=1}^{n}{(\log (Pred_i+1)-\log (Act_i+1))^2}}}
$$
回答用のsubmission.csvを用意する(エントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列(idとy以外)が含まれていた場合はエラーとなります。
提出ファイルは以下の列のみを必ず含んでください:
id,y
0, 25
1, 30
2, 4.5
3, 7
本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。
コード公開後3週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。
レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。
開始日 2020/06/26 0:00 JST
終了日 2020/8/11 0:00 JST
エントリー締め切り なし
※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。
原則外部データ使用は禁止としておりますが、正解データの入手につながらない場合は、下記承認プロセスにより使用できることといたします
注)ただし、コンペ終了まで10日をきってからの申請は禁止とします
公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年6月22日
はい。
最も精度の高い学習モデルを作成した優勝者には、賞金10万円を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。
可能です。チームページから作成いただけます。
こちらから作成いただけます。
コンペティション参加にはアカウント登録が必要となりますのでご注意ください。
Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。
このチュートリアルでは不動産取引データに対して
を行います。
まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありえますが、pandas
のread_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)
ヒストグラムとしては、グラフエリアの左側に1本だけ棒状グラフが出力されました。
ほぼ全てのレコードの取引金額が10,000未満であり、一部の少数のレコードが60,000近い値を取っているために、上記のように表示されました。
極端に他のレコードと値の異なるものは'外れ値'と言われ、回帰モデルに悪影響を及ぼす場合もあります。この'外れ値'をどのように扱うかは場合により異なります。
今回は、四分位法と呼ばれる外れ値の除外手法にもとづき取引金額90以上のレコードを除外しました。
#外れ値除外
train_data = train_data[train_data["y"] < (90)]
plt.hist(train_data['y'], bins=20)
外れ値を除外したヒストグラムでは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
#
'地域'
は欠損値が多数含まれていることがわかりました。欠損値が多い列を説明変数として採用すると、作成したモデルの汎用性が低くなる可能性があります。
データの形式を見ると、数値については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')
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年6月22日