Help us understand the problem. What is going on with this article?

東京のAirbnbのデータをpandasを使って見てみる。 その2

概要

http://insideairbnb.com/get-the-data.html から取得した、
2019年分の東京のデータをpandasを使って見てみた。
calendar.csv というデータを使っていてarchiveされているものも使っています。

東京のAirbnbのデータをpandasを使って見てみる。 の続き。

経緯

東京のAirbnbのデータをpandasを使って見てみる。 でlisting.csvの
分析をしてみたが、どういった部屋を出せば予約してもらえるのかが分からなかったので、
継続して他のCSVも見てみることにしました。

前提条件

2019年9月〜12月までのデータを使っています。


準備

import

import pandas as pd
from matplotlib import pyplot as plt
import japanize_matplotlib
import seaborn as sns
import glob
import datetime
import numpy as np
%matplotlib inline

CSVの読み込み

http://insideairbnb.com/get-the-data.html から calendar.csvを取得して、
nodebook があるディレクトリにdataというディレクトリを作ってそこに保管します。
そしたら、以下のコードでCSVファイルを読み込みます。

calendar_path_list = glob.glob("./data/calendar*csv") # CSVが置いてあるパスを読み込む。

calendar_df = pd.DataFrame()
# 読み込んだパスの数だけforを回し、CSVを読み込む。
for i in calendar_path_list:
    tmp_df = pd.read_csv(i, parse_dates=[1])
    calendar_df = pd.concat((calendar_df, tmp_df))
calendar_df.reset_index(drop=True, inplace=True)
calendar_df.dropna(inplace=True) # nanがある行は削除する。

# priceとadjust priceの値に$や,が入っていて文字列として扱われているので数値に変換する
calendar_df["price"] = calendar_df["price"].apply(lambda x: x.replace(",", "").split(".")[0].split("$")[1])
calendar_df["adjusted_price"] = calendar_df["adjusted_price"].apply(lambda x: x.replace(",", "").split(".")[0].split("$")[1])
calendar_df["price"] = calendar_df["price"].astype("int")
calendar_df["adjusted_price"] = calendar_df["adjusted_price"].astype("int")
calendar_df.head()

以下のようなデータフレームが出来上がります。
スクリーンショット 2020-01-12 8.49.22.png

形はこんな感じ。

calendar_df.shape

スクリーンショット 2020-01-12 8.55.28.png

予約可能と予約不可の数の可視化

sns.catplot(x="date", y="listing_id", data=available_df, hue="available", aspect=10, kind="strip")
plt.xticks(rotation=90);
plt.ylabel("予約の可否数");
plt.legend(loc="upper left")

こんなグラフが描けます。
available1.png

グラフの一部を拡大してみると、
スクリーンショット 2020-01-12 8.57.47.png
という感じ。
項目名が、availableなのでTrueが予約できる状態で、Falseが予約できない状態だと思います。
切り出した画像では最後の方の11月中旬頃を除き、基本的に予約できない件数の方が多いみたいです。

予約可と予約不可の割合を可視化する

では、全物件数のどれくらいが予約可でどれくらいが予約不可なのかを見ていきたいと思います。

# 日毎のレコード数を計算する。
capacity_series = available_df.groupby("date").sum()["listing_id"]

こんなシリーズを作ります。日付とその日のレコード数の和のシリーズです。
スクリーンショット 2020-01-12 9.03.02.png

# applyで適用する関数
def calc_available(x):
    date, count = x
    tmp_totalcount = capacity_series[date]
    return count / tmp_totalcount

# 関数に適用して日毎かつavailable毎のレコードの合計数/日毎のレコードの合計数をして割合を計算する。
available_df["available_percent"] = available_df[["date", "listing_id"]].apply(calc_available, axis=1)
sns.catplot(x="date", y="available_percent", data=available_df, hue="available", aspect=10)
plt.xticks(rotation=90);
plt.legend(loc="upper left")

こんなグラフが描けます。
available2.png

グラフの一部を切り出してみるとこんな感じです。
スクリーンショット 2020-01-12 9.06.30.png

どうも大体、6割以上は予約ができない感じみたいですね。

予約が取れている部屋はどんな部屋なのか

Flaseのレコード件数の統計量を見てみます。

listing_id_available_df2 = calendar_df.groupby(by=["listing_id", "available"], as_index=False).count()
listing_id_count_series = calendar_df.groupby(by="listing_id").count()["date"]
def calc_total_count(x):
    listing_id, date = x
    total_count = listing_id_count_series[listing_id]
    return date / total_count
listing_id_available_df2["available_percent"] = listing_id_available_df2[["listing_id", "date"]].apply(calc_total_count, axis=1)
false_only_available_df = listing_id_available_df2.query("available == 'f'")
# 統計量を表示
display(false_only_available_df.head(), false_only_available_df.describe())

中央値と第一四分位の値が中央値と第三四分位の値よりも間隔が大きいので
この辺に予約される物件とそうでない物件の壁みたいなものがあるのかしら。
スクリーンショット 2020-01-12 9.22.36.png

予約可能となっている割合の分布を見てみる

# binsにしていした区切りにavailable_percentの値を入れていきます。
# つまり、-0.1以上0.1未満の区切りに入るデータはいくつあるというのが分かるようになります。

false_only_catg_series = pd.cut(false_only_available_df["available_percent"], bins=[-0.1, 0.1, 0.3, 0.6, 0.8,1.1])

plt.subplot(2,1,1)
sns.countplot(false_only_catg_series)
plt.subplot(2,1,2)
sns.countplot(pd.cut(false_only_available_df["available_percent"], bins=[-0.1,0.6,1.1]))

こんなグラフが描けます。
スクリーンショット 2020-01-12 9.28.56.png

上のグラフから見ると、0.3以上0.6未満のところが意外と多いですね。
下のグラフで0.6を境目にしてみると、半分くらいの物件が6割を切っています。

では、どんな部屋が人気なのかを見てきます。

どんな部屋だと予約してもらえるのか

前回の記事で使ったlisting.csvのデータを使います。
どうもlisting.csvのid列とcalendar.csvのlisting_id列は対応しているみたいだからです。
(同じidで複数のタイプの物件を営んでいる人もいるのですが、特に考慮していません。)

# availableが0.6以上のものを抽出する。
upto06_available_df = false_only_available_df.query("available_percent > 0.6")

# id列とroom_type列でグループ化する。
df4 = df.groupby(by=["id", "room_type"], as_index=False).count().iloc[:, :2]

# 2つのデータフレームをmergeする。
df5 = pd.merge(upto06_available_df, df4, left_on="listing_id", right_on="id")

# グラフを描く!
for i in df5["room_type"].unique():
    plt.title(i)
    plt.ylim(0,1600)
    plt.show((sns.countplot(pd.cut(df5.query("room_type == @i")["available_percent"], bins=[0.5, 0.6, 0.7, 0.8, 0.9, 1.1]))))

こんなグラフが描けます。

entire_home_and_apt.png
hotel_room.png
private_room.png
shared_room.png

各物件のタイプの総数が異なるので、ちょっとそのまま比べるのはアレなのですが、
Entire home/apt が儲かりそうなのかしら?

まとめ

どの部屋のタイプが儲かるのかはさておき、Airbnbの活況具合が何となくわかりました。
データ分析としてはさらに、

  • 物件がどこにあるのか(渋谷区とか)
  • 最低宿泊数(最低二泊三日しないといけないとか)
  • 価格

を分析すると、Entire home/apt の中でもさらに売れそうな部屋が見えてきそうだなと思いました。

txt_only
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした