R语言机器学习预测酒店预订取消

数听说明:

本分析报告中的数据来源于R社区的 tidytuesday 项目中的数据。这个项目在每周二会发布一份数据,供数据科学社区分析,并在twitter上相互分享分析结果,交流学习。node

image

业务问题:

对于酒店行业来讲,预订有两方面的意义:ios

  1. 酒店能够经过预订信息,对将来的需求有充分的准备,这是预订对业务有益的一个方面;
  2. 可是同时,若是以前的预订产生大量的取消的状况,则会对酒店业务产生不利的影响,若是大量被预订的房间被撤销,不少时候,空余出来的酒店房间并不能及时被租出去,则会对酒店的利用率产生不利的影响,于是,若是可以对酒店的预订状况做出比较准确的预测,对于那些取消风险高的客房,酒店则能够提早作出准备,避免或下降对业务损失。

数据获取与概览:

全部tidytuesday的数据均可以经过两个方式获取,能够安装tidytueday的R包或者直接经过read_csv从github上直接下载。若是你对以往的历史数据集感兴趣,能够访问下面的Tidytuesday at Github.git

1. 数据集下载:

library(tidyverse)
library(skimr)
library(lubridate)
library(stringr)
library(ggthemr)
ggthemr("flat")
hotel_bookings <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-02-11/hotels.csv')

咱们如今已经将数据存储在了hotel_bookings这个DF中,下面咱们能够经过skimr包中的skim函数对整个数据集有一个初步的把握:github

skim(hotel_bookings)
-- Data Summary ------------------------
                           Values        
Name                       hotel_bookings
Number of rows             119390        
Number of columns          32            
_______________________                  
Column type frequency:                   
  character                13            
  Date                     1             
  numeric                  18            
________________________                 
Group variables            None          

-- Variable type: character ------------------------------------------------------------------------------------------------------
# A tibble: 13 x 8
   skim_variable        n_missing complete_rate   min   max empty n_unique whitespace
 * <chr>                    <int>         <dbl> <int> <int> <int>    <int>      <int>
 1 hotel                        0             1    10    12     0        2          0
 2 arrival_date_month           0             1     3     9     0       12          0
 3 meal                         0             1     2     9     0        5          0
 4 country                      0             1     2     4     0      178          0
 5 market_segment               0             1     6    13     0        8          0
 6 distribution_channel         0             1     3     9     0        5          0
 7 reserved_room_type           0             1     1     1     0       10          0
 8 assigned_room_type           0             1     1     1     0       12          0
 9 deposit_type                 0             1    10    10     0        3          0
10 agent                        0             1     1     4     0      334          0
11 company                      0             1     1     4     0      353          0
12 customer_type                0             1     5    15     0        4          0
13 reservation_status           0             1     7     9     0        3          0

-- Variable type: Date -----------------------------------------------------------------------------------------------------------
# A tibble: 1 x 7
  skim_variable           n_missing complete_rate min        max        median     n_unique
* <chr>                       <int>         <dbl> <date>     <date>     <date>        <int>
1 reservation_status_date         0             1 2014-10-17 2017-09-14 2016-08-07      926

-- Variable type: numeric --------------------------------------------------------------------------------------------------------
# A tibble: 18 x 11
   skim_variable                  n_missing complete_rate       mean       sd      p0    p25    p50   p75  p100 hist 
 * <chr>                              <int>         <dbl>      <dbl>    <dbl>   <dbl>  <dbl>  <dbl> <dbl> <dbl> <chr>
 1 is_canceled                            0          1       0.370     0.483     0       0      0       1     1 ▇▁▁▁▅
 2 lead_time                              0          1     104.      107.        0      18     69     160   737 ▇▂▁▁▁
 3 arrival_date_year                      0          1    2016.        0.707  2015    2016   2016    2017  2017 ▃▁▇▁▆
 4 arrival_date_week_number               0          1      27.2      13.6       1      16     28      38    53 ▅▇▇▇▅
 5 arrival_date_day_of_month              0          1      15.8       8.78      1       8     16      23    31 ▇▇▇▇▆
 6 stays_in_weekend_nights                0          1       0.928     0.999     0       0      1       2    19 ▇▁▁▁▁
 7 stays_in_week_nights                   0          1       2.50      1.91      0       1      2       3    50 ▇▁▁▁▁
 8 adults                                 0          1       1.86      0.579     0       2      2       2    55 ▇▁▁▁▁
 9 children                               4          1.00    0.104     0.399     0       0      0       0    10 ▇▁▁▁▁
10 babies                                 0          1       0.00795   0.0974    0       0      0       0    10 ▇▁▁▁▁
11 is_repeated_guest                      0          1       0.0319    0.176     0       0      0       0     1 ▇▁▁▁▁
12 previous_cancellations                 0          1       0.0871    0.844     0       0      0       0    26 ▇▁▁▁▁
13 previous_bookings_not_canceled         0          1       0.137     1.50      0       0      0       0    72 ▇▁▁▁▁
14 booking_changes                        0          1       0.221     0.652     0       0      0       0    21 ▇▁▁▁▁
15 days_in_waiting_list                   0          1       2.32     17.6       0       0      0       0   391 ▇▁▁▁▁
16 adr                                    0          1     102.       50.5      -6.38   69.3   94.6   126  5400 ▇▁▁▁▁
17 required_car_parking_spaces            0          1       0.0625    0.245     0       0      0       0     8 ▇▁▁▁▁
18 total_of_special_requests              0          1       0.571     0.793     0       0      0       1     5 ▇▁▁▁▁

skim函数的输出结果来看,这个数据集包含了近12万条的酒店预订记录以及32个变量,其中13个为文本变量,18个位数值型变量,以及一个日期型变量。数据集比较整洁完整,只有children这个变量中包含了4个缺失值。这对于咱们来讲,是一件很是好的事情,能够节省大量的数据整理的时间。毕竟,在数据科学家中间,有一我的尽皆知的笑话:算法

数据科学家的工做,80%的时间都是用于整理数据,剩下的20%的时间,都用来抱怨数据有多糟糕。

2. 数据的预处理

虽然这个数据集是相对比较整洁的,可是为了建模的须要,咱们仍是须要对数据进行一些处理。
具体而言,有几个类别型变量的值过多,须要咱们对其进行整合,不然则会致使咱们的数据模型中每一个类别的样本量都比较少。具体而言:机器学习

  1. country变量包含了178个不一样的值,而且分布很不均匀;
  2. agent变量包含了334个不一样的值,也是分布很不均匀;
  3. company变量包含了353个不一样的值。

tidyverse中包含了能够对类别型变量进行重组的函数fct_reorder能够很方便地让咱们对以上三个变量进行重组:分布式

hotel_bookings <- hotel_bookings %>% 
  mutate(agent=fct_lump(agent,prop = 0.008))
hotel_bookings <- hotel_bookings %>% 
mutate(company=if_else(company=="NULL","Individual","Corporate"))

除此以外,咱们还有另一些变量须要进行一些处理:函数

hotel_bookings <- hotel_bookings %>% 
  select(is_canceled,everything()) %>% 
  mutate(is_canceled=factor(if_else(is_canceled==1,"Canceled","Not_Canceled"))) %>% 
  select(-reservation_status_date,-arrival_date_year,-arrival_date_day_of_month,-arrival_date_week_number)

hotel_bookings <- hotel_bookings %>% 
  mutate(with_kids=babies+children
  )

hotel_bookings <- hotel_bookings %>% 
  filter(!is.na(with_kids)) %>% 
  select(-babies,-children)

hotel_bookings <- hotel_bookings %>% 
  select(-reservation_status)   ## this is another indicator for reservation, won't use in the model due to data leakage

这里尤为要提到的是我在原始数据中删除了reservation_status这个变量,由于这个变量实际上产生了所谓的data leakage的问题,由于在我第一次的建模过程当中,我发现最终的测试预测准确率达到了100%!!做为一个有多年预测建模经验的人,本能的第一反应就是数据中存在信息泄露的问题,实际上这个reservation_status变量和最终咱们要预测的是否取消是等同的。于是,为了不这样的问题致使模型没有最终的实际业务价值,咱们必须将其从原始数据中删除。学习

3. 数据的不均衡问题诊断:

在一些特定的机器学习问题中,好比银行违约这类的数据,每每存在不均衡的问题,毕竟违约的是不多数的。而这个不均衡的问题,对于机器学习模型会产生很大的影响。测试

hotel_bookings %>% 
  count(is_canceled,sort = TRUE) %>% 
  mutate(Percent_of_Total=n/sum(n)) %>% 
  kableExtra::kable()

image.png
从数据上看,预定取消的比例大概有40%不到(比我想象的高出很多)。可是另外一方面,也说明咱们没有太大的class imbalance的问题。

4. 数据类型的转换

由于咱们须要使用到的是h2o来进行预测建模,所以,咱们须要将原始数据中的全部文本类型的数据转换为factor,这很容易经过tidyverse中的mutate_if函数来轻松实现。

hotel_bookings <- hotel_bookings %>% 
  mutate_if(is.character,factor)

经过h2o中的automl来进行预测建模:

h2o简介:

h2o是美国一家公司开发的开源机器学习项目,由斯坦福大学的几位世界知名的统计学教授做为技术指导,同时提供了R和Python的包,以超高的预测准确率闻名。具体信息能够点击h2o官网

h2o的主要优势有如下几个方面:

  1. 为大数据准备,能够利用分布式计算在电脑的多核以及集群上运行;
  2. 速度快,h2o实际是用Java编写,弥补了R在计算速度上的缺陷;
  3. API界面统一,学习周期短;
  4. 数据预处理要求比较低,不少数据预处理的工做均可以自动完成。

1.启动h2o:

library(h2o)
h2o.init(nthreads = 6,max_mem_size = "36g")

h2o的一大优势就是你能够本身定义为本项目能够利用的计算机处理器和内存的使用量,能够保证你在运行模型时,不影响其余电脑正在运行的任务。个人电脑是8核的处理器,有48GB的内存,因此我为其余任务保留了必定的计算能力。

Connection successful!

R is connected to the H2O cluster: 
    H2O cluster uptime:         1 hours 6 minutes 
    H2O cluster timezone:       Asia/Shanghai 
    H2O data parsing timezone:  UTC 
    H2O cluster version:        3.28.0.2 
    H2O cluster version age:    1 month and 14 days  
    H2O cluster name:           H2O_started_from_R_chn-fzj_tff946 
    H2O cluster total nodes:    1 
    H2O cluster total memory:   35.80 GB 
    H2O cluster total cores:    8 
    H2O cluster allowed cores:  6 
    H2O cluster healthy:        TRUE 
    H2O Connection ip:          localhost 
    H2O Connection port:        54321 
    H2O Connection proxy:       NA 
    H2O Internal Security:      FALSE 
    H2O API Extensions:         Amazon S3, Algos, AutoML, Core V3, TargetEncoder, Core V4 
    R Version:                  R version 3.6.2 (2019-12-12)

若是你看到和以上相似的信息,就说明你的设置已经成功了。

2.数据框的转换与分割:

response <- "is_canceled"
predictors <- setdiff(names(hotel_bookings),response)

bookings_h2o <- as.h2o(hotel_bookings)


data_split <- h2o.splitFrame(bookings_h2o,ratios = c(0.9,0.05))

bookings_train <- data_split[[1]]
bookings_valid <- data_split[[2]]
bookings_test <- data_split[[3]]

在使用h2o进行建模以前咱们须要将R中的dataframe转换成h2o的数据框,而后将咱们的数据分割成训练集,验证集和测试集。在本案例中,由于咱们的原始数据量仍是比较大的,于是我是按照90%的训练集,5%的验证集和5%的测试集。

automl_model <- h2o.automl(x=predictors,
                           y=response,
                           training_frame = bookings_train,
                           validation_frame = bookings_valid,
                           nfolds = 20,
                           max_runtime_secs = 600,
                           max_models = 20,
                           stopping_metric = "AUC",
                           stopping_tolerance = 0.005,
                           seed = 1234,
                           project_name = "First_AutoML_Model")

我使用的是automl的算法,本质上来讲就是一种ensemble的方法,能够同时随即森林,GBM等方法训练出模型并从中选择出表现最好的模型。
另外,我规定了模型训练的时间为600秒,这是一个很是有用的特性,能够避免咱们平时须要等待几个小时才能看到模型的结果这样的情形出现。

3. 模型的表现对比:

前文说过,automl会产生多个不一样的算法模型,经过提取leaderboard的信息,咱们对模型的结果有一个比较准确的认识:

image.png
从这些模型中,咱们直接选择出表现最好的模型,并使用这个模型对测试集的数据进行预测,并验证最终的结果表现,确保没有过拟合现象的出现:

automl_best <- automl_model@leader

h2o.confusionMatrix(automl_best)

image.png

predictions_with_bestmodel <- h2o.predict(automl_best,bookings_test)

test_df <- as.data.frame(bookings_test)
predictions_with_bestmodel <- as.data.frame(predictions_with_bestmodel)
predicted <- predictions_with_bestmodel %>% 
  pull(predict)
testing_results <- data.frame(
  actual=test_df$is_canceled,
  predictions=predicted
  
)
testing_results %>% 
  count(actual,predictions)

image.png

咱们花费了10分钟训练出来的模型的预测准确率达到了88%,这个结果是至关不错的。

下面还应该作些什么?

上面的内容只是一个最简单的案例,在实际业务过程当中,咱们还须要:

  1. 使用更多的模型和参数;
  2. 训练更长的时间;
  3. 探究模型是否是在某一些方面的预测能力存在问题,可能须要对预测变量进行更多的处理;
  4. 最终,模型完成验证以后,须要进行部署。
相关文章
相关标签/搜索