Kaggle项目:酒店预订需求数据的探索与预测

您所在的位置:网站首页 餐饮预订信息表格 Kaggle项目:酒店预订需求数据的探索与预测

Kaggle项目:酒店预订需求数据的探索与预测

2024-07-04 07:30| 来源: 网络整理| 查看: 265

EDA and Predictive Analysis of Hotel Booking Demand Datasets 2.0

数据背景:该数据集包含酒店预订相关信息,数据信息范围包括:酒店类型、订单是否取消、预订时间、入住时长、入住人数、用户国籍等。

数据分析目的:1、分析用户的特征分布;2、分析酒店业务经营情况 ;3、预测酒店订单是否会被取消,找出重要影响因素

数据来源链接: https://www.kaggle.com/jessemostipak/hotel-booking-demand

以下通过Python对酒店预订数据进行探索性数据分析(Exploratory Data Analysis)和预测分析(Predictive Analysis):

一、数据准备 import os import zipfile import pandas as pd import numpy as np import datetime as dt import matplotlib.pyplot as plt import seaborn as sns import warnings # 忽略警告 warnings.filterwarnings('ignore') # 正常显示中文和负号 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False # 可视化显示在页面 %matplotlib inline # 设定绘图风格 plt.style.use('ggplot') # 声明变量 dataset_path = './' # 数据集路径 zip_filename = 'archive_4.zip' # zip文件名 zip_filepath = os.path.join(dataset_path, zip_filename) # zip文件路径 # 解压数据集 with zipfile.ZipFile(zip_filepath) as zf: dataset_filename = zf.namelist()[0] # 数据集文件名(在zip中) dataset_filepath = os.path.join(dataset_path, dataset_filename) # 数据集文件路径 print ("解压zip...",) zf.extractall(path = dataset_path) print ("完成。") 解压zip... 完成。 # 导入数据集 df_data = pd.read_csv(dataset_filepath) # 查看加载的数据基本信息 print ('数据集基本信息:') df_data.info() 数据集基本信息: RangeIndex: 119390 entries, 0 to 119389 Data columns (total 32 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 dtypes: float64(4), int64(16), object(12) memory usage: 29.1+ MB

总共有32个列标签,119390条数据记录,存在缺失数据。

二、数据清洗 # 逐条预览每个字段的数据计数,例: col_data=df_data['meal'].value_counts() plt.barh(y=col_data.index,width=col_data.values,height=0.5)

在这里插入图片描述

分析字段数据的含义并对32个列标签初步分类,拟定数据清洗方法,如下表: 在这里插入图片描述

(一)缺失数据处理 #复制源数据 df_copy=df_data.copy() # 查看有缺失数据的字段缺失个数占比 print ('缺失个数占比:') df_copy.isnull().sum()[df_copy.isnull().sum()!=0]/df_copy.shape[0] 缺失个数占比: children 0.000034 country 0.004087 agent 0.136862 company 0.943069 dtype: float64 # 'children'列缺失值较少,直接删除缺失的行 df_copy.dropna(subset=['children'],inplace=True) # 'country'列缺失值较少,直接删除缺失的行 df_copy.dropna(subset=['country'],inplace=True) #‘agent'列缺失值占比近14%,使用0替换列中的缺失值 df_copy['agent'].fillna(value=0, inplace = True) # 'company'列缺失值过多,占比约94%,直接删除列 df_copy.drop(['company'],axis =1,inplace=True) # 查验是否还有缺失数据 print ('含缺失数据的列的个数:') df_copy.isnull().sum()[df_copy.isnull().sum()!=0].count() 含缺失数据的列的个数: 0 (二)删除重复记录

数据集无主键,暂不处理重复记录

(三)异常值处理 # 剔除入住晚数为0的记录 df_copy.drop(df_copy[df_copy['stays_in_weekend_nights']+df_copy['stays_in_week_nights']==0].index,inplace=True) # 剔除入住人数为0的记录 df_copy.drop(df_copy[df_copy['adults']+df_copy['children']+df_copy['babies']==0].index,inplace=True) # 将'children'字段数据类型修改为整型 df_copy.children = df_copy.children.astype(int) # 将'meal'字段中的Undefined 修改为 SC df_copy.meal.replace("Undefined", "SC", inplace=True) # 将'agent'字段数据类型修改为字符串型 df_copy.agent = df_copy.agent.astype(int) df_copy['agent'] = df_copy['agent'].apply(str) #查看'adr'字段数据分布 plt.boxplot(df_copy['adr']) {'whiskers': [, ], 'caps': [, ], 'boxes': [], 'medians': [], 'fliers': [], 'means': []}

在这里插入图片描述

#删除'adr'字段离群点 df_copy.drop(df_copy[df_copy['adr']>5000].index,inplace=True) # 重置索引 df_copy.reset_index(drop=True,inplace=True) # 查验加载的数据基本信息 print ('数据集基本信息:') df_copy.info() 数据集基本信息: RangeIndex: 118087 entries, 0 to 118086 Data columns (total 31 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 hotel 118087 non-null object 1 is_canceled 118087 non-null int64 2 lead_time 118087 non-null int64 3 arrival_date_year 118087 non-null int64 4 arrival_date_month 118087 non-null object 5 arrival_date_week_number 118087 non-null int64 6 arrival_date_day_of_month 118087 non-null int64 7 stays_in_weekend_nights 118087 non-null int64 8 stays_in_week_nights 118087 non-null int64 9 adults 118087 non-null int64 10 children 118087 non-null int32 11 babies 118087 non-null int64 12 meal 118087 non-null object 13 country 118087 non-null object 14 market_segment 118087 non-null object 15 distribution_channel 118087 non-null object 16 is_repeated_guest 118087 non-null int64 17 previous_cancellations 118087 non-null int64 18 previous_bookings_not_canceled 118087 non-null int64 19 reserved_room_type 118087 non-null object 20 assigned_room_type 118087 non-null object 21 booking_changes 118087 non-null int64 22 deposit_type 118087 non-null object 23 agent 118087 non-null object 24 days_in_waiting_list 118087 non-null int64 25 customer_type 118087 non-null object 26 adr 118087 non-null float64 27 required_car_parking_spaces 118087 non-null int64 28 total_of_special_requests 118087 non-null int64 29 reservation_status 118087 non-null object 30 reservation_status_date 118087 non-null object dtypes: float64(1), int32(1), int64(16), object(13) memory usage: 27.5+ MB 三、数据分析及可视化 (一)用户的特征分布

从用户属性、用户行为分析用户的特征分布,判断其对取消订单的相关性:

1、用户的地域分布 #引入世界地图信息表 import geopandas world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres')) #按'country'字段分组对酒店的订单量计数 df_country=df_copy['country'].value_counts().reset_index().rename (columns= {'index': 'code','country':'num_order'}) #将酒店订单量数据并入世界地图信息表 df_country = world.merge(df_country, how="left", left_on=['iso_a3'], right_on=['code']) df_country.head() pop_estcontinentnameiso_a3gdp_md_estgeometrycodenum_order0889953.0OceaniaFijiFJI5496MULTIPOLYGON (((180.00000 -16.06713, 180.00000...FJI1.0158005463.0AfricaTanzaniaTZA63177POLYGON ((33.90371 -0.95000, 34.07262 -1.05982...TZA4.02603253.0AfricaW. SaharaESH907POLYGON ((-8.66559 27.65643, -8.66512 27.58948...NaNNaN337589262.0North AmericaCanadaCAN1736425MULTIPOLYGON (((-122.84000 49.00000, -122.9742...NaNNaN4328239523.0North AmericaUnited States of AmericaUSA21433226MULTIPOLYGON (((-122.84000 49.00000, -120.0000...USA2089.0 #概览来自不同地区客户的酒店订单量的计数分布 plt.boxplot(df_copy['country'].value_counts()) {'whiskers': [, ], 'caps': [, ], 'boxes': [], 'medians': [], 'fliers': [], 'means': []}

在这里插入图片描述

根据箱线图可知,酒店客户主要集中在部分地区,可视化过程中应重点突出该部分地区。

#可视化 fig, ax = plt.subplots(1, figsize=(25,10)) df_country.plot(column='num_order', cmap='ocean_r', linewidth=0.8, ax=ax, edgecolors='0.8',legend=True,\ missing_kwds={'color': 'lightgrey'}) ax.set_title('Order Quantity of Customers from different Countries ', fontdict={'fontsize':30}) ax.set_axis_off()

在这里插入图片描述

根据地区分布图可知,酒店客户主要来自西欧国家。其中,来自葡萄牙的客户订单量最多,占总订单量近一半,其次订单主要集中来自英国、法国、西班牙、德国。

#筛选订单量前五的地区数据 df_copy_top5 = df_copy.loc[df_copy['country'].isin(['PRT','GBR','FRA','ESP','DEU'])] # 订单量前五地区 grouped_df_copy_top5 = df_copy_top5.pivot_table(values='hotel',index='country',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_copy_top5.plot(kind='bar',title='订单量前五地区')

在这里插入图片描述

根据上图发现,葡萄牙用户订单取消的概率远高于其他地区用户。

2、新老用户分布 # 新老客户的订单量 grouped_df_guest = df_copy.pivot_table(values='hotel',index='is_repeated_guest',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_guest.plot(kind='bar',title='新老客户订单量')

在这里插入图片描述

根据新老客户分布可知,酒店订单主要来自新客户,而老客户取消订单的概率明显低于新客户。

3、客户类型分布 # 各客户类型的订单量 grouped_df_ct = df_copy.pivot_table(values='hotel',index='customer_type',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_ct.plot(kind='bar',title='客户类型订单量')

在这里插入图片描述

根据客户类型分布可知,酒店订单主要来自过往旅客,高于其他客户。此外,跟团旅客取消订单可能性很小。

4、客户历史取消率 # 复制df_copy表 df_copy_pb = df_copy.copy() #计算历史订单取消率,创建新列'canceled_rate' df_copy_pb['canceled_rate'] = (df_copy_pb['previous_cancellations']/(df_copy_pb['previous_bookings_not_canceled']\ +df_copy_pb['previous_cancellations'])).replace(np.nan,0) # 历史订单取消率分布 grouped_df_copy_pb = df_copy_pb.pivot_table(values='is_canceled',index='canceled_rate', aggfunc='mean') # 可视化 sns.jointplot(x=grouped_df_copy_pb.index, y=grouped_df_copy_pb.is_canceled, kind='reg')

在这里插入图片描述

根据上图可知,用户d 历史订单取消率与是否取消酒店订单有一定的相关性。

5、订单预订时长和确定时长分布 # 预订时长对应的订单取消率 grouped_df_lt = df_copy.pivot_table(values='is_canceled',index='lead_time',aggfunc='mean') # 可视化 fig, ax = plt.subplots(1, figsize=(18,6)) grouped_df_lt.plot(kind='bar', ax=ax, title='预订时长对应的订单取消率')

在这里插入图片描述

由上图可知,预订时长越长,酒店订单被取消的概率显着增长。

# 确认时长对应的订单取消率 grouped_df_diwl = df_copy.pivot_table(values='is_canceled',index='days_in_waiting_list',aggfunc='mean') # 可视化 fig, ax = plt.subplots(1, figsize=(18,6)) grouped_df_diwl.plot(kind='bar', ax=ax, title='确认时长对应的订单取消率')

在这里插入图片描述

根据上图,未发现确认时长与酒店订单被取消的相关关系。

6、客户入住时间分布 # 查看每年月份是否完整 df_copy.drop_duplicates(['arrival_date_year','arrival_date_month'])[['arrival_date_year','arrival_date_month']] arrival_date_yeararrival_date_month02015July8252015August14542015September20542015October27892015November32122015December36692016January37942016February42042016March47302016April54462016May61942016June66832016July71872016August77952016September83972016October90912016November93662016December96862017January98892017February102712017March106622017April111932017May117362017June123642017July130202017August

由上表可知,数据集包含的入住时间范围为2015年下半年、2016年完整年及2017年1-8月。

# 复制df_copy表 df_copy_t = df_copy.copy() # 对入住月份进行映射,创建入住季度字段'arrival_date_season' df_copy_t['arrival_date_season'] = df_copy_t['arrival_date_month'].map({'January':'冬季','February':'春季','March':'春季',\ 'April':'春季','May':'夏季','June':'夏季','July':'夏季',\ 'August':'秋季','September':'秋季','October':'秋季',\ 'November':'冬季','December':'冬季'}) # 按季度自定义排序 from pandas.api.types import CategoricalDtype cat_size_order = CategoricalDtype(['春季','夏季','秋季','冬季'], ordered=True) df_copy_t['arrival_date_season'] = df_copy_t['arrival_date_season'].astype(cat_size_order) # 选取2016年数据,排除其他因素干扰 df_copy_t_2016 = df_copy_t[df_copy_t['arrival_date_year']==2016] # 各季度的客户订单量 grouped_df_copy_t_2016 = df_copy_t_2016.pivot_table(values='hotel',index='arrival_date_season',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_copy_t_2016.plot(kind='bar',title='酒店各季度的客户订单量')

在这里插入图片描述

从时间分布可知,客户订单量随着季节的变化比较明显。其中,秋季为入住高峰,对应取消的订单较多,冬季为入住低峰,对应取消的订单也较少,入住季节与订单取消率未发现明显关联。

7、客户入住晚数分布 # 复制df_copy表 df_copy_n = df_copy.copy() #创建入住晚数字段'stays_in_nights' df_copy_n['stays_in_nights'] = df_copy_n['stays_in_weekend_nights'] + df_copy_n['stays_in_week_nights'] # 各入住晚数对应订单量 grouped_df_copy_n = df_copy_n.pivot_table(values='hotel',index='stays_in_nights',columns='is_canceled',aggfunc='count') # 可视化 fig, ax = plt.subplots(1, figsize=(18,6)) grouped_df_copy_n.plot(kind='bar',ax=ax, title='各入住晚数对应订单量')

在这里插入图片描述

根据入住晚数分布图,酒店订单对应的入住晚数主要集中在1-3晚,其中入住1晚的订单被取消的概率明显较小。入住7晚和14晚的订单量有异常增长,需根据酒店信息分层分析。

# 选取未被取消订单的数据 df_copy_n_0 = df_copy_n[df_copy_n['is_canceled']==0] # 各入住晚数对应入住订单量 grouped_df_copy_n_0 = df_copy_n_0.pivot_table(values='is_canceled',index='stays_in_nights',columns='hotel',aggfunc='count') # 可视化 fig, ax = plt.subplots(1, figsize=(18,6)) grouped_df_copy_n_0.plot(kind='bar',ax=ax, title='各入住晚数对应入住订单量')

在这里插入图片描述

从上图可知,入住7晚和14晚的异常订单量主要发生在度假酒店,可能与度假酒店优惠活动有关,需补充酒店信息相关数据进一步分析。

8、成人、孩子、婴儿入住人数分布 # 成人入住人数对应的订单取消率 grouped_df_a = df_copy.pivot_table(values='is_canceled',index='adults',aggfunc='mean') # 可视化 grouped_df_a.plot(kind='bar',title='成人入住人数对应的订单取消率')

在这里插入图片描述

由上图可知,成人入住人数在5及5以上的订单被取消概率极高。

# 孩子入住人数对应订单量 grouped_df_copy_c = df_copy.pivot_table(values='is_canceled',index='children',aggfunc='mean') # 可视化 grouped_df_copy_c.plot(kind='bar',title='孩子入住人数对应订单量')

在这里插入图片描述

由上图可知,孩子入住人数为10人的订单被取消概率极高。

# 婴儿入住人数对应订单量 grouped_df_copy_b = df_copy.pivot_table(values='is_canceled', index='babies', aggfunc='mean') # 可视化 grouped_df_copy_b.plot(kind='bar',title='婴儿入住人数对应订单量')

在这里插入图片描述

由上图可知,无婴儿入住的订单被取消的概率偏高。

9、订餐 # 各订餐类型的订单量 grouped_df_meal = df_copy.pivot_table(values='hotel',index='meal',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_meal.plot(kind='bar',title='订餐类型订单量')

在这里插入图片描述

由上图可知,订餐类型中早中晚餐全包(FB)的酒店订单被取消的可能性更大。

10、市场细分及分销渠道分布 # 市场细分的订单量 grouped_df_ms = df_copy.pivot_table(values='hotel',index='market_segment',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_ms.plot(kind='bar',title='市场细分的订单量')

在这里插入图片描述

根据上图可以看出,订单量按照市场细分后,其被取消的概率差异较大。

# 分销渠道的订单量 grouped_df_dc = df_copy.pivot_table(values='hotel',index='distribution_channel',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_dc.plot(kind='bar',title='分销渠道的订单量')

在这里插入图片描述

根据上图可以看出,订单量按照分销渠道细分后,'TA/TO’渠道被取消的概率较大。

11、房型分布 # 预订房型的订单取消率 grouped_df_rrt = df_copy.pivot_table(values='is_canceled',index='reserved_room_type',aggfunc='mean') # 可视化 grouped_df_rrt.plot(kind='bar',title='预订房型的订单取消率')

在这里插入图片描述

由上图可知,不同预订房型对应的订单取消率差异较小。

# 复制df_copy表 df_copy_rt = df_copy.copy() #创建字段'room_type_agreed',判断预订房型与酒店分配房型是否一致 df_copy_rt['room_type_agreed'] = np.where(df_copy_rt['reserved_room_type']==df_copy_rt['assigned_room_type'],1,0) # 房型是否一致的订单量 grouped_df_rt = df_copy_rt.pivot_table(values='hotel',index='room_type_agreed',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_rt.plot(kind='bar',title='房型是否一致的订单量')

在这里插入图片描述

根据上图,房型不一致的客户订单取消的概率较小,可能因为大部分房型不一致的情况属于房型升级,从而降低了退单率,也可能因为酒店非常受欢迎导致供不应求,从而客户退订的概率减小,需引入相关数据进一步分析。

12、订单变更分布 # 订单变更次数对应的订单取消率 grouped_df_bc = df_copy.pivot_table(values='is_canceled',index='booking_changes',aggfunc='mean') # 可视化 grouped_df_bc.plot(kind='bar',title='订单变更次数对应的订单取消率')

在这里插入图片描述

从上图发现,订单未做过变更或者变更次数达14、16次的,订单取消率较高。

13、押金类型分布 # 押金类型对应的订单量 grouped_df_dt = df_copy.pivot_table(values='hotel',index='deposit_type',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_dt.plot(kind='bar',title='押金类型对应的订单量')

在这里插入图片描述

根据上图,用户订单主要为无押金订单,不可退押金订单基本被取消,可退押金订单较少,需进一步查看取消率。

# 押金类型对应的订单量取消率 grouped_df_dtp = df_copy.pivot_table(values='is_canceled',index='deposit_type',aggfunc='mean') # 可视化 grouped_df_dtp.plot(kind='bar',title='押金类型对应的订单量取消率')

在这里插入图片描述

可退押金订单与无押金订单的取消率差距较小,不可退押金订单取消率接近于1,可根据用户属性和订单特征进一步分析退订原因。

14、代理商分布 # 订单量前10的代理商id df_copy['agent'].value_counts().head(10).index Index(['9', '0', '240', '1', '14', '7', '6', '250', '241', '28'], dtype='object') df_copy_a_top10 = df_copy.loc[df_copy['agent'].isin(['9', '0', '240', '1', '14', '7', '6', '250', '241', '28'])] # 代理商对应的订单量 grouped_df_a_top10 = df_copy_a_top10.pivot_table(values='hotel',index='agent',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_a_top10.plot(kind='bar',title='代理商对应的订单量')

在这里插入图片描述

根据上图,代理商9的订单占比最高,其次为无代理商订单。各代理商对应酒店订单的取消率差异较大,其中代理商1的取消率明显偏高,需根据退订客户的用户画像进一步分析。

15、需求数量分布 # 车位数量需求对应的订单量 grouped_df_rcps = df_copy.pivot_table(values='hotel',index='required_car_parking_spaces',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_rcps.plot(kind='bar',title='车位数量需求对应的订单量')

在这里插入图片描述

由上图可知,大部分订单没有车位需求,有1个车位需求的订单基本都未被取消。

# 特殊需求数量对应的订单量 grouped_df_tosr = df_copy.pivot_table(values='hotel',index='total_of_special_requests',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_tosr.plot(kind='bar',title='特殊需求数量对应的订单量')

在这里插入图片描述

根据上图可知,有特殊需求的客户订单被取消的概率较小。

16、预约状态分布 # 预约状态对应的订单量 grouped_df_rs = df_copy.pivot_table(values='hotel',index='reservation_status',columns='is_canceled',aggfunc='count') # 可视化 grouped_df_rs.plot(kind='bar',title='预约状态对应的订单量')

在这里插入图片描述

由上图可知,被取消的订单中大部分为用户直接取消,小部分用户未入住但告知酒店原因。

(二)酒店经营情况分析 # 复制df_copy表 df_copy_tri = df_copy.copy() # 创建'total_rental_income'列 df_copy_tri['total_rental_income']=(df_copy_tri['stays_in_weekend_nights']+df_copy_tri['stays_in_week_nights'])*df_copy_tri['adr'] # 筛除已取消预订的数据 df_copy_tri_0 = df_copy_tri[df_copy_tri['is_canceled']==0] 1、按年分析 # 酒店各年营业总额 df_copy_tri_0.pivot_table(values='total_rental_income',index='arrival_date_year',columns='hotel',aggfunc='sum')\ .plot(kind='bar',title='酒店各年营业收入总额')

在这里插入图片描述

由图可知,2015年下半年城市酒店营业收入低于度假酒店,2016年完整年及2017年1-8月城市酒店营业收入高于度假酒店;

2、按月分析 # 创建入住月份数值列'arrival_date_month_code' df_copy_tri_0['arrival_date_month_code'] = df_copy_tri_0['arrival_date_month']\ .map({'January':1,'February':2,'March':3,'April':4,'May':5,'June':6,\ 'July':7,'August':8,'September':9,'October':10,'November':11,'December':12 }) # 选取有完整月份的2016年数据 df_copy_tri_2016= df_copy_tri_0[df_copy_tri_0['arrival_date_year']==2016] # 酒店2016年各月营业收入总额 df_copy_tri_2016.pivot_table(values='total_rental_income',index='arrival_date_month_code',columns='hotel',aggfunc='sum')\ .plot(kind='bar',title='酒店2016年各月营业收入总额')

在这里插入图片描述

由图可知: 1、度假酒店仅7月和8月营业收入高于城市酒店,其他月份均低于城市酒店; 2、8月为酒店营业收入高峰时间,其中度假酒店每月营业收入分布峰度高于城市酒店。

# 酒店2016年各月平均adr(日均房价) df_copy_tri_2016.pivot_table(values='adr',index='arrival_date_month_code',columns='hotel',aggfunc='mean').plot(title='酒店2016年各月平均adr')

在这里插入图片描述

由图可知,度假酒店相比城市酒店各月的房价波动较大,其中度假酒店8月的日均房价最高,因此其8月的营业收入总额达到峰值。

四、预测酒店订单是否会被取消,找出重要影响因素 from sklearn import preprocessing from sklearn.model_selection import train_test_split from sklearn.preprocessing import OneHotEncoder from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.ensemble import AdaBoostClassifier from sklearn.metrics import confusion_matrix from sklearn.model_selection import cross_val_score from sklearn.model_selection import GridSearchCV # 查看酒店预订的情况 is_canceled = df_copy['is_canceled'].value_counts().reset_index() plt.figure(figsize = (6,6)) plt.title('酒店预订情况\n (预订:0, 取消:1)') sns.set_color_codes("pastel") sns.barplot(x = 'index', y='is_canceled', data=is_canceled)

在这里插入图片描述

# 复制df_copy表 df_copy2 = df_copy.copy() # 根据上文数据分析,删除与分类无关、暴露取消或入住后信息的特征列 df_copy2.drop(['arrival_date_year','arrival_date_month', 'arrival_date_week_number', 'arrival_date_day_of_month',\ 'days_in_waiting_list','adr','reservation_status', 'reservation_status_date'] ,axis =1,inplace=True) # 根据上文数据分析,对部分数值型特征列特殊处理 #计算历史订单取消率,创建新列'canceled_rate' df_copy2['canceled_rate'] = (df_copy2['previous_cancellations']/(df_copy2['previous_bookings_not_canceled']\ +df_copy2['previous_cancellations'])).replace(np.nan, 0) df_copy2.drop(['previous_cancellations','previous_bookings_not_canceled'] ,axis =1,inplace=True) # 选出数值型列特征选择 num_features = ['lead_time', 'stays_in_weekend_nights', 'stays_in_week_nights',\ 'adults', 'children', 'babies', 'is_repeated_guest', 'canceled_rate', 'booking_changes',\ 'required_car_parking_spaces','total_of_special_requests'] # 数值型列特征列数据标准化 X_num = StandardScaler().fit_transform(df_copy2[num_features]) # 根据上文数据分析,对部分字符型特征列特殊处理 #创建字段'room_type_agreed',判断预订房型与酒店分配房型是否一致 df_copy2['room_type_agreed'] = np.where(df_copy2['reserved_room_type']==df_copy2['assigned_room_type'],1,0) df_copy2.drop(['assigned_room_type','reserved_room_type'] ,axis =1,inplace=True) # 选出字符型特征列,对其独热编码 cat_features = ['hotel', 'meal', 'country', 'market_segment', 'distribution_channel', \ 'room_type_agreed', 'deposit_type', 'agent', 'customer_type'] X_cat = OneHotEncoder(handle_unknown='ignore').fit_transform(df_copy2[cat_features]).toarray() # 创建数据集 X = np.concatenate((X_num, X_cat),axis=1) y = df_copy2['is_canceled'].values # 30%作为测试集,其余作为训练集 train_x, test_x, train_y, test_y = train_test_split(X, y, test_size=0.30, stratify = y, random_state = 2) # 构造分类器 classifiers = [ LogisticRegression(), DecisionTreeClassifier(criterion='gini'), RandomForestClassifier(random_state = 2, criterion = 'gini'), KNeighborsClassifier(metric = 'minkowski'), AdaBoostClassifier() ] # 分类器名称 classifier_names = [ 'LogisticRegression', 'DecisionTreeClassifier', 'RandomForestClassifier', 'KNeighborsClassifier', 'AdaBoostClassifier' ] # 显示模型评估结果 def show_metrics(): tp = cm[1,1] fn = cm[1,0] fp = cm[0,1] tn = cm[0,0] print('精确率: {:.3f}'.format(tp/(tp+fp))) print('召回率: {:.3f}'.format(tp/(tp+fn))) print('F1值: {:.3f}'.format(2*(((tp/(tp+fp))*(tp/(tp+fn)))/((tp/(tp+fp))+(tp/(tp+fn)))))) # 使用分类器对酒店预订进行预测 for model, model_name in zip(classifiers, classifier_names): clf = model clf.fit(train_x, train_y) predict_y = clf.predict(test_x) # 计算混淆矩阵 cm = confusion_matrix(test_y, predict_y) # 显示模型评估分数 print(model_name+":") show_metrics() LogisticRegression: 精确率: 0.817 召回率: 0.717 F1值: 0.764 DecisionTreeClassifier: 精确率: 0.805 召回率: 0.806 F1值: 0.806 RandomForestClassifier: 精确率: 0.853 召回率: 0.808 F1值: 0.830 KNeighborsClassifier: 精确率: 0.802 召回率: 0.791 F1值: 0.796 AdaBoostClassifier: 精确率: 0.822 召回率: 0.719 F1值: 0.767

从对以上5个分类器的评估分数可知,随机森林分类器的预测效果综合性最强,精确率达0.853,召回率达0.808,均高于其他分类器,能更精准地预测和覆盖到将被取消的酒店订单。

#拟对随机森林分类器参数进行调优,绘制n_estimators的学习曲线,确定大致范围,间隔为10 rfc_s = [] for i in range(0,101,10): rfc = RandomForestClassifier(random_state = 2, criterion = 'gini', n_estimators=i) cvs = cross_val_score(rfc, train_x, train_y, cv=3).mean() rfc_s.append(cvs) plt.plot(range(0,101,10),rfc_s,label='随机森林') plt.legend()

在这里插入图片描述

# 根据上图缩小参数范围 parameters = {'n_estimators':[40,45,50,55,60]} # 使用GridSearchCV进行参数调优 clf = GridSearchCV(estimator=RandomForestClassifier(random_state = 2, criterion = 'gini'), param_grid=parameters, scoring='f1') # 对数据集进行分类 clf.fit(train_x, train_y) print("最优分数: %.3lf" %clf.best_score_) print("最优参数:", clf.best_params_) 最优分数: 0.825 最优参数: {'n_estimators': 55} #建立n_estimators为55的随机森林 rf = RandomForestClassifier(random_state = 2, criterion = 'gini', n_estimators=55) rf.fit(train_x, train_y) # 特征重要性 importances = rf.feature_importances_ # 标签名称 feat_labels = pd.concat([df_copy2[num_features], df_copy2['room_type_agreed'], df_copy2_dum], axis=1).columns # 下标排序 indices = np.argsort(importances)[::-1] # 找出重要性排前10的特征(-号代表左对齐、后补空白,*号代表对齐宽度由输入时确定) for f in range(10): print("%2d) %-*s %f" % (f + 1, 30, feat_labels[indices[f]], importances[indices[f]])) 1) lead_time 0.219403 2) country_PRI 0.067354 3) total_of_special_requests 0.065522 4) deposit_type_Non Refund 0.065501 5) deposit_type_Refundable 0.060866 6) stays_in_week_nights 0.059261 7) stays_in_weekend_nights 0.034379 8) canceled_rate 0.029086 9) booking_changes 0.023928 10) required_car_parking_spaces 0.023598

以上10个特征对酒店订单是否会被取消有较重要的影响,应重点关注,包括:预订时长、用户是否为葡萄牙国籍、是否有特殊需求数量、订单是否可退押金、入住晚数、用户历史订单取消率、订单变更次数、车位数量需求等。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3