如何預測“他”什麼時候住酒店?

看到這個題目,大家是否會有一些小小的想法?

別鬧~

筆者是一個正經人,討論的也是一個技術問題,哈哈~

每個人的行爲都是有跡可循的,這些蛛絲馬跡可以作爲預測的數據支持,有沒有想過一個人什麼時候住酒店能夠被預測出來?筆者作爲一個從事機器學習方面的程序員,對這一問題表示肯定,因爲,如果不信就沒有工作了。

筆者以爲:所謂預測即爲通過歷史上遺留下來的蛛絲馬跡:行爲、訂單甚至大廳門口的攝像頭,判斷某個人接下來的行爲舉動。這樣的預測多少還是有些價值的,畢竟,人的想法是會通過行爲表達出來,想法是漸變的,也就預示着行爲存在一定的連續性。

試想一下,如果一個人或者一個公司能有客戶在某個地方的消費記錄,以及通過觀察分析發現客戶的基本特徵,數據量足夠大的情況下是否能夠預測出客人什麼時候入住酒店呢?我想結論大家都知道了~

作爲一個旁觀者和理論家(哈哈),我們來一起探討一下,什麼樣的特徵和模型能夠預測出客戶住酒店的時間?

有沒有一點小小激動,畢竟預測是在不確定性中尋找肯定~

01  酒店預測的價值

有誰會關心酒店的預測結果呢?

如果你想到的是情感問題,哈哈,我想該讓你失望了,因爲筆者是一個滿心工作的狂人。姑且將上面的人羣算作一個吧,還會有誰呢?

1) 心繫萬千客戶的大老闆們;

2) 將驕傲賦予代碼的程序員們;

3) 天天接待客戶的銷售精英們;

4) 想盡奇招探索客戶的運營大佬們;

……

預測的價值在於能夠幫助決策者減少混亂,在是否到店?什麼時候到店?的基礎上實現客羣的細分並在細分客羣的思路下挖掘客戶更深入的價值。在大數據領域中,預測將會是大數據的核心價值。

02 預測的思路

什麼樣的客戶會進入到我們的酒店呢?

客戶什麼樣的行爲預示着要來酒店了呢?

我想這是酒店運營或老闆最關心的問題吧?

正如上文所言,一個好的預測是需要對歷史數據進行充分的解讀,然後基於數據特性進行模型的構建,最終得到預測結果。

因此,我們需要分析一下什麼樣的情況下才會發生酒店入住行爲,以及入住時間受什麼因素影響?

對於酒店的入住,往往受較多方面的影響:出差、旅遊、走親訪友……

入住時間呢?

影響入住時間的因素往往較爲寬泛,比如:春夏秋冬季節時令、酒店所處城市、酒店附近交通的便利程度、天氣情況等等……

再結合酒店的定位、客戶的年齡、性別,以及從着裝、談吐定位出的薪資水平、社會階層等幾乎可以勾勒出一個較爲完整的特徵集合了。

筆者粗略的做了一下整理,如有不足歡迎大家關注公衆號溝通~

基本特徵如下:

其中有些特徵是需要進行線下錄入,或者邏輯推理完成,比如:入住目的,在華爲公司附近的酒店,見到來自上海的華爲員工,工作日獨身一人辦理入住,完全有理由相信,他來是出差的~

特徵整理好之後我們就需要對模型有一個預判了:

首先這是一個連續值預測模型,我們姑且把時間轉化成連續值,預測到月日粒度就可以了。

常見的連續值預測模型有如下幾個:

1) 線性迴歸;

2) 神經網絡RNN等;

3) 決策樹融合線性迴歸等;

4) ARIMA等時間序列模型;

每一種模型都會有他的優勢和缺點,比如:線性迴歸預測方便簡單,但是較難解決自相關的問題;神經網絡能較好的擬合高維特性但是解釋性較差;ARIMA需要較強的融合時間因素等等。他們的優缺點包括但不限於這些描述,有興趣的讀者可以深入瞭解一下。

本文筆者採用的是決策樹融合線性迴歸GBDT+Ridge的建模方式,這一方式主要是受到GBDT+LR模型的啓發,facebook構建的GBDT+LR融合模型在點擊率預測中效果顯著,曾一度在各個公司中應用,但是在連續值預測中多少會有一些不足,畢竟LR模型是一個用線性迴歸實現的分類模型,曲線的調整會影響預測的效果。

GBDT+Ridge融合模型用嶺迴歸替換掉了LR的部分,對應功能上Ridge更適合進行連續值的預測。另外,Ridge可以通過添加約束條件以及懲罰係數,限定預測範圍和解決多重共線性的問題,預測結果調整上具有一定程度的靈活性;

GBDT本身在決策樹方面有較好的名氣:

1) 其對特徵值有較好的容忍性,數據有空值、異常值等情況下都可以有效運行;

2) 對較高維度的特徵融合效果也較爲突出,因爲樹的特性,GBDT能夠有效的探索高維的特徵特性,每一個樹狀分支都是對多個特徵的高維度融合;

3) 由於其boosting的設計思路,不停的迭代優化能夠迅速提升模型的準確性;

所以GBDT從一出生就是明星算法。

但是其本身也存在一定的缺點:

1) 樹的每個分支都有一個維度相乘的效果,每個維度的變化都會引發整體的變化,因此其靈敏度較高,容易過擬合;

2) 無法較好的用在連續值預測上,GBDT本質上還是一個分類算法;

而Ridge剛好彌補了這一問題,線性迴歸Ridge中各個特徵值是相加的,單個特徵的變化對整體的影響較小,同時Ridge本身就是用來進行連續值預測的,又較好的解決了多重共線性的問題。

基於上面的考慮,筆者對兩個模型進行了融合,讓有情人終成眷屬。

03 預測的實現邏輯

模型的預測基本上遵循數據建模的常規套路,我們借這個機會將流程進行一些梳理:

1) 特徵清洗:數據的離散化、歸一化,缺失值填充,one_hot/WOE變化等;

2) 特徵降維:降維主要有兩方面原因,其一是維度之間有一些共線性,我們在訓練過程中需要把對y值影響不大或者x之間相互影響的特徵剔除掉;其二是當我們用one_hot進行向量化變化之後,往往存在梯度爆炸等問題,爲了解決這一問題,我們經常用到的方法有:主成分分析、因子分析、決策樹篩選、相關係數計算、embedding、稀疏自編碼等;

3) 切分訓練集和測試集:在訓練集和測試集的切分中常用的方法有兩個:其一是按照一定比例隨機提取,比如:隨機2:8分,80%數據做訓練集,20%數據做測試集,這一方法簡單高效,但是訓練的準確性較低;其二:K-fold切分,將數據集拆分成測試集和訓練集之後,對訓練集進行K折拆分,循環訓練,循環驗證,可以有效防止過擬合的現象;

4) 構建模型:模型的構建正如上文提到的,我們使用的GBDT+Ridge融合模型,在建模過程中,需要格外小心模型的輸入和輸出數據格式,通常我們會把融合模型整合成一個函數,那麼對應的參數作爲輸入數據就需要做好格式對照;

5) 模型保存/使用:訓練好的模型需要進行保存固話,這樣可以避免下次使用模型的時候重新訓練,畢竟一次模型的訓練需要較長的時間,固話模型的一些常用方法有:pickle、joblib等,對於一些深度學習的模型存在各自的方法,比如keras中的model.save();模型使用時也有對應的方法,比如:joblib和pickle中的loads函數,可以有效的還原訓練好的模型,直接使用到生產環境中。

6) 訓練結果驗證:訓練結果需要進行比較才能知道好壞,我們通常會選擇多個模型,融合之後通過一定的指標進行比較,常用的比較指標有:F-score、AUC、ROC曲線等。

上面即爲構建模型的常規思路,在這樣的思路下,我們實現了酒店入住時間的預測,小小的滿足了一下宅男的臆想,看到這裏估計會被我的技術折服吧,哈哈,小小調侃一下~

下面是作爲程序員的必備課了,上代碼

04 預測代碼

預測代碼主要是基於下面的思路進行構建的:

1)數據結構爲:

2)文件結構爲:

3) 對應代碼爲:

(源碼請關注公衆號:數據python戰算法,回覆:酒店,筆者會及時回覆,並源碼送上,謝謝)

首先需要對代碼進行特徵處理;

 ……

for i in range(0, len(test_data_p_1)):    tmp = []    tmp.append(test_data_p_1.iloc[i, 0])    dd = datetime.datetime.strptime(test_data_p_1.iloc[i, 1].split('.')[0], "%Y-%m-%d %H:%M:%S")    tmp.append(dd.year)    tmp.append(dd.month)    tmp.append(dd.day)    tmp.append(dd.hour)    tmp.append(dd.minute)    tmp.append(dd.second)
    tt = test_data_p_1.iloc[i, 2] if len(test_data_p_1.iloc[i, 2]) > 10 else '0'    tt = datetime.datetime.strptime(tt, "%Y-%m-%d %H:%M:%S") if tt != '0' else '0'    tmp.append(tt.year if tt != '0' else '0')    tmp.append(tt.month if tt != '0' else '0')    tmp.append(tt.day if tt != '0' else '0')
    ss = test_data_p_1.iloc[i, 3] if len(test_data_p_1.iloc[i, 3]) > 10 else '0'    ss = datetime.datetime.strptime(ss, "%Y-%m-%d %H:%M:%S") if ss != '0' else '0'    tmp.append(ss.year if ss != '0' else '0')    tmp.append(ss.month if ss != '0' else '0')    tmp.append(ss.day if ss != '0' else '0')

……

其次需要進行數據彙總;

 ……

data_s = pd.merge(data_1_4, data_2_2, on='id', how='inner')data_s = pd.merge(data_s, data_3_4, on='id', how='inner')data_s = pd.merge(data_s, data_4_2, on='id', how='inner').drop_duplicates().reset_index()data_s = data_s.filter(regex="[^'index']")data_s.to_csv('data_s.csv', encoding="utf_8_sig")

……

最後就是驗證和使用;

grd = GradientBoostingClassifier(n_estimators=60)# 調用one-hot編碼。grd_enc = OneHotEncoder()# 調用LR分類模型。# grd_lm = LogisticRegression()grd_lm = RidgeCV(alphas=[0.1, 1.0, 10.0])# 使用X_train訓練GBDT模型,後面用此模型構造特徵grd.fit(train_X, train_y)# fit one-hot編碼器grd_enc.fit(grd.apply(train_X)[:, :, 0])# 使用訓練好的GBDT模型構建特徵,然後將特徵經過one-hot編碼作爲新的特徵輸入到LR模型訓練。# clf = grd_lm.fit(grd_enc.transform(grd.apply(X_train_lr)[:, :, 0]), y_train_lr)clf = grd_lm.fit(grd_enc.transform(grd.apply(X_train_lr)[:, :, 0]), y_train_lr)   # 線性迴歸建模# 用訓練好的LR模型對X_test做預測y_pred_grd_lm = grd_lm.predict(grd_enc.transform(grd.apply(test_X)[:, :, 0]))

……

思路和代碼都只是機器學習的引導,算是建模的一個較爲完整的流程,希望能夠對大家有所幫助,有興趣歡迎相互溝通~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章