Project 7: The NYC Airbnb Market – Analysis

1. Importing the Data

New York City skyline
Welcome to New York City (NYC), one of the most-visited cities in the world. As a result, there are many Airbnb listings to meet the high demand for temporary lodging for anywhere between a few nights to many months. In this notebook, we will take a look at the NYC Airbnb market by combining data from multiple file types like .csv.tsv, and .xlsx.



We will be working with three datasets:

  1. "datasets/airbnb_price.csv"
  2. "datasets/airbnb_room_type.xlsx"
  3. "datasets/airbnb_last_review.tsv"
  4. What is the average price, per night, of an Airbnb listing in NYC?
  5. How does the average price of an Airbnb listing, per month, compare to the private rental market?
  6. How many adverts are for private rooms?
  7. How do Airbnb listing prices compare across the five NYC boroughs?

In [54]:

import pandas as pd
import numpy as np
import datetime as dt

# Load airbnb_price.csv, prices
prices =pd.read_csv('datasets/airbnb_price.csv')

# Load airbnb_room_type.xlsx, xls
xls = pd.ExcelFile("datasets/airbnb_room_type.xlsx")

# Parse the first sheet from xls, room_types
room_types = xls.parse(sheet_name=0) 

# Load airbnb_last_review.tsv, reviews
reviews = pd.read_csv("datasets/airbnb_last_review.tsv", sep="\t")

# Print the first five rows of each DataFrame
display(prices.head(), "\n", room_types.head(), "\n", reviews.head())
listing_idpricenbhood_full
02595225 dollarsManhattan, Midtown
1383189 dollarsBrooklyn, Clinton Hill
25099200 dollarsManhattan, Murray Hill
3517879 dollarsManhattan, Hell’s Kitchen
45238150 dollarsManhattan, Chinatown
'\n'
listing_iddescriptionroom_type
02595Skylit Midtown CastleEntire home/apt
13831Cozy Entire Floor of BrownstoneEntire home/apt
25099Large Cozy 1 BR Apartment In Midtown EastEntire home/apt
35178Large Furnished Room Near B’wayprivate room
45238Cute & Cozy Lower East Side 1 bdrmEntire home/apt
'\n'
listing_idhost_namelast_review
02595JenniferMay 21 2019
13831LisaRoxanneJuly 05 2019
25099ChrisJune 22 2019
35178ShunichiJune 24 2019
45238BenJune 09 2019

2. Cleaning the price column

Now the DataFrames have been loaded, the first step is to calculate the average price per listing by room_type.

You may have noticed that the price column in the prices DataFrame currently states each value as a string with the currency (dollars) following, i.e.,

price
225 dollars
89 dollars
200 dollars

We will need to clean the column in order to calculate the average price.

In [56]:

# Remove whitespace and string characters from prices column
prices["price"] = prices.price.str.replace(" dollars","")

# Convert prices column to numeric datatype
prices["price"] = pd.to_numeric(prices.price)

# Print descriptive statistics for the price column
print(prices.price.describe())
count    25209.000000
mean       141.777936
std        147.349137
min          0.000000
25%         69.000000
50%        105.000000
75%        175.000000
max       7500.000000
Name: price, dtype: float64

3. Calculating average price

We can see three quarters of listings cost $175 per night or less.

However, there are some outliers including a maximum price of $7,500 per night!

Some of listings are actually showing as free. Let’s remove these from the DataFrame, and calculate the average price.

In [58]:

# Subset prices for listings costing $0, free_listings
free_listings = prices["price"]==0

# Update prices by removing all free listings from prices
prices = prices[~free_listings]

# Calculate the average price, avg_price
avg_price = round(prices.price.mean(),2)

# Print the average price
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. Comparing costs to the private rental market

Now we know how much a listing costs, on average, per night, but it would be useful to have a benchmark for comparison. According to Zumper, a 1 bedroom apartment in New York City costs, on average, $3,100 per month. Let’s convert the per night prices of our listings into monthly costs, so we can compare to the private market.

In [60]:

# Add a new column to the prices DataFrame, price_per_month
prices["price_per_month"] = prices["price"] * 365 / 12

# Calculate average_price_per_month
average_price_per_month = round(prices.price_per_month.mean(), 2)

# Compare Airbnb and rental market
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. Cleaning the room type column

Unsurprisingly, using Airbnb appears to be substantially more expensive than the private rental market. We should, however, consider that these Airbnb listings include single private rooms or even rooms to share, as well as entire homes/apartments.

Let’s dive deeper into the room_type column to find out the breakdown of listings by type of room. The room_type column has several variations for private room listings, specifically:

  • “Private room”
  • “private room”
  • “PRIVATE ROOM”

We can solve this by converting all string characters to lower case (upper case would also work just fine).

In [62]:

# Convert the room_type column to lowercase
room_types["room_type"] = room_types["room_type"].str.lower()

# Update the room_type column to category data type
room_types["room_type"] = room_types["room_type"].astype("category")

# Create the variable room_frequencies
room_frequencies = room_types['room_type'].value_counts()

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

6. What timeframe are we working with?

It seems there is a fairly similar sized market opportunity for both private rooms (45% of listings) and entire homes/apartments (52%) on the Airbnb platform in NYC.

Now let’s turn our attention to the reviews DataFrame. The last_review column contains the date of the last review in the format of “Month Day Year” e.g., May 21 2019. We’ve been asked to find out the earliest and latest review dates in the DataFrame, and ensure the format allows this analysis to be easily conducted going forwards.

In [64]:

# Change the data type of the last_review column to datetime
reviews["last_review"] = pd.to_datetime(reviews.last_review,format='%B %d %Y')

# Create first_reviewed, the earliest review date
first_reviewed = reviews["last_review"].dt.date.min()

# Create last_reviewed, the most recent review date
last_reviewed = reviews["last_review"].dt.date.max()

# Print the oldest and newest reviews from the DataFrame
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. Joining the DataFrames.

Now we’ve extracted the information needed, we will merge the three DataFrames to make any future analysis easier to conduct. Once we have joined the data, we will remove any observations with missing values and check for duplicates.

In [66]:

# Merge prices and room_types to create rooms_and_prices
rooms_and_prices = prices.merge(room_types, how='outer', on='listing_id')

# Merge rooms_and_prices with the reviews DataFrame to create airbnb_merged
airbnb_merged = rooms_and_prices.merge(reviews,how='outer' , on='listing_id')

# Drop missing values from airbnb_merged
airbnb_merged.dropna(inplace=True)

# Check if there are any duplicate values
print("There are {} duplicates in the DataFrame.".format(airbnb_merged.duplicated().sum()))
There are 0 duplicates in the DataFrame.

8. Analyzing listing prices by NYC borough

Now we have combined all data into a single DataFrame, we will turn our attention to understanding the difference in listing prices between New York City boroughs. We can currently see boroughs listed as the first part of a string within the nbhood_full column, e.g.,

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

We will therefore need to extract this information from the string and store in a new column, borough, for analysis.

In [68]:

# Extract information from the nbhood_full column and store as a new column, borough
airbnb_merged["borough"] = airbnb_merged["nbhood_full"].str.partition(',')[0]

# Group by borough and calculate summary statistics
boroughs = airbnb_merged.groupby("borough")["price"].agg(["sum", "mean", "median", "count"])

# Round boroughs to 2 decimal places, and sort by mean in descending order
boroughs = boroughs.round(2).sort_values(by="mean", ascending=False)

# Print boroughs
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. Price range by borough

The above output gives us a summary of prices for listings across the 5 boroughs. In this final task we would like to categorize listings based on whether they fall into specific price ranges, and view this by borough.

We can do this using percentiles and labels to create a new column, price_range, in the DataFrame. Once we have created the labels, we can then group the data and count frequencies for listings in each price range by borough.

We will assign the following categories and price ranges:

labelprice
Budget$0-69
Average$70-175
Expensive$176-350
Extravagant> $350

In [70]:

# Create labels for the price range, label_names
label_names = ["Budget", "Average", "Expensive","Extravagant"]

# Create the label ranges, ranges
ranges = [0, 69, 175, 350, np.inf]

# Insert new column, price_range, into DataFrame
airbnb_merged["price_range"] = pd.cut(airbnb_merged['price'], bins=ranges, labels=label_names)

# Calculate borough and price_range frequencies, prices_by_borough
prices_by_borough = airbnb_merged.groupby(['borough','price_range'])['price'].count()
print(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
Name: price, dtype: int64

Leave a comment

Hello !!! I’m Ram Rallabandi

an AI consultant and data scientist with a proven track record of delivering high-impact AI solutions. My mission is simple: transform complex AI strategies into measurable business outcomes.

→ What I Do:
I specialize in leading the end-to-end lifecycle of AI products, from ideation to technical development to successful market launch. My expertise lies in bridging the gap between technical innovation and business value to ensure that every AI initiative aligns with organizational goals.

→ How I Add Value:
☑ Drive the adoption of responsible AI practices to future-proof businesses
☑ Build scalable, high-quality AI solutions that directly address customer needs
☑ Streamline processes to connect AI demand with delivery teams efficiently
☑ Analyze market trends to position data-driven solutions for maximum impact

Why It Works:
With a strong foundation in AI, machine learning, and data science, I provide strategic insights that empower organizations to leverage cutting-edge technologies for growth. I collaborate with technical and business teams to:
↳ Define product roadmaps
↳ Manage budgets, timelines, and scopes
↳ Foster cross-functional alignment for AI-driven innovation

My Passion:
I thrive on leading AI storytelling for executive leadership and fostering collaboration across diverse teams. With deep experience in Fintech and Payments, I’m dedicated to unlocking AI’s potential to deliver business transformation and create widely adopted solutions.

Let’s connect to explore how AI can transform your business.