機械学習を使ってお買い得中古物件を探す~前処理編~
前回はこちら maxonblog.hatenablog.com
前回同様、本日はこちらのサイトにアイデアを頂いて進めていきます。 www.analyze-world.com
データ読み込み&確認
まずはなにはともあれデータの読み込み、確認です。pandas
便利ですね。
方法
Pandas
:Series
のattributionである、strを使っていきます。正規表現も使えます。列全体に対して処理を行うことができるので便利です。
split(x, expand)
xを検索、ヒットしたらxで左右に分ける。expand=True
とすると、複数列を持つDataFrame
としてくれます。expand=False
とすると単列の中にすべて入れこまれます。逆に、どういう用途でどうやって使うんだろう。。。replace(x,y)
xを検索、yに入れ替えます。xに正規表現を使っています。正規表現は()
で囲んで使いましょう。contains(x)
xを含む行をindex(かな?)のSeriesで返します。DataFrameの列指定に入れ込むことで、xを含む行だけにすることができます。extract(x)
各要素からxを検索して、matchしたものを各要素に返します。Seriesで返ってきます。pandas.to_datetime()
文字列で記述された日付をdatetime型に変換します。
import pandas as pd import datetime as dt from pandas import DataFrame df = pd.read_csv("./Data/suumoData.csv", encoding="utf-8") df.head()
name | price | location | station | size | floor | terrace | construction | |
---|---|---|---|---|---|---|---|---|
0 | シャトレーイン東京・笹塚 | 770万円 | 東京都渋谷区笹塚1 | 京王線「笹塚」徒歩5分 | 14.52m2(4.39坪)(壁芯) | ワンルーム | - | 1987年3月 |
1 | 高幡台住宅 26号棟 | 780万円 | 東京都日野市三沢 | 京王線「高幡不動」徒歩11分 | 48.85m2(14.77坪)(壁芯) | 2LDK | 6m2 | 1970年7月 |
2 | ライオンズマンション西日暮里北 | 880万円 | 東京都荒川区東尾久2-44-16 | 日暮里・舎人ライナー「赤土小学校前」徒歩3分 | 19.6m2(壁芯) | 1K | 3.36m2 | 1989年10月 |
3 | ライオンズガーデン町田の丘 | 900万円 | 東京都町田市図師町 | JR横浜線「町田」バス20分停歩3分 | 51.87m2(壁芯) | 3LDK | 7.41m2 | 1993年9月 |
4 | 武蔵小金井フラワーホーム | 980万円 | 東京都小金井市緑町5 | JR中央線「武蔵小金井」徒歩12分 | 26.22m2(壁芯) | ワンルーム | 7m2 | 1977年7月 |
データ整形
路線・駅名・駅までの距離
路線、駅名、徒歩時間を切り分けます。
"歩"、"「"といったところで切れるので、splitで分けた後replaceで不要な文字("」"以降、"分")を削除していきます。他の方法があったかな。最後に大元dfにくっつけることを忘れないようにしましょう。
尚、今更ながら、Jupyterだと、大元のデータを処理してしまうと微調整して再処理するとエラーを吐くので、input用変数とoutput用変数は分けるべきだったようです。
いらないデータはdrop
で削除し、最後にconcat
でもとのデータ(df)にくっつけます。
df_split_1 = df["station"].str.split("歩", expand=True) df_split_1 = pd.concat([df_split_1[0].str.split("「", expand=True), df_split_1[1]], axis=1) df_split_1.columns = ["line", "station", "time"] df_split_1["station"] = df_split_1["station"].str.replace("」(.)", "") df_split_1["time"] = df_split_1["time"].str.replace("分", "") df.drop(['station'], axis=1, inplace=True) df = pd.concat((df, df_split_1),axis=1) df.head()
name | price | location | size | floor | terrace | construction | line | station | time | |
---|---|---|---|---|---|---|---|---|---|---|
0 | シャトレーイン東京・笹塚 | 770万円 | 東京都渋谷区笹塚1 | 14.52m2(4.39坪)(壁芯) | ワンルーム | - | 1987年3月 | 京王線 | 笹塚 | 5 |
1 | 高幡台住宅 26号棟 | 780万円 | 東京都日野市三沢 | 48.85m2(14.77坪)(壁芯) | 2LDK | 6m2 | 1970年7月 | 京王線 | 高幡不動 | 11 |
2 | ライオンズマンション西日暮里北 | 880万円 | 東京都荒川区東尾久2-44-16 | 19.6m2(壁芯) | 1K | 3.36m2 | 1989年10月 | 日暮里・舎人ライナー | 赤土小学校前 | 3 |
3 | ライオンズガーデン町田の丘 | 900万円 | 東京都町田市図師町 | 51.87m2(壁芯) | 3LDK | 7.41m2 | 1993年9月 | JR横浜線 | 町田ス20分停 | 3 |
4 | 武蔵小金井フラワーホーム | 980万円 | 東京都小金井市緑町5 | 26.22m2(壁芯) | ワンルーム | 7m2 | 1977年7月 | JR中央線 | 武蔵小金井 | 12 |
住所を修正。東京23区内のみの分析にする。
本当は23区外も分析の対象外にしたかったのですが、規則性が薄そうで手間がかかりそうだったのでまずは東京23区を対象とすべく、"区"を含む行だけにして処理を進めます。エリアまでほしかったので、区以降の住所の中の地域名をaddressとして残します。
r"([^\d]*)"
は、正規表現で数字「以外」を抜き出しています。
df = df[df["location"].str.contains("区")] temp_1 = df["location"].str.replace("東京都", "").str.split("区", expand=True) temp_1.columns = ["ku", "address"] temp_1 = temp_1["address"].str.extract(r"([^\d]*)") df = pd.concat((df, temp_1), axis=1) df.head()
name | price | location | size | floor | terrace | construction | line | station | time | address | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | シャトレーイン東京・笹塚 | 770万円 | 東京都渋谷区笹塚1 | 14.52m2(4.39坪)(壁芯) | ワンルーム | - | 1987年3月 | 京王線 | 笹塚 | 5 | 笹塚 |
2 | ライオンズマンション西日暮里北 | 880万円 | 東京都荒川区東尾久2-44-16 | 19.6m2(壁芯) | 1K | 3.36m2 | 1989年10月 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | 東尾久 |
8 | プレール新中野 | 1280万円 | 東京都中野区中央4 | 17.45m2(5.27坪)(壁芯) | 1K | 2.5m2 | 1990年3月 | 東京メトロ丸ノ内線 | 新中野 | 3 | 中央 |
9 | ニュー荻窪フラワーホーム | 1280万円 | 東京都杉並区桃井3 | 31.44m2(9.51坪)(壁芯) | 1DK | 5.51m2 | 1972年2月 | JR中央線 | 荻窪 | 18 | 桃井 |
10 | ライオンズマンション西日暮里北 | 1380万円 | 東京都荒川区東尾久2 | 44.62m2(壁芯) | 2DK | 11.01m2 | 1989年10月 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | 東尾久 |
広さのm2以降を削除する
数字として扱いたいので、いらない文字は削除しましょう。
df["size"] = df["size"].replace("m2(.*)", "", regex=True) df["terrace"] = df["terrace"].replace("m2(.*)", "", regex=True)
価格を使えるデータに整形する
注釈とか幅をもたせたデータ(~、・、※を含むデータ)は削除し、x億円以上の部分は10,000かけて単位をずらして万円とつなげる、その後、intに変換します。
df = df[~df["price"].str.contains("~|〜|・|〜|~|※")] df_split_1 = pd.DataFrame(df["price"].str.extract('(.*億)').str.replace("億", "").fillna(0).astype(int) * 10000) df_split_2 = pd.DataFrame(df["price"].str.replace('(.*億)', "").str.replace("万|円", "").str.extract(r"(\d+)").fillna(0).astype(int)) df["price"] = df_split_1 + df_split_2 df.head()
name | price | location | size | floor | terrace | construction | line | station | time | address | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | シャトレーイン東京・笹塚 | 770 | 東京都渋谷区笹塚1 | 14.52 | ワンルーム | - | 1987年3月 | 京王線 | 笹塚 | 5 | 笹塚 |
2 | ライオンズマンション西日暮里北 | 880 | 東京都荒川区東尾久2-44-16 | 19.6 | 1K | 3.36 | 1989年10月 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | 東尾久 |
8 | プレール新中野 | 1280 | 東京都中野区中央4 | 17.45 | 1K | 2.5 | 1990年3月 | 東京メトロ丸ノ内線 | 新中野 | 3 | 中央 |
9 | ニュー荻窪フラワーホーム | 1280 | 東京都杉並区桃井3 | 31.44 | 1DK | 5.51 | 1972年2月 | JR中央線 | 荻窪 | 18 | 桃井 |
10 | ライオンズマンション西日暮里北 | 1380 | 東京都荒川区東尾久2 | 44.62 | 2DK | 11.01 | 1989年10月 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | 東尾久 |
建築日を使えるデータにする
まずは建築日(完工日?)を日付データに変換します。年月までの情報しかないので、各月の1日に完工したと設定し、日付データとします。
次に、完工日からデータ取得日までの日数のデータとするため、引き算。日付のまま保持するより、int型に変換したほうがよかったかな、と思いはじめました。
df["construction"] = pd.to_datetime(df["construction"] + "1日", format="%Y年%m月%d日") temp_1 = pd.to_datetime(dt.date.today()) - df["construction"] temp_1 = temp_1.rename("age") df = pd.concat((df, temp_1), axis=1) df.head()
name | price | location | size | floor | terrace | construction | line | station | time | address | age | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | シャトレーイン東京・笹塚 | 770 | 東京都渋谷区笹塚1 | 14.52 | ワンルーム | - | 1987-03-01 | 京王線 | 笹塚 | 5 | 笹塚 | 12401 days |
2 | ライオンズマンション西日暮里北 | 880 | 東京都荒川区東尾久2-44-16 | 19.6 | 1K | 3.36 | 1989-10-01 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | 東尾久 | 11456 days |
8 | プレール新中野 | 1280 | 東京都中野区中央4 | 17.45 | 1K | 2.5 | 1990-03-01 | 東京メトロ丸ノ内線 | 新中野 | 3 | 中央 | 11305 days |
9 | ニュー荻窪フラワーホーム | 1280 | 東京都杉並区桃井3 | 31.44 | 1DK | 5.51 | 1972-02-01 | JR中央線 | 荻窪 | 18 | 桃井 | 17908 days |
10 | ライオンズマンション西日暮里北 | 1380 | 東京都荒川区東尾久2 | 44.62 | 2DK | 11.01 | 1989-10-01 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | 東尾久 | 11456 days |
Floor(部屋数)の修正
Floor(部屋数)を使えるデータに変換します。ここは割と工夫をした点です。2LDKとか3LDKとかだけでなく、11LDKとか、S(納戸)とか変なデータが多かったので、まずはどういうフレームワークで分析するか考えました。
結論として、Room、Living、Dining、Kitchen、Service、及び部屋数のデータを残すことに。手順は以下の通りです。
- 部屋数の数字をextract:2LDKの"2"の部分ですね。
- L、D、Kの数を数える。2つLivingがある部屋は、2LLDKという表記になっています。
- Sについては、"S"の前だけ抜き出して、その文字列に含む数字をSの数とします。+2S(納戸)とかいう不思議な表記になっているためです。
- 最後に、全部の部屋数を足した部屋数列を作成。
ついでに、今日の日付の情報も入れておきましょう。
これらを元のデータにくっつけておしまいです。
df = df.reset_index(drop=True) temp_1 = pd.Series(df["floor"]).str.replace("(.*ワンルーム)", "1") rldks: DataFrame = pd.DataFrame([ temp_1.str.extract(r"(\d\d*)"), temp_1.str.count("L"), temp_1.str.count("D"), temp_1.str.count("K"), temp_1.str.extract(r"(\+.*S)").fillna("0").str.extract(r"(\d+)").fillna(1)], index=["room", "Living", "Dining", "Kitchen", "Service"] ).astype(int).T temp2 = pd.DataFrame({"No.ofRooms": rldks.sum(axis=1)}) today = pd.Series([dt.date.today() for i in range(len(df))]) df = pd.concat((df, rldks, temp2,today), axis=1) df.head()
name | price | location | size | floor | terrace | construction | line | station | time | ... | Service | No.ofRooms | 0 | room | Living | Dining | Kitchen | Service | No.ofRooms | 0 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | シャトレーイン東京・笹塚 | 770 | 東京都渋谷区笹塚1 | 14.52 | ワンルーム | - | 1987-03-01 | 京王線 | 笹塚 | 5 | ... | 0 | 1 | 2021-02-11 | 1 | 0 | 0 | 0 | 0 | 1 | 2021-02-11 |
1 | ライオンズマンション西日暮里北 | 880 | 東京都荒川区東尾久2-44-16 | 19.6 | 1K | 3.36 | 1989-10-01 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | ... | 0 | 2 | 2021-02-11 | 1 | 0 | 0 | 1 | 0 | 2 | 2021-02-11 |
2 | プレール新中野 | 1280 | 東京都中野区中央4 | 17.45 | 1K | 2.5 | 1990-03-01 | 東京メトロ丸ノ内線 | 新中野 | 3 | ... | 0 | 2 | 2021-02-11 | 1 | 0 | 0 | 1 | 0 | 2 | 2021-02-11 |
3 | ニュー荻窪フラワーホーム | 1280 | 東京都杉並区桃井3 | 31.44 | 1DK | 5.51 | 1972-02-01 | JR中央線 | 荻窪 | 18 | ... | 0 | 3 | 2021-02-11 | 1 | 0 | 1 | 1 | 0 | 3 | 2021-02-11 |
4 | ライオンズマンション西日暮里北 | 1380 | 東京都荒川区東尾久2 | 44.62 | 2DK | 11.01 | 1989-10-01 | 日暮里・舎人ライナー | 赤土小学校前 | 3 | ... | 0 | 4 | 2021-02-11 | 2 | 0 | 1 | 1 | 0 | 4 | 2021-02-11 |
5 rows × 26 columns
終わり
さて、次は楽しい分析です!Pythonだとデータ分析は難しいのでRでやるかなー。
df.head(5) df.tail(5)
name | price | location | size | floor | terrace | construction | line | station | time | address | age | room | Living | Dining | Kitchen | Service | No.ofRooms | 0 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
17970 | フォレセーヌ赤坂檜坂 | 24000 | 東京都港区赤坂6 | 88.13 | 2LDK | 8.49 | 2016-01-01 | 東京メトロ日比谷線 | 六本木 | 6 | 赤坂 | 1868 days | 2 | 1 | 1 | 1 | 0 | 5 | 2021-02-11 |
17971 | パークコート青山ザ・タワー | 25800 | 東京都港区南青山2 | 82.79 | 2LDK | - | 2017-12-01 | 東京メトロ銀座線 | 青山一丁目 | 3 | 南青山 | 1168 days | 2 | 1 | 1 | 1 | 0 | 5 | 2021-02-11 |
17972 | パークハウス多摩川 | 29000 | 東京都大田区下丸子4 | 307.68 | 1LDK | 56.4 | 1993-02-01 | 東急多摩川線 | 鵜の木 | 7 | 下丸子 | 10237 days | 1 | 1 | 1 | 1 | 0 | 4 | 2021-02-11 |
17973 | ブランズ六本木ザ・レジデンス | 30000 | 東京都港区六本木4 | 101.97 | 2LDK | 5.22 | 2019-01-01 | 都営大江戸線 | 六本木 | 3 | 六本木 | 772 days | 2 | 1 | 1 | 1 | 0 | 5 | 2021-02-11 |
17974 | パークコート乃木坂ザ・タワー | 33000 | 東京都港区南青山1 | 100.65 | 2LDK | 11.42 | 2019-02-01 | 東京メトロ千代田線 | 乃木坂 | 2 | 南青山 | 741 days | 2 | 1 | 1 | 1 | 0 | 5 | 2021-02-11 |