4/19/26, 11:55 PM Data_Science_Project_Final (1).
ipynb - Colab
keyboard_arrow_down Hotel Booking Data Science Analysis
keyboard_arrow_down Install & Explore NumPy, Pandas, SciPy, Seaborn
import numpy as np
import pandas as pd
import [Link] as plt
import seaborn as sns
import [Link] as stats
import os, kagglehub
from [Link] import norm
from mpl_toolkits.mplot3d import Axes3D
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics
from [Link] import MinMaxScaler
sns.set_theme(style="whitegrid")
print(f"NumPy {np.__version__} | Pandas {pd.__version__} | Seaborn {sns.__version__}")
NumPy 2.0.2 | Pandas 2.2.2 | Seaborn 0.13.2
keyboard_arrow_down Working with NumPy Arrays
# NumPy Array Operations
n = [Link]([1, 2, 3, 5, 7, 2, 4, 6, 3, 1])
r = [Link](50, 201, 15)
print(f"Max: {[Link]()} | Min: {[Link]()} | Mean: {[Link]():.2f}")
print("Reshaped (2x5):\n", [Link](2, 5))
print("Square Root:", [Link]([Link](n), 2))
print("Logarithm:", [Link]([Link](r), 2))
# Random and Linear space
[Link](42)
print("Zeros:", [Link](5))
print("Ones:", [Link](5))
print("Random Normal:", [Link](5).round(3))
print("Linspace:", [Link]([Link](0, 1, 12), 2))
# Matrix Math
g = [Link](9).reshape(3, 3)
print("Matrix G:\n", g)
print("G + G:\n", g + g)
print("G * G:\n", g * g)
Max: 7 | Min: 1 | Mean: 3.40
Reshaped (2x5):
[[1 2 3 5 7]
[2 4 6 3 1]]
Square Root: [1. 1.41 1.73 2.24 2.65 1.41 2. 2.45 1.73 1. ]
Logarithm: [3.91 4.17 4.38 4.55 4.7 4.83 4.94 5.04 5.14 5.22 5.3 ]
Zeros: [0. 0. 0. 0. 0.]
Ones: [1. 1. 1. 1. 1.]
Random Normal: [ 0.497 -0.138 0.648 1.523 -0.234]
Linspace: [0. 0.09 0.18 0.27 0.36 0.45 0.55 0.64 0.73 0.82 0.91 1. ]
Matrix G:
[[0 1 2]
[3 4 5]
[6 7 8]]
G + G:
[[ 0 2 4]
[ 6 8 10]
[12 14 16]]
G * G:
[[ 0 1 4]
[ 9 16 25]
[36 49 64]]
[Link] 1/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
keyboard_arrow_down Working with Pandas DataFrames
# Pandas DataFrames Basics
data = {
'hotel_type': ['City', 'Resort', 'City', 'Resort', 'City'],
'nights': [3, 7, 2, 5, 1],
'adr': [120.5, 85, 200, 95, 150],
'canceled': [0, 0, 1, 0, 1]
}
df_sample = [Link](data)
df_sample['revenue'] = df_sample['nights'] * df_sample['adr']
print("Sample DataFrame:\n", df_sample)
print("\nCanceled Bookings:\n", df_sample[df_sample['canceled'] == 1])
print("\nSlicing (Rows 1-3, nights & adr):\n", df_sample.loc[1:3, ['nights', 'adr']])
# Multi-Index Example
index = [Link].from_tuples([('Q1', 'Jan'), ('Q1', 'Feb'), ('Q2', 'Jan'), ('Q2', 'Feb')])
dm = [Link]([Link](4, 2), index=index, columns=['City', 'Resort'])
print("\nMulti-Index DataFrame:\n", dm)
print("\nAccessing Q1:\n", [Link]['Q1'])
Sample DataFrame:
hotel_type nights adr canceled revenue
0 City 3 120.5 0 361.5
1 Resort 7 85.0 0 595.0
2 City 2 200.0 1 400.0
3 Resort 5 95.0 0 475.0
4 City 1 150.0 1 150.0
Canceled Bookings:
hotel_type nights adr canceled revenue
2 City 2 200.0 1 400.0
4 City 1 150.0 1 150.0
Slicing (Rows 1-3, nights & adr):
nights adr
1 7 85.0
2 2 200.0
3 5 95.0
Multi-Index DataFrame:
City Resort
Q1 Jan -0.234137 1.579213
Feb 0.767435 -0.469474
Q2 Jan 0.542560 -0.463418
Feb -0.465730 0.241962
Accessing Q1:
City Resort
Jan -0.234137 1.579213
Feb 0.767435 -0.469474
keyboard_arrow_down Reading Data & Descriptive Analytics
path = kagglehub.dataset_download("mojtaba142/hotel-booking")
csv_path = next([Link](r, f) for r, d, fs in [Link](path) for f in fs if [Link]('.csv'))
df = pd.read_csv(csv_path)
display([Link]())
[Link]()
print("\nMissing:\n", [Link]().sum().nlargest(5))
[Link] 2/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
Using Colab cache for faster access to the 'hotel-booking' dataset.
hotel is_canceled lead_time arrival_date_year arrival_date_month arrival_date_week_number arrival_date_day_of_month st
Resort
0 0 342 2015 July 27 1
Hotel
Resort
1 0 737 2015 July 27 1
Hotel
Resort
2 0 7 2015 July 27 1
Hotel
Resort
3 0 13 2015 July 27 1
Hotel
Resort
4 0 14 2015 July 27 1
Hotel
5 rows × 36 columns
<class '[Link]'>
RangeIndex: 119390 entries, 0 to 119389
Data columns (total 36 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 hotel 119390 non-null object
1 is_canceled 119390 non-null int64
2 lead_time 119390 non-null int64
3 arrival_date_year 119390 non-null int64
4 arrival_date_month 119390 non-null object
5 arrival_date_week_number 119390 non-null int64
6 arrival_date_day_of_month 119390 non-null int64
7 stays_in_weekend_nights 119390 non-null int64
8 stays_in_week_nights 119390 non-null int64
9 adults 119390 non-null int64
10 children 119386 non-null float64
11 babies 119390 non-null int64
12 meal 119390 non-null object
13 country 118902 non-null object
14 market_segment 119390 non-null object
15 distribution_channel 119390 non-null object
16 is_repeated_guest 119390 non-null int64
17 previous_cancellations 119390 non-null int64
18 previous_bookings_not_canceled 119390 non-null int64
19 reserved_room_type 119390 non-null object
20 assigned_room_type 119390 non-null object
21 booking_changes 119390 non-null int64
22 deposit_type 119390 non-null object
23 agent 103050 non-null float64
24 company 6797 non-null float64
25 days_in_waiting_list 119390 non-null int64
26 customer_type 119390 non-null object
27 adr 119390 non-null float64
28 required_car_parking_spaces 119390 non-null int64
29 total_of_special_requests 119390 non-null int64
30 reservation_status 119390 non-null object
31 reservation_status_date 119390 non-null object
32 name 119390 non-null object
33 email 119390 non-null object
34 phone-number 119390 non-null object
35 credit_card 119390 non-null object
dtypes: float64(4), int64(16), object(16)
memory usage: 32.8+ MB
Missing:
company 112593
agent 16340
country 488
children 4
hotel 0
dtype: int64
df = [Link]({'children': 0, 'agent': 0, 'company': 0, 'country': 'Unknown'}).drop_duplicates()
df = df[(df[['adults', 'children', 'babies']].sum(axis=1) > 0) & df['adr'].between(0, 5000)]
df = [Link](columns={'adr': 'avg_daily_rate'})
print(f"Cleaned Shape: {[Link]}")
[Link] 3/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
for col in ['hotel', 'country', 'meal']:
print(f"\nTop 5 {col}:\n", df[col].value_counts().head(5))
Cleaned Shape: (119208, 36)
Top 5 hotel:
hotel
City Hotel 79162
Resort Hotel 40046
Name: count, dtype: int64
Top 5 country:
country
PRT 48482
GBR 12119
FRA 10401
ESP 8560
DEU 7285
Name: count, dtype: int64
Top 5 meal:
meal
BB 92234
HB 14458
SC 10549
Undefined 1169
FB 798
Name: count, dtype: int64
keyboard_arrow_down Statistical Analysis
Univariate Analysis
Computing mean, median, mode, variance, std deviation, and skewness.
for col in ['avg_daily_rate', 'stays_in_week_nights']:
s = df[col]
print(f"\n--- {col} ---\nMean: {[Link]():.2f} | Median: {[Link]():.2f} | Std: {[Link]():.2f} | Skew: {[Link](s):.3f}")
print(f"Percentiles: {[Link](s, [25, 50, 75, 90])}")
--- avg_daily_rate ---
Mean: 101.93 | Median: 94.95 | Std: 48.04 | Skew: 1.030
Percentiles: [ 69.5 94.95 126. 164.05]
--- stays_in_week_nights ---
Mean: 2.50 | Median: 2.00 | Std: 1.90 | Skew: 2.755
Percentiles: [1. 2. 3. 5.]
keyboard_arrow_down Bivariate Analysis – Linear & Logistic Regression
def fit_eval(X, y, kind='linear'):
xt, xv, yt, yv = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression().fit(xt, yt) if kind=='linear' else LogisticRegression(max_iter=1000).fit(xt, yt)
pred = [Link](xv)
if kind=='linear':
print(f"[Linear] R2: {metrics.r2_score(yv, pred):.4f} | MAE: {metrics.mean_absolute_error(yv, pred):.2f}")
else:
print(f"[Logistic] Accuracy: {metrics.accuracy_score(yv, pred):.4f}\n", metrics.classification_report(yv, pred))
return model, xv, yv
lin_m, x_l, y_l = fit_eval(df[['lead_time']], df['avg_daily_rate'])
log_feats = ['lead_time', 'stays_in_week_nights', 'adults', 'avg_daily_rate']
log_m, _, _ = fit_eval(df[log_feats], df['is_canceled'], 'logistic')
[Link](figsize=(10, 5))
sidx = x_l['lead_time'].argsort()
[Link](x_l, y_l, alpha=0.1, s=5)
[Link](x_l.iloc[sidx], lin_m.predict(x_l.iloc[sidx]), 'r', lw=2)
[Link]('Lead Time vs ADR'); [Link]()
[Link] 4/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
[Linear] R2: 0.0043 | MAE: 36.12
[Logistic] Accuracy: 0.6624
precision recall f1-score support
0 0.68 0.88 0.77 14909
1 0.60 0.29 0.39 8933
accuracy 0.66 23842
macro avg 0.64 0.59 0.58 23842
weighted avg 0.65 0.66 0.63 23842
keyboard_arrow_down Multiple Regression Analysis
mf = ['lead_time', 'stays_in_week_nights', 'stays_in_weekend_nights', 'adults', 'children', 'total_of_special_requests']
mm = LinearRegression().fit(df[mf], df['avg_daily_rate'])
print("Coefficients:", dict(zip(mf, mm.coef_.round(4))))
display(df[mf + ['avg_daily_rate']].corr().round(3))
Coefficients: {'lead_time': np.float64(-0.0343), 'stays_in_week_nights': np.float64(1.0762), 'stays_in_weekend_nights': [Link]
lead_time stays_in_week_nights stays_in_weekend_nights adults children total_of_special_requests a
lead_time 1.000 0.167 0.086 0.118 -0.038 -0.096
stays_in_week_nights 0.167 1.000 0.494 0.096 0.045 0.069
stays_in_weekend_nights 0.086 0.494 1.000 0.095 0.046 0.073
adults 0.118 0.096 0.095 1.000 0.029 0.123
children -0.038 0.045 0.046 0.029 1.000 0.082
total_of_special_requests -0.096 0.069 0.073 0.123 0.082 1.000
avg_daily_rate -0.068 0.071 0.054 0.235 0.341 0.182
keyboard_arrow_down Plotting Functions
Normal Curves
fig, axes = [Link](1, 2, figsize=(14, 4))
for ax, (col, c) in zip(axes, [('avg_daily_rate', 'royalblue'), ('lead_time', 'tomato')]):
x = [Link](df[col].min(), df[col].max(), 100)
[Link](x, [Link](x, df[col].mean(), df[col].std()), color=c, lw=2)
ax.set_title(f'Normal: {col}')
[Link]()
[Link] 5/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
keyboard_arrow_down Density and Contour Plots
fig, axes = [Link](1, 3, figsize=(18, 5))
[Link]('hotel')['avg_daily_rate'].[Link](ax=axes[0], legend=True, title='ADR Density')
smp = [Link](2000, random_state=42)
axes[1].scatter(smp.lead_time, smp.avg_daily_rate, alpha=0.1, s=5)
h2, xe, ye = np.histogram2d(smp.lead_time, smp.avg_daily_rate, bins=30)
xc, yc = 0.5*(xe[:-1]+xe[1:]), 0.5*(ye[:-1]+ye[1:])
axes[2].contourf(xc, yc, h2.T, cmap='RdYlGn')
[Link]()
# Correlation Heatmap and Color-coded Scatter
analysis_cols = ['lead_time', 'stays_in_week_nights', 'stays_in_weekend_nights', 'adults', 'avg_daily_rate', 'total_of_special_re
fig, (ax_heat, ax_scat) = [Link](1, 2, figsize=(16, 6))
# Heatmap
[Link](df[analysis_cols].corr(), annot=True, fmt='.2f', cmap='coolwarm', ax=ax_heat)
ax_heat.set_title('Correlation Heatmap')
# Scatter with Cancellation mapping
cancel_colors = df['is_canceled'].map({0: 'green', 1: 'red'})
ax_scat.scatter(df['adults'], df['avg_daily_rate'], c=cancel_colors, alpha=0.1, s=5)
ax_scat.set(title='ADR vs Adults (Green=Success, Red=Canceled)', xlabel='Adults', ylabel='ADR')
plt.tight_layout()
[Link]()
[Link] 6/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
keyboard_arrow_down Histograms
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'Decemb
df['arrival_date_month'] = [Link](df['arrival_date_month'], categories=months, ordered=True)
fig, axes = [Link](2, 3, figsize=(15, 8))
for i, (col, c) in enumerate([('avg_daily_rate','b'), ('lead_time','r'), ('stays_in_week_nights','g')]):
axes[0,i].hist(df[col], bins=40, color=c)
[Link].value_counts().[Link](ax=axes[1,0], rot=0)
df.arrival_date_month.value_counts().sort_index().[Link](ax=axes[1,1])
axes[1,2].hist2d(df.lead_time, df.avg_daily_rate, bins=30, cmap='Blues')
plt.tight_layout(); [Link]()
keyboard_arrow_down Three-Dimensional Plotting
s3 = [Link](1000, random_state=42)
fig = [Link](figsize=(15, 10))
ax1 = fig.add_subplot(221, projection='3d')
[Link](s3.lead_time, s3.stays_in_week_nights, s3.avg_daily_rate, c=s3.avg_daily_rate)
xs2 = [Link](-3, 3, 50); X2, Y2 = [Link](xs2, xs2); Z2 = [Link]([Link](X2**2 + Y2**2))
fig.add_subplot(222, projection='3d').plot_surface(X2, Y2, Z2, cmap='coolwarm')
fig.add_subplot(223, projection='3d').plot_wireframe(X2, Y2, Z2)
ax4 = fig.add_subplot(224, projection='3d')
ax4.bar3d(s3.lead_time[:20], s3.avg_daily_rate[:20], 0, 5, 5, s3.stays_in_week_nights[:20])
[Link]()
[Link] 7/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
keyboard_arrow_down Geographic Data Visualization with Basemap
Guest countries are plotted on a world map using country-level data.
cc = [Link].value_counts().head(10)
fig, (ax1, ax2) = [Link](1, 2, figsize=(15, 5))
[Link](ax=ax1); [Link](cc, labels=[Link], autopct='%1.1f%%'); [Link]()
[Link] 8/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
keyboard_arrow_down Full EDA Dashboard
Combined visualisation covering all important business insights.
fig, axes = [Link](3, 3, figsize=(18, 14))
([Link]('hotel')['is_canceled'].mean()*100).[Link](ax=axes[0,0], rot=0, title='Cancel %')
[Link](x='hotel', y='avg_daily_rate', data=df, ax=axes[0,1]).set(ylim=(0, 400))
df.arrival_date_month.value_counts().sort_index().plot(ax=axes[0,2], marker='o')
for i, col in enumerate(['customer_type', 'meal', 'distribution_channel']):
df[col].value_counts().[Link](ax=axes[1,i], title=col)
cnt, edges = [Link](df.avg_daily_rate, bins=50, density=True)
pdf = cnt/[Link]()
axes[2,0].plot(edges[1:], pdf, label='PDF'); axes[2,0].plot(edges[1:], [Link](pdf), label='CDF'); axes[2,0].legend()
[Link](df[['lead_time','avg_daily_rate','is_canceled']].corr(), annot=True, ax=axes[2,1])
axes[2,2].hexbin(df.lead_time, df.avg_daily_rate, gridsize=20, cmap='Blues')
plt.tight_layout(); [Link]()
keyboard_arrow_down Cancellation Risk Tier Calculator
df['risk_score'] = MinMaxScaler(feature_range=(0,100)).fit_transform(log_m.predict_proba(df[log_feats])[:,1].reshape(-1,1)).rou
df['risk_tier'] = [Link](df['risk_score'], bins=[0, 35, 65, 100], labels=['Low', 'Medium', 'High'], include_lowest=True)
df['deposit'] = df['avg_daily_rate'] * df['risk_tier'].map({'Low':0.1, 'Medium':0.25, 'High':0.5}).astype(float)
df['rev'] = df['avg_daily_rate'] * (df['stays_in_week_nights'] + df['stays_in_weekend_nights'])
display([Link]('risk_tier', observed=True).agg(bookings=('risk_score','count'), cancel_rate=('is_canceled','mean'), avg_dep
[Link] 9/10
4/19/26, 11:55 PM Data_Science_Project_Final (1).ipynb - Colab
fig, axes = [Link](1, 3, figsize=(18, 5))
clrs = {'Low':'seagreen', 'Medium':'goldenrod', 'High':'tomato'}
for t, c in [Link](): axes[0].hist(df[df['risk_tier']==t]['risk_score'], bins=20, alpha=0.6, color=c, label=t)
([Link]('risk_tier', observed=True)['is_canceled'].mean()*100).plot(kind='bar', ax=axes[1], color=[Link]())
canc = df[df['is_canceled']==1]
l, r = [Link]('risk_tier', observed=True)['rev'].sum()/1e6, [Link]('risk_tier', observed=True)['deposit'].sum()/1e6
axes[2].bar([Link](), l, color='grey', alpha=0.3); axes[2].bar([Link](), r, color=[Link]())
[Link]()
print(f"Lost: ${[Link]():,.2f} | Rec: ${[Link]():,.2f} | Rate: {([Link]()/[Link]())*100:.2f}%")
bookings cancel_rate avg_dep_pct
risk_tier
Low 76868 0.286 0.10
Medium 35083 0.495 0.25
High 7257 0.670 0.50
$ | $ |
[Link] 10/10