New York City Airbnb Analysis¶

New York City skyline

世界で最も訪問者の多い都市の 1 つであるニューヨーク市 (NYC)。
数泊から数か月にわたる一時的な宿泊施設の高い需要に応えるため、Airbnb のリストが多数存在します。.csv、.tsv、.xlsx などの複数のファイル タイプのデータを組み合わせて、ニューヨーク市の Airbnb 市場を見ていきます。

1. データのインポート¶

3 つのデータセットを操作します。

  1. airbnb_price.csv」

  2. airbnb_room_type.xlsx

  3. airbnb_last_review.tsv

目標は、整理されていないデータを適切な形式に変換して分析し、次のような重要な疑問に答えることです。

  • ニューヨーク市のAirbnb掲載物件の1泊あたりの平均価格はいくらか?
  • Airbnb リスティングの月額平均価格は、民間賃貸市場と比較してどうか?
  • 個室の広告は何枚ありか?
  • Airbnb の掲載価格はニューヨーク市の 5 つの区でどのように比較されるか?
from zipfile import ZipFile
from io import BytesIO
import pandas as pd

zf = ZipFile('datasets.zip')
zf.namelist()
['datasets/',
 'datasets/airbnb_room_type.xlsx',
 'datasets/airbnb_price.csv',
 'datasets/airbnb_last_review.tsv']
import datetime as dt

prices = pd.read_csv(BytesIO(zf.read(zf.namelist()[2])))

reviews = pd.read_csv(BytesIO(zf.read(zf.namelist()[3])), sep='\t')

xls = pd.ExcelFile(zf.namelist()[1])
room_types = pd.DataFrame(xls.parse(0))
room_types.head()
listing_id description room_type
0 2595 Skylit Midtown Castle Entire home/apt
1 3831 Cozy Entire Floor of Brownstone Entire home/apt
2 5099 Large Cozy 1 BR Apartment In Midtown East Entire home/apt
3 5178 Large Furnished Room Near B'way private room
4 5238 Cute & Cozy Lower East Side 1 bdrm Entire home/apt
prices.head()
listing_id price nbhood_full
0 2595 225 dollars Manhattan, Midtown
1 3831 89 dollars Brooklyn, Clinton Hill
2 5099 200 dollars Manhattan, Murray Hill
3 5178 79 dollars Manhattan, Hell's Kitchen
4 5238 150 dollars Manhattan, Chinatown
reviews.head()
listing_id host_name last_review
0 2595 Jennifer May 21 2019
1 3831 LisaRoxanne July 05 2019
2 5099 Chris June 22 2019
3 5178 Shunichi June 24 2019
4 5238 Ben June 09 2019

2. 価格列のクリーニング¶

これでDataFramesがを読み込みました。
最初は、room_typeごとにリスティングごとの平均価格を計算します。

prices データフレームの price 列には、各値が通貨 (ドル) の後に続く文字列として示されています。

price
225 dollars
89 dollars
200 dollars

平均価格を計算するにはカラムをクリーニングする必要があります。

まず価格列から空白文字と文字列文字を削除し
価格列を数値データ型に変換し
価格列の記述統計を出力します。

prices["price"] = prices['price'].str.replace(" dollars", "")

prices["price"] = pd.to_numeric(prices['price'])

prices['price']
0        225
1         89
2        200
3         79
4        150
        ... 
25204    129
25205     45
25206    235
25207    100
25208     30
Name: price, Length: 25209, dtype: int64

3. 平均価格の計算¶

物件の 4 分の 3 が 1 泊あたり 175 ドルであることがわかります。

一部のリストは実際には無料として表示されています。これらをDataFrameから削除して、平均価格を計算してみます。

price = 0 のリストのサブセットをfree_listingsとします
価格からすべての無料リスティングを削除して価格を更新します
平均価格 avg_price を計算します。

free_listings = prices['price'] == 0

prices = prices.loc[~free_listings]

avg_price = round(prices['price'].mean(),2)

print("The average price per night for an Airbnb listing in NYC is ${}.".format(avg_price))
The average price per night for an Airbnb listing in NYC is $141.82.

4. 民間賃貸市場とのコストの比較¶

これで 1 泊あたりの平均料金がわかりましたが、比較のためのベンチマークがあると便利です。
Zumper によると、ニューヨーク市の 1 ベッドルーム アパートメントの費用は平均で月額 3,100 ドルです。
プライベート市場と比較できるように、リスティングの 1 泊あたりの料金を月々の費用に換算します。

価格データフレームに新しい列、price_per_month を追加して
月あたりの平均価格を計算し
Airbnbと賃貸市場を比較します。

prices["price_per_month"] = prices["price"] * 365 / 12

average_price_per_month = round(prices["price_per_month"].mean(), 2)

print("airbnb monthly costs are ${}, while in the private market you would pay {}.".format(average_price_per_month, "$3,100.00"))
airbnb monthly costs are $4313.61, while in the private market you would pay $3,100.00.

5. 部屋タイプ欄の掃除¶

当然のことながら、Airbnb の利用は民間の賃貸市場よりもかなり高価であるようです。ただし、これらのAirbnbのリストには、家やアパート全体だけでなく、1人の個室やシェアする部屋も含まれていることを考慮する必要があります。

room_type列をさらに詳しく見て、部屋のタイプごとのリストの内訳を確認してみましょう。 room_type 列には、private room リストのバリエーションがいくつかあります。具体的には次のとおりです。

  • "Private room"
  • "private room"
  • "PRIVATE ROOM"

これは、すべての文字列の文字を小文字もしくは大文字に変換して統一することで解決できます。

room_type 列を小文字に変換し
room_type 列を category データ型に更新
変数 room_frequency を作成します

room_types["room_type"] = room_types["room_type"].str.lower()

room_types["room_type"] = room_types["room_type"].astype("category")

room_frequencies = room_types["room_type"].value_counts()

print(room_frequencies)
entire home/apt    13266
private room       11356
shared room          587
Name: room_type, dtype: int64

6. どのタイムフレームで取り組んでいるのか?¶

ニューヨーク市のAirbnbプラットフォームには、個室(物件の45%)と住宅/アパート全体(52%)の両方に、ほぼ同じ規模の市場機会があるようです。

次に、reviews データフレームに注目してみます。
last_review 列には、「月日年」の形式で最後のレビューの日付が含まれます (例: May 21 2019)。
データフレーム内の最も古いレビュー日と最新のレビュー日を調べて、その形式が許可されていることを確認するように求められました。
この分析は今後簡単に実施できるようになります。

last_review 列のデータ型を datetime に変更します。
最も早いレビュー日である first_reviewed を作成し、
last_reviewed、最新のレビュー日を作成して
DataFrame から最も古いレビューと最新のレビューを出力します。

reviews["last_review"] = pd.to_datetime(reviews["last_review"])

first_reviewed = reviews["last_review"].dt.date.min()

last_reviewed = reviews["last_review"].dt.date.max()

print("The latest Airbnb review is {}, the earliest review is {}".format(first_reviewed, last_reviewed))
The latest Airbnb review is 2019-01-01, the earliest review is 2019-07-09

7. データフレームを結合¶

必要な情報を抽出したので、3 つの DataFrame をマージして、今後の分析をより簡単に実行できるようにします。データを結合したら、欠損値のある観測値を削除し、重複がないかチェックします。

価格と room_types を結合して rooms_and_prices を作成し
rooms_and_prices をレビュー データフレームとマージして airbnb_merged を作成
airbnb_merged から欠損値を削除する

rooms_and_prices = prices.merge(room_types, how='outer', on="listing_id")

airbnb_merged = rooms_and_prices.merge(reviews, how='outer', on="listing_id")

airbnb_merged.dropna(inplace=True)

print("There are {} duplicates in the DataFrame.".format(airbnb_merged.duplicated().sum()))
There are 0 duplicates in the DataFrame.

8. ニューヨーク市区ごとの上場価格の分析¶

すべてのデータを 1 つの データフレームに結合しました。
次に、ニューヨーク市の各区 間の出品価格の違いを理解することに目を向けます。
現在、nbhood_full 列内の文字列の最初の部分として区がリストされていることがわかります。

Manhattan, Midtown
Brooklyn, Clinton Hill
Manhattan, Murray Hill
Manhattan, Hell's Kitchen
Manhattan, Chinatown

分析のために文字列からこの情報を抽出し、新しい列boroughに保存します。

nbhood_full 列から情報を抽出し、新しい列として保存します。
区ごとにグループ化し、概要統計を計算し
区を小数点第 2 位に四捨五入し、平均値を降順に並べ替えます

airbnb_merged["borough"] = airbnb_merged["nbhood_full"].str.partition(',')[0]

boroughs = airbnb_merged.groupby("borough")["price"].agg(["sum", "mean", "median", "count"])

boroughs = boroughs.round(2).sort_values("mean", ascending=False)

print(boroughs)
                     sum    mean  median  count
borough                                        
Manhattan      1898417.0  184.04   149.0  10315
Brooklyn       1275250.0  122.02    95.0  10451
Queens          320715.0   92.83    70.0   3455
Staten Island    22974.0   86.04    71.0    267
Bronx            55156.0   79.25    65.0    696

9. 区別の価格帯¶

上記の出力は、5 つの区にわたる物件の価格の概要を示しています。
リストが特定の価格帯に該当するかどうかに基づいてリストを分類し、これを地区ごとに表示します。

パーセンタイルとラベルを使用してこれを実行し、データフレームに新しい列 price_range を作成します。ラベルを作成したら、データをグループ化し、地区ごとに各価格帯のリストの頻度をカウントできます。

次のカテゴリと価格帯を割り当てます。

label price
Budget \$0-69
Average \$70-175
Expensive \$176-350
Extravagant > $350

価格帯 label_names のラベルを作成します。
ラベル範囲、範囲を作成して
新しい列、price_range を データフレームに挿入します。
地区と価格範囲の頻度、価格ごとの地区を計算します。

label_names = ["Budget", "Average", "Expensive", "Extravagant"]

ranges = [0, 69, 175, 350, np.inf]

airbnb_merged["price_range"] = pd.cut(airbnb_merged['price'], bins = ranges, labels = label_names)

prices_by_borough = airbnb_merged.groupby(['borough','price_range'])["price_range"].count()
prices_by_borough
borough        price_range
Bronx          Budget          381
               Average         285
               Expensive        25
               Extravagant       5
Brooklyn       Budget         3194
               Average        5532
               Expensive      1466
               Extravagant     259
Manhattan      Budget         1148
               Average        5285
               Expensive      3072
               Extravagant     810
Queens         Budget         1631
               Average        1505
               Expensive       291
               Extravagant      28
Staten Island  Budget          124
               Average         123
               Expensive        20
               Extravagant       0
Name: price_range, dtype: int64

これでそれぞれの区ごとに、どの価格帯がどのくらい存在しているかがわかるようになりました。