3 つのデータセットを操作します。
airbnb_price.csv」
airbnb_room_type.xlsx
airbnb_last_review.tsv
目標は、整理されていないデータを適切な形式に変換して分析し、次のような重要な疑問に答えることです。
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 |
これで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
物件の 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.
価格データフレームに新しい列、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.
当然のことながら、Airbnb の利用は民間の賃貸市場よりもかなり高価であるようです。ただし、これらのAirbnbのリストには、家やアパート全体だけでなく、1人の個室やシェアする部屋も含まれていることを考慮する必要があります。
room_type列をさらに詳しく見て、部屋のタイプごとのリストの内訳を確認してみましょう。 room_type 列には、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
ニューヨーク市の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
必要な情報を抽出したので、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.
すべてのデータを 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
上記の出力は、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
これでそれぞれの区ごとに、どの価格帯がどのくらい存在しているかがわかるようになりました。