推薦系統遇上深度學習(十)--GBDT+LR融合方案實戰
來自專欄大數據分析挖掘42 人贊了文章
作者:石曉文 Python愛好者社區專欄作者
個人公眾號:小小挖掘機 博客專欄: wenwen
推薦系統遇上深度學習系列:
推薦系統遇上深度學習(一)--FM模型理論和實踐:https://www.jianshu.com/p/152ae633fb00推薦系統遇上深度學習(二)--FFM模型理論和實踐:https://www.jianshu.com/p/781cde3d5f3d推薦系統遇上深度學習(三)--DeepFM模型理論和實踐:
https://www.jianshu.com/p/6f1c2643d31b推薦系統遇上深度學習(四)--多值離散特徵的embedding解決方案:https://www.jianshu.com/p/4a7525c018b2推薦系統遇上深度學習(五)--Deep&Cross Network模型理論和實踐:https://www.jianshu.com/p/77719fc252fa推薦系統遇上深度學習(六)--PNN模型理論和實踐:https://www.jianshu.com/p/be784ab4abc2推薦系統遇上深度學習(七)--NFM模型理論和實踐:https://www.jianshu.com/p/4e65723ee632推薦系統遇上深度學習(八)--AFM模型理論和實踐:https://www.jianshu.com/p/83d3b2a1e55d推薦系統遇上深度學習(九)--評價指標AUC原理及實踐:
https://www.jianshu.com/p/4dde15a56d44寫在前面的話
GBDT和LR的融合在廣告點擊率預估中算是發展比較早的演算法,為什麼會在這裡寫這麼一篇呢?本來想嘗試寫一下阿里的深度興趣網路(Deep Interest Network),發現阿里之前還有一個演算法MLR,然後去查找相關的資料,裡面提及了樹模型也就是GBDT+LR方案的缺點,恰好之前也不太清楚GBDT+LR到底是怎麼做的,所以今天我們先來了解一下GBDT和LR的融合方案。
1、背景
在CTR預估問題的發展初期,使用最多的方法就是邏輯回歸(LR),LR使用了Sigmoid變換將函數值映射到0~1區間,映射後的函數值就是CTR的預估值。
LR屬於線性模型,容易並行化,可以輕鬆處理上億條數據,但是學習能力十分有限,需要大量的特徵工程來增加模型的學習能力。但大量的特徵工程耗時耗力同時並不一定會帶來效果提升。因此,如何自動發現有效的特徵、特徵組合,彌補人工經驗不足,縮短LR特徵實驗周期,是亟需解決的問題。FM模型通過隱變數的方式,發現兩兩特徵之間的組合關係,但這種特徵組合僅限於兩兩特徵之間,後來發展出來了使用深度神經網路去挖掘更高層次的特徵組合關係。但其實在使用神經網路之前,GBDT也是一種經常用來發現特徵組合的有效思路。
Facebook 2014年的文章介紹了通過GBDT解決LR的特徵組合問題,隨後Kaggle競賽也有實踐此思路,GBDT與LR融合開始引起了業界關注。
在介紹這個模型之前,我們先來介紹兩個問題:
1)為什麼要使用集成的決策樹模型,而不是單棵的決策樹模型:一棵樹的表達能力很弱,不足以表達多個有區分性的特徵組合,多棵樹的表達能力更強一些。可以更好的發現有效的特徵和特徵組合2)為什麼建樹採用GBDT而非RF:RF也是多棵樹,但從效果上有實踐證明不如GBDT。且GBDT前面的樹,特徵分裂主要體現對多數樣本有區分度的特徵;後面的樹,主要體現的是經過前N顆樹,殘差仍然較大的少數樣本。優先選用在整體上有區分度的特徵,再選用針對少數樣本有區分度的特徵,思路更加合理,這應該也是用GBDT的原因。了解了為什麼要用GBDT,我們就來看看到底二者是怎麼融合的吧!
2、GBDT和LR的融合方案
GBDT和LR的融合方案,FaceBook的paper中有個例子:
圖中共有兩棵樹,x為一條輸入樣本,遍歷兩棵樹後,x樣本分別落到兩顆樹的葉子節點上,每個葉子節點對應LR一維特徵,那麼通過遍歷樹,就得到了該樣本對應的所有LR特徵。構造的新特徵向量是取值0/1的。舉例來說:上圖有兩棵樹,左樹有三個葉子節點,右樹有兩個葉子節點,最終的特徵即為五維的向量。對於輸入x,假設他落在左樹第一個節點,編碼[1,0,0],落在右樹第二個節點則編碼[0,1],所以整體的編碼為[1,0,0,0,1],這類編碼作為特徵,輸入到LR中進行分類。
這個方案還是很簡單的吧,在繼續介紹下去之前,我們先介紹一下代碼實踐部分。
3、GBDT+LR代碼實踐
本文介紹的代碼只是一個簡單的Demo,實際中大家需要根據自己的需要進行參照或者修改。
github地址:https://github.com/princewen/tensorflow_practice/tree/master/recommendation/GBDT%2BLR-Demo
訓練GBDT模型
本文使用lightgbm包來訓練我們的GBDT模型,訓練共100棵樹,每棵樹有64個葉子結點。df_train = pd.read_csv(data/train.csv)df_test = pd.read_csv(data/test.csv)NUMERIC_COLS = [ "ps_reg_01", "ps_reg_02", "ps_reg_03", "ps_car_12", "ps_car_13", "ps_car_14", "ps_car_15",]print(df_test.head(10))y_train = df_train[target] # training labely_test = df_test[target] # testing labelX_train = df_train[NUMERIC_COLS] # training datasetX_test = df_test[NUMERIC_COLS] # testing dataset# create dataset for lightgbmlgb_train = lgb.Dataset(X_train, y_train)lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)params = { task: train, boosting_type: gbdt, objective: binary, metric: {binary_logloss}, num_leaves: 64, num_trees: 100, learning_rate: 0.01, feature_fraction: 0.9, bagging_fraction: 0.8, bagging_freq: 5, verbose: 0}# number of leaves,will be used in feature transformationnum_leaf = 64print(Start training...)# traingbm = lgb.train(params, lgb_train, num_boost_round=100, valid_sets=lgb_train)print(Save model...)# save model to filegbm.save_model(model.txt)print(Start predicting...)# predict and get data on leaves, training data
特徵轉換
在訓練得到100棵樹之後,我們需要得到的不是GBDT的預測結果,而是每一條訓練數據落在了每棵樹的哪個葉子結點上,因此需要使用下面的語句:
y_pred = gbm.predict(X_train, pred_leaf=True)
列印上面結果的輸出,可以看到shape是(8001,100),即訓練數據量*樹的棵樹
print(np.array(y_pred).shape)print(y_pred[0])
結果為:
(8001, 100)[[43 26 47 47 47 19 36 19 50 52 29 0 0 0 46 23 13 27 27 13 10 22 0 10 4 57 17 55 54 57 59 42 22 22 22 13 8 5 27 5 58 23 58 14 16 16 10 32 60 32 4 4 4 4 4 46 57 48 57 34 54 6 35 6 4 55 13 23 15 51 40 0 47 40 10 29 24 24 31 24 55 3 41 3 22 57 6 0 6 6 57 55 57 16 12 18 30 15 17 30]]
然後我們需要將每棵樹的特徵進行one-hot處理,如前面所說,假設第一棵樹落在43號葉子結點上,那我們需要建立一個64維的向量,除43維之外全部都是0。因此用於LR訓練的特徵維數共num_trees * num_leaves。
print(Writing transformed training data)transformed_training_matrix = np.zeros([len(y_pred), len(y_pred[0]) * num_leaf], dtype=np.int64) # N * num_tress * num_leafsfor i in range(0, len(y_pred)): temp = np.arange(len(y_pred[0])) * num_leaf + np.array(y_pred[I]) transformed_training_matrix[i][temp] += 1
當然,對於測試集也要進行同樣的處理:
y_pred = gbm.predict(X_test, pred_leaf=True)print(Writing transformed testing data)transformed_testing_matrix = np.zeros([len(y_pred), len(y_pred[0]) * num_leaf], dtype=np.int64)for i in range(0, len(y_pred)): temp = np.arange(len(y_pred[0])) * num_leaf + np.array(y_pred[I]) transformed_testing_matrix[i][temp] += 1
LR訓練
然後我們可以用轉換後的訓練集特徵和label訓練我們的LR模型,並對測試集進行測試:lm = LogisticRegression(penalty=l2,C=0.05) # logestic model constructionlm.fit(transformed_training_matrix,y_train) # fitting the datay_pred_test = lm.predict_proba(transformed_testing_matrix) # Give the probabilty on each label
我們這裡得到的不是簡單的類別,而是每個類別的概率。
效果評價
在Facebook的paper中,模型使用NE(Normalized Cross-Entropy),進行評價,計算公式如下:代碼如下:
NE = (-1) / len(y_pred_test) * sum(((1+y_test)/2 * np.log(y_pred_test[:,1]) + (1-y_test)/2 * np.log(1 - y_pred_test[:,1])))print("Normalized Cross Entropy " + str(NE))
4、反思
現在的GBDT和LR的融合方案真的適合現在的大多數業務數據么?現在的業務數據是什麼?是大量離散特徵導致的高維度離散數據。而樹模型對這樣的離散特徵,是不能很好處理的,要說為什麼,因為這容易導致過擬合。下面的一段話來自知乎:
用蓋坤的話說,GBDT只是對歷史的一個記憶罷了,沒有推廣性,或者說泛化能力。
但這並不是說對於大規模的離散特徵,GBDT和LR的方案不再適用,感興趣的話大家可以看一下參考文獻2和3,這裡就不再介紹了。
剛才提到了阿里的蓋坤大神,他的團隊在2017年提出了兩個重要的用於CTR預估的模型,MLR和DIN,之後的系列中,我們會講解這兩種模型的理論和實戰!歡迎大家繼續關注!
參考文獻:
1、Facebook的paper:http://quinonero.net/Publications/predicting-clicks-facebook.pdf
2、http://www.cbdio.com/BigData/2015-08/27/content_3750170.htm3、https://blog.csdn.net/shine19930820/article/details/717136804、https://www.zhihu.com/question/358215665、https://github.com/neal668/LightGBM-GBDT-LR/blob/master/GBFT%2BLR_simple.py推薦閱讀:
※經典的分類例子:
※大話機器學習之窮人如何玩轉數據挖掘
※數據分析入門必備之excel運用
※數據分析師該這樣霸氣回應「0.00008的轉化也很好」的謬論
※一個化學工程師的數據科學之旅
TAG:深度學習DeepLearning | 機器學習 | 數據挖掘 |