本分析報告中的數據來源於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%,這個結果是至關不錯的。
上面的內容只是一個最簡單的案例,在實際業務過程當中,咱們還須要: