テストエンジニアが機械学習してみた備忘録

広島とジト目が好きなテストエンジニアが機械学習に手を出した備忘録。

「機械学習を使って東京23区のお買い得賃貸物件を探してみた」を京都駅周辺でやってみる 〜前処理&データ探索編〜

というわけで前回の続きで、 Shoさんのブログの内容をなぞっていきたいと思います。

www.analyze-world.com

www.analyze-world.com

実行環境

前処理

思ったより時間がかかってしまいましたが、前処理に関してはShoさんのブログの内容とほぼ同等のことをしています。違いは以下の点。

  • 住所は市 or 郡とそれ以降の2列に分割
    • ただし京都市のみ区とそれ以降の2列
  • 最寄駅がバスで○分のようなデータは弾く(NaNにする)
  • 建物の階数は地下と地上を合計

データ探索

前処理したデータを見ていきますが、グラフを自由自在に操るのって結構大変…

pandasのplotやseabornはmatplotlibをラップしたものという理解ですが、 目的に応じてどの方法が1番楽なのかとかがよくわからないのでこの機会に整理しながら進めます。 とは言え、グラフを綺麗に描くことは本質ではないのでそこそこに…

なお、以下では前処理したデータを変数dfにデータフレームとして保持しています。出てくるカラムの意味は以下です。

  • address_1
  • rent
    • 家賃+共益費
  • room_num
    • 部屋の数(1Kや2DKの数値部分)
  • storeroom, living, dining, kitchen
    • それぞれS、L、D、Kが含まれるかを表すダミー変数

地域毎の物件数

seabornのcountplotを使えば一発ですが、ソートして描画する方法がわからない…orz orderオプションで描画順を指定できるようなので、データフレームから直接集計した結果を指定するという二度手間でゴリ押し。

import seaborn as sns
address = df.address_1.value_counts().sort_values(ascending=False)
sns.countplot(y='address_1', data=df, order=address.index, labe)

f:id:gratk:20171125142122p:plain

最寄駅が京都駅まで30分以内の単身者向け物件は伏見区に多いようです。 続いて下京区、中京区、左京区右京区…と続き、1〜8位を京都市が占める結果に。まぁ、当たり前と言えば当たり前ですが。 宇治市京田辺市を間に挟んで東山区、北区とつづきます。観光地だったりファミリー層向けだったりなイメージなので妥当でしょうか。

地域毎の家賃+共益費(箱ひげ図)

つづいて地域毎の家賃を見ていきます。以下で箱ひげ図(ボックスプロット)を作成します。描画順は中央値でソートします。

rent_median = df.groupby('address_1').rent.median().sort_values(ascending=False)
sns.boxplot(x='rent', y='address_1', data=df, order=rent_median.index)

f:id:gratk:20171125142148p:plain

箱ひげ図の外れ値は、IRQ(四分位範囲)の1.5倍を第1四分位点から引いた値を下限、 第3四分位点に足した値を上限とした閉区間の外とすることが一般的だそうです。( 4-3. 外れ値検出のある箱ひげ図 | 統計学の時間 | 統計WEB)

seabornではIRQへの倍率を引数whisで指定でき、デフォルトは1.5になっているようです。 (seaborn.boxplot — seaborn 0.8.1 documentation)

そもそも家賃10万円以内で検索しているので、めちゃくちゃ家賃が高いような外れ値はありません。 中央値が高いのは中京区、左京区下京区京都市中心部が多いです。 向日市城陽市もトップに食い込んできていますが、そもそも物件数が少ないという要因もありそうです。 伏見区は物件数ではトップだったものの、中央値で見ると下位なので、比較的リーズナブルな範囲で選択肢が多くなりそうです。 また、下限以下の外れ値が存在するのは左京区のみということも読み取れます。

地域毎の家賃+共益費(ヒストグラム

分布の形についてはseabornのdistplotを用います。 arrayやSeriesなどを放り込めば、ヒストグラム確率密度関数を出してくれます。 ヒストグラムのみでいい場合はkdeを、確率密度関数のみでよいのであればhistをそれぞれFalseにすればよいです。

複数のグラフを重ねて描画して凡例をつけるにはFacetGridを用いるようです。

nekoyukimmm.hatenablog.com

df1 = df[(df.address_1 == '中京') | (df.address_1 == '北') | (df.address_1 == '伏見')].loc[:, ['rent', 'address_1']]
df1.columns = ['rent', '地区']
g = sns.FacetGrid(df1, hue='地区', size=5)
g.map(sns.distplot, 'rent', kde=False)
g.add_legend()

f:id:gratk:20171125112541p:plain

Shoさんのブログの東京23区の場合と同様に、家賃の中央値が高い地域の方が分散が大きいことがわかります。 このあと地図上へのプロットを行なっていますが、今回は割愛します。

部屋数と家賃(散布図)

今回は単身者向けということで、部屋数を2部屋まで(2Kとか1LDK)に絞っているため、 部屋数だけで見ると1 or 2になってしまうのであまり意味がなさそう。 というわけで単純にS、L、D、Kを1部屋カウントしてしまいます。 散布図の描画にはregplotを用います。

df2 = df.loc[:, ['rent', 'room_num', 'kitchen', 'dining', 'living', 'storeroom']]
df2['rooms'] = df2['room_num'] + df2['kitchen'] + df2['dining'] + df2['living'] + df2['storeroom']
sns.regplot(x='rooms', y='rent', data=df2)

f:id:gratk:20171125115137p:plain

部屋数の換算が雑なものの、一応回帰線を見ると部屋数に応じて家賃があがるようです。 部屋数4に家賃が安い物件があるので見てみます。

df3['rooms'] = df2.rooms
df3[(df3.rooms == 4) & (df3.rent < 60000)]

結果を見ると最寄が玉水駅(綴喜郡)、亀岡市宇治市だったので、単純に少し京都駅から遠いという話のようです。 一応、玉水駅から京都駅まではJR奈良線で30分だったので、検索条件には合致しています。

まとめ

「前処理」でpandasによるデータ処理を、「データ探索」でグラフの描画を実際に試してみました。 使いこなすにはまだまだですが、やはり読むだけじゃなくて実際のデータをいじると使い方が身につく印象です。 次回からいよいよ予測モデルの構築をやってみます。