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

# 概要

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

[東京のAirbnbのデータをpandasを使って見てみる。](https://qiita.com/txt_only/items/de67b104fd9831f9f6e5) の続き。

# 経緯

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

# 前提条件

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

---

# 準備

## import

```python
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ファイルを読み込みます。

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/83a392aa-dbb0-03d2-3aef-8aca3804197f.png)

形はこんな感じ。

```python
calendar_df.shape
```

![スクリーンショット 2020-01-12 8.55.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/f1050d20-211e-9dc0-b0cf-15205baa2d1e.png)

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

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/7e1636b0-8866-4e92-3528-5ce6998beaba.png)

グラフの一部を拡大してみると、
![スクリーンショット 2020-01-12 8.57.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/1ff9e0e7-1bc3-4cb2-0295-b7f15e9db8b2.png)
という感じ。
項目名が、availableなのでTrueが予約できる状態で、Falseが予約できない状態だと思います。
切り出した画像では最後の方の11月中旬頃を除き、基本的に予約できない件数の方が多いみたいです。

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

```python
# 日毎のレコード数を計算する。
capacity_series = available_df.groupby("date").sum()["listing_id"]
```
こんなシリーズを作ります。日付とその日のレコード数の和のシリーズです。
![スクリーンショット 2020-01-12 9.03.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/547cb775-cf56-7ee9-6d8b-b3e19346b2af.png)

```python
# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/4cc93e86-23ec-6624-2c52-3b9b2911d1fd.png)

グラフの一部を切り出してみるとこんな感じです。
![スクリーンショット 2020-01-12 9.06.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/425cb606-3c22-74ca-ee7e-61bbd8bc3973.png)

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

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

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

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/cbbb3f9e-2ba0-0247-5323-3077f5e2ddcf.png)

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

```python
# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/7ac21672-a5bb-9274-107c-28e6c161dd12.png)

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

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

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

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

```python
# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/b55f91cc-d5fe-675e-8692-bb4f7254b274.png)
![hotel_room.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/b9be5476-9707-aaab-193a-0aa091699118.png)
![private_room.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/ce5f1e34-b38d-b837-c885-36d9282d0bfc.png)
![shared_room.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86853/4553a1a3-a1f7-ed14-2390-ba8b0d272b24.png)

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

# まとめ

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

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

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