Project Python Foundations: FoodHub Data Analysis¶

Context¶

The number of restaurants in New York is increasing day by day. Lots of students and busy professionals rely on those restaurants due to their hectic lifestyles. Online food delivery service is a great option for them. It provides them with good food from their favorite restaurants. A food aggregator company FoodHub offers access to multiple restaurants through a single smartphone app.

The app allows the restaurants to receive a direct online order from a customer. The app assigns a delivery person from the company to pick up the order after it is confirmed by the restaurant. The delivery person then uses the map to reach the restaurant and waits for the food package. Once the food package is handed over to the delivery person, he/she confirms the pick-up in the app and travels to the customer's location to deliver the food. The delivery person confirms the drop-off in the app after delivering the food package to the customer. The customer can rate the order in the app. The food aggregator earns money by collecting a fixed margin of the delivery order from the restaurants.

Objective¶

The food aggregator company has stored the data of the different orders made by the registered customers in their online portal. They want to analyze the data to get a fair idea about the demand of different restaurants which will help them in enhancing their customer experience. Suppose you are hired as a Data Scientist in this company and the Data Science team has shared some of the key questions that need to be answered. Perform the data analysis to find answers to these questions that will help the company to improve the business.

Data Description¶

The data contains the different data related to a food order. The detailed data dictionary is given below.

Data Dictionary¶

  • order_id: Unique ID of the order
  • customer_id: ID of the customer who ordered the food
  • restaurant_name: Name of the restaurant
  • cuisine_type: Cuisine ordered by the customer
  • cost_of_the_order: Cost of the order
  • day_of_the_week: Indicates whether the order is placed on a weekday or weekend (The weekday is from Monday to Friday and the weekend is Saturday and Sunday)
  • rating: Rating given by the customer out of 5
  • food_preparation_time: Time (in minutes) taken by the restaurant to prepare the food. This is calculated by taking the difference between the timestamps of the restaurant's order confirmation and the delivery person's pick-up confirmation.
  • delivery_time: Time (in minutes) taken by the delivery person to deliver the food package. This is calculated by taking the difference between the timestamps of the delivery person's pick-up confirmation and drop-off information

Let us start by importing the required libraries¶

In [1]:
# Installing the libraries with the specified version.
!pip install numpy==1.25.2 pandas==1.5.3 matplotlib==3.7.1 seaborn==0.13.1 -q --user

Note: After running the above cell, kindly restart the notebook kernel and run all cells sequentially from the start again.

In [2]:
# import libraries for data manipulation
import numpy as np
import pandas as pd

# import libraries for data visualization
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.simplefilter('ignore')
%matplotlib inline
pd.set_option('display.float_format', lambda x: '%.2f' % x) 
sns.set_palette("ocean_r")

Understanding the structure of the data¶

In [3]:
df= pd.read_csv('foodhub_order.csv')
df.columns
Out[3]:
Index(['order_id', 'customer_id', 'restaurant_name', 'cuisine_type',
       'cost_of_the_order', 'day_of_the_week', 'rating',
       'food_preparation_time', 'delivery_time'],
      dtype='object')
In [4]:
df.head()
Out[4]:
order_id customer_id restaurant_name cuisine_type cost_of_the_order day_of_the_week rating food_preparation_time delivery_time
0 1477147 337525 Hangawi Korean 30.75 Weekend Not given 25 20
1 1477685 358141 Blue Ribbon Sushi Izakaya Japanese 12.08 Weekend Not given 25 23
2 1477070 66393 Cafe Habana Mexican 12.23 Weekday 5 23 28
3 1477334 106968 Blue Ribbon Fried Chicken American 29.20 Weekend 3 25 15
4 1478249 76942 Dirty Bird to Go American 11.59 Weekday 4 25 24

Question 1: How many rows and columns are present in the data? [0.5 mark]¶

In [5]:
df.shape
Out[5]:
(1898, 9)

Observations:¶

  • This data set has 1898 rows or 9 columns.

Question 2: What are the datatypes of the different columns in the dataset? (The info() function can be used) [0.5 mark]¶

In [6]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1898 entries, 0 to 1897
Data columns (total 9 columns):
 #   Column                 Non-Null Count  Dtype  
---  ------                 --------------  -----  
 0   order_id               1898 non-null   int64  
 1   customer_id            1898 non-null   int64  
 2   restaurant_name        1898 non-null   object 
 3   cuisine_type           1898 non-null   object 
 4   cost_of_the_order      1898 non-null   float64
 5   day_of_the_week        1898 non-null   object 
 6   rating                 1898 non-null   object 
 7   food_preparation_time  1898 non-null   int64  
 8   delivery_time          1898 non-null   int64  
dtypes: float64(1), int64(4), object(4)
memory usage: 133.6+ KB

Observations:¶

  • This data set has 3 data types, integers (int64), floats (float64) and objects. Rating column has a type of object but integer is expected.

Question 3: Are there any missing values in the data? If yes, treat them using an appropriate method. [1 mark]¶

In [7]:
df.isnull().sum()
Out[7]:
order_id                 0
customer_id              0
restaurant_name          0
cuisine_type             0
cost_of_the_order        0
day_of_the_week          0
rating                   0
food_preparation_time    0
delivery_time            0
dtype: int64

Observations:¶

  • There are no missing values.

Question 4: Check the statistical summary of the data. What is the minimum, average, and maximum time it takes for food to be prepared once an order is placed? [2 marks]¶

In [8]:
df.describe().T
Out[8]:
count mean std min 25% 50% 75% max
order_id 1898.00 1477495.50 548.05 1476547.00 1477021.25 1477495.50 1477969.75 1478444.00
customer_id 1898.00 171168.48 113698.14 1311.00 77787.75 128600.00 270525.00 405334.00
cost_of_the_order 1898.00 16.50 7.48 4.47 12.08 14.14 22.30 35.41
food_preparation_time 1898.00 27.37 4.63 20.00 23.00 27.00 31.00 35.00
delivery_time 1898.00 24.16 4.97 15.00 20.00 25.00 28.00 33.00

Observations:¶

  • The average cost of an order is $16.50.
  • The average prep time is about 27 minutes.
  • The average delivery time is about 24 minues.
  • The order_id and customer_id values are nominal values for which the central tendancies calculations are meaningless and should be ignored.

Question 5: How many orders are not rated? [1 mark]¶

In [9]:
df['rating'].value_counts()
Out[9]:
Not given    736
5            588
4            386
3            188
Name: rating, dtype: int64

Exploratory Data Analysis (EDA)¶

Observations:¶

  • There are 736 orders that are not rated which is indicated by the value 'Not Given'. The nature of a subjective rating makes it not a good candidate for imputing data however the 'Not Given' could be changed to NaN instead of the string or we may also exclude those rows from analysis. Consideration should be given for analysis of this column so that the missing data doesn't result in an inaccurate representation of a particular restaraunt, cuisine, customer, day of the week etc. We should avoid substituing zero or integer value for missing ratings.

Univariate Analysis¶

Question 6: Explore all the variables and provide observations on their distributions. (Generally, histograms, boxplots, countplots, etc. are used for univariate exploration.) [9 marks]¶

In [10]:
df['customer_id'].nunique()
Out[10]:
1200
In [11]:
df['restaurant_name'].nunique()
Out[11]:
178
In [12]:
df['cuisine_type'].nunique()
Out[12]:
14
In [13]:
df['cost_of_the_order'].agg(['median','mean'])
Out[13]:
median   14.14
mean     16.50
Name: cost_of_the_order, dtype: float64
In [14]:
plt.figure(figsize=(10, 5))
sns.histplot(data=df,x='cost_of_the_order', kde=True)
plt.title('Distribution of Cost of Orders')
plt.xlabel('Cost of the Order')
plt.ylabel('Frequency')
plt.show()
plt.figure(figsize=(10, 5))
sns.boxplot(data=df, x='cost_of_the_order')
plt.title('Boxplot of Cost of Orders')
plt.xlabel('Cost of the Order')
plt.ylabel('Cost')
plt.show()
No description has been provided for this image
No description has been provided for this image

Observations:¶

  • The cost data is multi modal with peaks around $12, $25, $30 and right skewed.
  • The median is about $14.
In [15]:
plt.figure(figsize=(10, 5))
sns.histplot(data=df,x='delivery_time', kde=True)
plt.title('Distribution of Delivery Time')
plt.xlabel('Delivery Time (minutes)')
plt.ylabel('Frequency')
plt.show()
plt.figure(figsize=(10, 5))
sns.boxplot(data=df, x='delivery_time')
plt.title('Boxplot of Delivery Time')
plt.xlabel('Delivery Time')
plt.ylabel('Delivery Time (minutes)')
plt.show()
No description has been provided for this image
No description has been provided for this image

Observations:¶

  • Delivery times are between 15-32 minutes with a median around 25 minutes.
  • Even fairly normal distribution.
In [16]:
plt.figure(figsize=(10, 5))
sns.histplot(data=df, x='food_preparation_time', kde=True)
plt.title('Distribution of Food Preparation Time')
plt.xlabel('Food Preparation Time (minutes)')
plt.ylabel('Frequency')
plt.show()

plt.figure(figsize=(10, 5))
sns.boxplot(data=df, x='food_preparation_time')
plt.title('Boxplot of Food Preparation Time')
plt.xlabel('Food Preparation Time')
plt.ylabel('Food Preparation Time (minutes)')
plt.show()
No description has been provided for this image
No description has been provided for this image

Observations:¶

  • Food preperation time takes from 20-35 minutes and has a median delivery time around 27 minutes with is a little longer than delivery time.
  • Minimum prep time is longer than delivery time.
  • By taking the min/max prep time and delivery time I can see that it will take at least 35 minutes from time of order but can be as up to hour and and 15 minutes.
In [17]:
plt.figure(figsize=(15, 5))
sns.countplot(data=df, x='cuisine_type', order=df['cuisine_type'].value_counts().index)
plt.title('Count of Orders by Cuisine Type')
plt.xlabel('Cuisine Type')
plt.ylabel('Count')
plt.xticks(rotation=45)
plt.show()

plt.figure(figsize=(10, 5))
sns.countplot(data=df, x='rating')
plt.title('Count of Ratings')
plt.xlabel('Rating')
plt.ylabel('Count')
plt.show()

plt.figure(figsize=(10, 5))
sns.countplot(data=df, x='day_of_the_week')
plt.title('Count of Orders by Day of the Week')
plt.xlabel('Day of the Week')
plt.ylabel('Count')
plt.show()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Observations:¶

  • The most popular cuisines are American, Japanese and Italian by a significant margin.
  • There are are a significant number of missing ratings. Almost 1/3 of orders don't provide a rating.
  • The 2 day weekend has more than double the number of orders as the 5 weekdays combined.

Question 7: Which are the top 5 restaurants in terms of the number of orders received? [1 mark]¶

In [18]:
top_5_restaurants = df['restaurant_name'].value_counts().head().reset_index()
top_5_restaurants.columns = ['restaurant_name', 'count']
print('The top 5 restaurants in terms of the number of orders received:')
print(top_5_restaurants.to_string(index=False))
sns.catplot(data=top_5_restaurants, x='restaurant_name', y='count', kind='bar')
plt.xticks(rotation=45)
plt.title('Top 5 Restaurants by Order Count')
plt.xlabel('Restaurant Name')
plt.ylabel('Order Count')
plt.show()
The top 5 restaurants in terms of the number of orders received:
          restaurant_name  count
              Shake Shack    219
        The Meatball Shop    132
        Blue Ribbon Sushi    119
Blue Ribbon Fried Chicken     96
                     Parm     68
No description has been provided for this image

Observations:¶

Shake Shake has the largest number of order by almost double the next largest.

Observations:¶

Question 8: Which is the most popular cuisine on weekends? [1 mark]¶

In [19]:
popular_on_weekend = df['cuisine_type'].where(df['day_of_the_week'] == 'Weekend').value_counts().head().reset_index()
popular_on_weekend.columns = ['cuisine_type', 'count']
print('The most popular cuisines on weekends are:')
print(popular_on_weekend.to_string(index=False))
sns.catplot(data=popular_on_weekend, x='cuisine_type', y='count', kind='bar')
plt.title('Popular Cuisine Types on Weekends')
plt.xlabel('Cuisine Type')
plt.ylabel('Count')
plt.show()
The most popular cuisines on weekends are:
cuisine_type  count
    American    415
    Japanese    335
     Italian    207
     Chinese    163
     Mexican     53
No description has been provided for this image

Observations:¶

  • The most popular cuisines on the weekend is American, Japanese and Italian.

Question 9: What percentage of the orders cost more than 20 dollars? [2 marks]¶

In [20]:
percent_cost_above_20_dollars = df[df['cost_of_the_order'] > 20]['order_id'].count() / df.shape[0] * 100
print(f'Percentage of the orders cost more than 20 dollars: {percent_cost_above_20_dollars:.2f}%')
Percentage of the orders cost more than 20 dollars: 29.24%

Observations:¶

  • About a 1/3 of the orders are over $20.

Question 10: What is the mean order delivery time? [1 mark]¶

In [21]:
mean_delivery_time = df['delivery_time'].mean()
print(f'The mean order delivery time: {mean_delivery_time:.2f}')
The mean order delivery time: 24.16

Observations:¶

  • The average deliver time is about 24 minutes which is a little lower than the median which tells us the data is a little bit left skewed with some orders getting delivered very fast.

Question 11: The company has decided to give 20% discount vouchers to the top 3 most frequent customers. Find the IDs of these customers and the number of orders they placed. [1 mark]¶

In [22]:
top_3_customers = df['customer_id'].value_counts().head(3)
print(f'The top 3 customers by number of orders placed:')
print(top_3_customers)
The top 3 customers by number of orders placed:
52832    13
47440    10
83287     9
Name: customer_id, dtype: int64

Observations:¶

  • The top customer placed 13 orders, 2nd placed 10 orders, 3rd placed 9 orders.

Multivariate Analysis¶

Question 12: Perform a multivariate analysis to explore relationships between the important variables in the dataset. (It is a good idea to explore relations between numerical variables as well as relations between numerical and categorical variables) [10 marks]¶

In [23]:
plt.figure(figsize=(15, 5))
sns.countplot(data=df, x='cuisine_type', order=df['cuisine_type'].value_counts().index, hue='day_of_the_week', palette='ocean_r')
plt.xticks(rotation=45)
plt.title('Count of Cuisine Types by Day of the Week')
plt.xlabel('Cuisine Type')
plt.ylabel('Count')
plt.show()
No description has been provided for this image

Observations:¶

  • The most popular restaurants are the same for weekdays and weekends.
In [24]:
plt.figure(figsize=(10, 5))
sns.histplot(data=df, x='cost_of_the_order', hue='day_of_the_week', kde=True, palette='ocean_r')
plt.title('Distribution of Cost of Orders by Day of the Week')
plt.xlabel('Cost of the Order')
plt.ylabel('Frequency')
plt.show()

plt.figure(figsize=(10, 5))
sns.boxplot(data=df, x='day_of_the_week', y='cost_of_the_order', hue='day_of_the_week', palette='ocean_r')
plt.title('Boxplot of Cost of Orders by Day of the Week')
plt.xlabel('Day of the Week')
plt.ylabel('Cost of the Order')
plt.show()
No description has been provided for this image
No description has been provided for this image

Observations:¶

  • The cost of an order is not impacted by weekday or weekend.
In [25]:
plt.figure(figsize=(10, 5))
plt.hist(df[['delivery_time', 'food_preparation_time']].values, bins=20, alpha=0.7, label=['Delivery Time', 'Food Preparation Time'])
plt.xlabel('Time')
plt.ylabel('Frequency')
plt.title('Histogram of Delivery Time and Food Preparation Time')
plt.legend()
plt.show()
No description has been provided for this image

Observations:¶

  • The preperation time is longer than delivery time.
In [26]:
df['total_time'] = df['food_preparation_time'] + df['delivery_time']
rating_order = [3, 4, 5, 'Not given']
plt.figure(figsize=(10, 5))
sns.boxplot(data=df, y='rating', x='total_time', hue='day_of_the_week', order=rating_order)
plt.title('Boxplot of Rating vs Total Time')
plt.xlabel('Total Time (minutes)')
plt.ylabel('Rating')
plt.show()

plt.figure(figsize=(10, 5))
sns.boxplot(data=df, y='cuisine_type', x='total_time', hue='day_of_the_week')
plt.title('Boxplot of Cuisine Type vs Total Time')
plt.xlabel('Total Time (minutes)')
plt.ylabel('Cuisine Type')
plt.xticks(rotation=90)
plt.show()

plt.figure(figsize=(10, 5))
sns.boxplot(data=df, y='cuisine_type', x='cost_of_the_order', hue='day_of_the_week')
plt.title('Boxplot of Cuisine Type vs Cost of the Order')
plt.xlabel('Cost of the Order')
plt.ylabel('Cuisine Type')
plt.show()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Observations:¶

  • The ratings are not significantly different on the weekend vs weekday or by total time.
  • Total time is significantly longer on the weekends.
  • Korean seems to have a little less variability and seems to have a signifcantly faster total time.
  • Vietnamese food has a significantly lower cost per order.
  • French and Middle easter have medians over $20 on weekdays.
  • French and Thai have the highest median for weekdays.
In [27]:
df_long = pd.melt(df, id_vars='day_of_the_week', value_vars=['food_preparation_time', 'delivery_time', 'total_time'], 
                  var_name='time_type', value_name='time')
plt.figure(figsize=(10, 5))
sns.boxplot(data=df_long, y='time_type', x='time', hue='day_of_the_week')
plt.title('Boxplot of Time Type vs Time')
plt.xlabel('Time (minutes)')
plt.ylabel('Time Type')
plt.show()
No description has been provided for this image

Observations:¶

  • Prep time is not impacted by the day of the week but delivery time is.
  • The significanlty longer total time on the week seems directly related the longer delivery time.

Question 13: The company wants to provide a promotional offer in the advertisement of the restaurants. The condition to get the offer is that the restaurants must have a rating count of more than 50 and the average rating should be greater than 4. Find the restaurants fulfilling the criteria to get the promotional offer. [3 marks]¶

In [28]:
df_filtered = df[df['rating'] != 'Not given'].copy()
df_filtered['rating'] = df_filtered['rating'].astype('int')

aggregated_df = df_filtered.groupby('restaurant_name').agg(count=('rating', 'size'),mean=('rating', 'mean')).reset_index()
elgible = aggregated_df[(aggregated_df['count'] > 50) & (aggregated_df['mean'] > 4)]
elgible.sort_values(by='count', ascending = False, inplace=True)
print(elgible.to_string(index=False))
          restaurant_name  count  mean
              Shake Shack    133  4.28
        The Meatball Shop     84  4.51
        Blue Ribbon Sushi     73  4.22
Blue Ribbon Fried Chicken     64  4.33

Observations:¶

  • Shake Shack also has the highest number of ratings.
  • The Meatball Shop has the highest mean of the top.
  • Of the restaurants that are elgible for offer all of them are in the top 5 restuarants by order count

Question 14: The company charges the restaurant 25% on the orders having cost greater than 20 dollars and 15% on the orders having cost greater than 5 dollars. Find the net revenue generated by the company across all orders. [3 marks]¶

In [29]:
df['revenue'] = df['cost_of_the_order'].apply(lambda x: x * 0.25 if x > 20 else (x * 0.15 if x > 5 else 0))
print(df[['restaurant_name', 'cost_of_the_order', 'revenue']].sort_values(by='revenue', ascending=False).head(5).to_string(index=False))
print('Total revenue from all restaurants: ', df.revenue.sum())
  restaurant_name  cost_of_the_order  revenue
            Pylos              35.41     8.85
      Han Dynasty              34.19     8.55
Blue Ribbon Sushi              33.37     8.34
   Nobu Next Door              33.37     8.34
      Tres Carnes              33.32     8.33
Total revenue from all restaurants:  6166.303

Observations:¶

  • The total revenue from all restaurants is $6166.30.
  • The highest amount of revenue from one order was 8.85.

Question 15: The company wants to analyze the total time required to deliver the food. What percentage of orders take more than 60 minutes to get delivered from the time the order is placed? (The food has to be prepared and then delivered.) [2 marks]¶

In [30]:
df['total_time'] = df['food_preparation_time'] + df['delivery_time']
orders_more_than_60_min = df[df['total_time'] > 60]
percentage_more_than_60_min = (len(orders_more_than_60_min) / len(df)) * 100
print("Percentage of orders taking more than 60 minutes to deliver: {:.2f}%".format(percentage_more_than_60_min))
Percentage of orders taking more than 60 minutes to deliver: 10.54%

Observations:¶

  • The percentage of orders taking more than 60 minutes to deliver: 10.54%

Question 16: The company wants to analyze the delivery time of the orders on weekdays and weekends. How does the mean delivery time vary during weekdays and weekends? [2 marks]¶

In [31]:
mean_delivery_time = df.groupby('day_of_the_week')['delivery_time'].mean()
print(mean_delivery_time)
day_of_the_week
Weekday   28.34
Weekend   22.47
Name: delivery_time, dtype: float64

Observations:¶

  • The delivery time increases on the weekdays.
In [32]:
total_revenue_by_restaurant = df.groupby('restaurant_name')['revenue'].sum()
total_revenue = total_revenue_by_restaurant.sum()

# Calculate percentage of revenue for each restaurant
percentage_revenue_by_restaurant = (total_revenue_by_restaurant / total_revenue) * 100

# Calculate mean total time by restaurant
mean_delivery_time_by_restaurant = df.groupby('restaurant_name')['delivery_time'].mean()

# Convert 'rating' column to numeric, replacing non-numeric values with NaN
df['rating'] = pd.to_numeric(df['rating'], errors='coerce')

# Filter out rows with NaN values in the 'rating' column
df_filtered = df.dropna(subset=['rating'])

# Calculate mean rating by restaurant
mean_rating_by_restaurant = df_filtered.groupby('restaurant_name')['rating'].mean()

# Create a DataFrame for the mean values
result_df = pd.DataFrame({
    'revenue': total_revenue_by_restaurant,
    'percent_revenue': percentage_revenue_by_restaurant,
    'mean_delivery_time': mean_delivery_time_by_restaurant,
    'mean_rating': mean_rating_by_restaurant
}).reset_index()  # Reset index to make 'restaurant_name' a column
result_df = result_df.sort_values(by='percent_revenue', ascending=False)

print('Final DataFrame:')
print(result_df.head(10).to_string(index=False))
Final DataFrame:
          restaurant_name  revenue  percent_revenue  mean_delivery_time  mean_rating
              Shake Shack   703.61            11.41               24.66         4.28
        The Meatball Shop   419.83             6.81               24.24         4.51
        Blue Ribbon Sushi   360.46             5.85               23.94         4.22
Blue Ribbon Fried Chicken   340.20             5.52               24.15         4.33
                     Parm   218.56             3.54               25.50         4.13
         RedFarm Broadway   191.47             3.11               23.15         4.24
           RedFarm Hudson   180.93             2.93               24.20         4.18
                      TAO   167.36             2.71               23.16         4.36
              Han Dynasty   149.40             2.42               23.15         4.43
                 Rubirosa   140.81             2.28               23.68         4.12
In [33]:
result_df = result_df.sort_values(by='percent_revenue', ascending=False).head(10)
fig, ax = plt.subplots(figsize=(12, 8))
sns.barplot(data=result_df, x='restaurant_name', y='percent_revenue', ax=ax, color='mediumseagreen')
ax.set_ylabel('Revenue')
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')
ax2 = ax.twinx()
sns.lineplot(data=result_df, x='restaurant_name', y='mean_rating', ax=ax2, marker='o', color='royalblue')
ax2.set_ylabel('Mean Rating')
ax3 = ax.twinx()
sns.lineplot(data=result_df, x='restaurant_name', y='mean_delivery_time', ax=ax3, marker='o', color='gold')
ax3.set_ylabel('Mean Delivery Time')
ax3.spines['right'].set_position(('outward', 60))
ax.set_title('Top 10 Restaurants: Percemt Revemue, Total Time, and Rating')
ax2.legend(['Mean Rating'], loc='upper right')
ax3.legend(['Mean Delivery Time'], loc='upper left')
plt.tight_layout()
plt.show()
No description has been provided for this image
In [34]:
pivot_df = df.pivot_table(index='cuisine_type', columns='day_of_the_week', values='revenue', aggfunc='sum')
pivot_df['total_revenue'] = pivot_df.sum(axis=1)
pivot_df = pivot_df.sort_values(by='total_revenue', ascending=False).head(10)

plt.figure(figsize=(10, 6))
sns.heatmap(pivot_df, annot=True, cmap='YlGnBu', fmt='.0f', linewidths=0.5)
plt.title('Revenue by Cuisine Type and Day of the Week')
plt.xlabel('Day of the Week')
plt.ylabel('Cuisine type')
plt.show()
No description has been provided for this image
In [35]:
pivot_df = df.pivot_table(index='restaurant_name', columns='day_of_the_week', values='revenue', aggfunc='sum')
pivot_df['total_revenue'] = pivot_df.sum(axis=1)
pivot_df = pivot_df.sort_values(by='total_revenue', ascending=False).head(10)

plt.figure(figsize=(10, 6))
sns.heatmap(pivot_df, annot=True, cmap='YlGnBu', fmt='.0f', linewidths=0.5)
plt.title('Revenue by Restaurant (top 10) and Day of the Week')
plt.xlabel('Day of the Week')
plt.ylabel('Restaurant')
plt.show()
No description has been provided for this image
In [36]:
correlation = df.corr()

sns.heatmap(correlation, annot=True, cmap="ocean_r");
plt.xticks(rotation=45)
plt.show()
No description has been provided for this image
In [37]:
plt.figure(figsize = (5,3))
sns.pairplot(data=df[['cost_of_the_order', 'food_preparation_time', 'delivery_time', 'rating', 'total_time', 'revenue']], palette='ocean_r', diag_kind="kde")
plt.show()
<Figure size 500x300 with 0 Axes>
No description has been provided for this image

Conclusion and Recommendations¶

Question 17: What are your conclusions from the analysis? What recommendations would you like to share to help improve the business? (You can use cuisine type and feedback ratings to drive your business recommendations.) [6 marks]¶

Conclusions:¶

  • Deliver time on the weekdays is longer.
  • Shake shack and The Meatball shop are the biggest revenue generators
  • American and Japenese cuisine are the biggest revenue generators
  • There are too many missing ratings

Recommendations:¶

  • Give drivers incentive to work on weekdays to decrease weekday delivery time.
  • Promote French and Middle easter on weekdays to increase revenue.
  • Promote French, Southern and Thai on weekdays to increase revenue.
  • Give customers incentives to complete the ratings to imporve data.
  • Offer discounts on weekday orders to increase revenue during the week. This would also likely give additional incentive to drivers to want to deliver on weekdays which would likely result in faster delivery times. Faster delivery times would likey result in improved ratings.
  • Offer incentives to customers for restaurants that have higher order averages and consequently offer higher revenue percentages.
  • Offer incentives to customers to increase their order size.
  • Look for more restaurants/cuisines styles like the most popular ones.