本分析报告中的数据来源于R社区的 tidytuesday 项目中的数据。这个项目在每周二会发布一份数据,供数据科学社区分析,并在twitter上相互分享分析结果,交流学习。node
对于酒店行业来讲,预订有两方面的意义:ios
全部tidytuesday的数据均可以经过两个方式获取,能够安装tidytueday的R包或者直接经过read_csv
从github上直接下载。若是你对以往的历史数据集感兴趣,能够访问下面的Tidytuesday at Github.git
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%的时间,都用来抱怨数据有多糟糕。
虽然这个数据集是相对比较整洁的,可是为了建模的须要,咱们仍是须要对数据进行一些处理。
具体而言,有几个类别型变量的值过多,须要咱们对其进行整合,不然则会致使咱们的数据模型中每一个类别的样本量都比较少。具体而言:机器学习
country
变量包含了178个不一样的值,而且分布很不均匀;agent
变量包含了334个不一样的值,也是分布很不均匀;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
变量和最终咱们要预测的是否取消是等同的。于是,为了不这样的问题致使模型没有最终的实际业务价值,咱们必须将其从原始数据中删除。学习
在一些特定的机器学习问题中,好比银行违约这类的数据,每每存在不均衡的问题,毕竟违约的是不多数的。而这个不均衡的问题,对于机器学习模型会产生很大的影响。测试
hotel_bookings %>% count(is_canceled,sort = TRUE) %>% mutate(Percent_of_Total=n/sum(n)) %>% kableExtra::kable()
从数据上看,预定取消的比例大概有40%不到(比我想象的高出很多)。可是另外一方面,也说明咱们没有太大的class imbalance
的问题。
由于咱们须要使用到的是h2o
来进行预测建模,所以,咱们须要将原始数据中的全部文本类型的数据转换为factor
,这很容易经过tidyverse
中的mutate_if
函数来轻松实现。
hotel_bookings <- hotel_bookings %>% mutate_if(is.character,factor)
h2o
中的automl
来进行预测建模:h2o
简介:h2o
是美国一家公司开发的开源机器学习项目,由斯坦福大学的几位世界知名的统计学教授做为技术指导,同时提供了R和Python的包,以超高的预测准确率闻名。具体信息能够点击h2o官网。
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)
若是你看到和以上相似的信息,就说明你的设置已经成功了。
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秒,这是一个很是有用的特性,能够避免咱们平时须要等待几个小时才能看到模型的结果这样的情形出现。
前文说过,automl
会产生多个不一样的算法模型,经过提取leaderboard的信息,咱们对模型的结果有一个比较准确的认识:
从这些模型中,咱们直接选择出表现最好的模型,并使用这个模型对测试集的数据进行预测,并验证最终的结果表现,确保没有过拟合现象的出现:
automl_best <- automl_model@leader h2o.confusionMatrix(automl_best)
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)
咱们花费了10分钟训练出来的模型的预测准确率达到了88%,这个结果是至关不错的。
上面的内容只是一个最简单的案例,在实际业务过程当中,咱们还须要: