推薦系統(tǒng)遇上深度學(xué)習(xí)系列:
推薦系統(tǒng)遇上深度學(xué)習(xí)(一)--FM模型理論和實踐:http://www.itdecent.cn/p/152ae633fb00
推薦系統(tǒng)遇上深度學(xué)習(xí)(二)--FFM模型理論和實踐:http://www.itdecent.cn/p/781cde3d5f3d
推薦系統(tǒng)遇上深度學(xué)習(xí)(三)--DeepFM模型理論和實踐:
http://www.itdecent.cn/p/6f1c2643d31b
推薦系統(tǒng)遇上深度學(xué)習(xí)(四)--多值離散特征的embedding解決方案:http://www.itdecent.cn/p/4a7525c018b2
推薦系統(tǒng)遇上深度學(xué)習(xí)(五)--Deep&Cross Network模型理論和實踐:
http://www.itdecent.cn/p/77719fc252fa
推薦系統(tǒng)遇上深度學(xué)習(xí)(六)--PNN模型理論和實踐:http://www.itdecent.cn/p/be784ab4abc2
推薦系統(tǒng)遇上深度學(xué)習(xí)(七)--NFM模型理論和實踐:
http://www.itdecent.cn/p/4e65723ee632
推薦系統(tǒng)遇上深度學(xué)習(xí)(八)--AFM模型理論和實踐:
http://www.itdecent.cn/p/83d3b2a1e55d
推薦系統(tǒng)遇上深度學(xué)習(xí)(九)--評價指標AUC原理及實踐:
http://www.itdecent.cn/p/4dde15a56d44
寫在前面的話
GBDT和LR的融合在廣告點擊率預(yù)估中算是發(fā)展比較早的算法,為什么會在這里寫這么一篇呢?本來想嘗試寫一下阿里的深度興趣網(wǎng)絡(luò)(Deep Interest Network),發(fā)現(xiàn)阿里之前還有一個算法MLR,然后去查找相關(guān)的資料,里面提及了樹模型也就是GBDT+LR方案的缺點,恰好之前也不太清楚GBDT+LR到底是怎么做的,所以今天我們先來了解一下GBDT和LR的融合方案。
1、背景
在CTR預(yù)估問題的發(fā)展初期,使用最多的方法就是邏輯回歸(LR),LR使用了Sigmoid變換將函數(shù)值映射到0~1區(qū)間,映射后的函數(shù)值就是CTR的預(yù)估值。
LR屬于線性模型,容易并行化,可以輕松處理上億條數(shù)據(jù),但是學(xué)習(xí)能力十分有限,需要大量的特征工程來增加模型的學(xué)習(xí)能力。但大量的特征工程耗時耗力同時并不一定會帶來效果提升。因此,如何自動發(fā)現(xiàn)有效的特征、特征組合,彌補人工經(jīng)驗不足,縮短LR特征實驗周期,是亟需解決的問題。
FM模型通過隱變量的方式,發(fā)現(xiàn)兩兩特征之間的組合關(guān)系,但這種特征組合僅限于兩兩特征之間,后來發(fā)展出來了使用深度神經(jīng)網(wǎng)絡(luò)去挖掘更高層次的特征組合關(guān)系。但其實在使用神經(jīng)網(wǎng)絡(luò)之前,GBDT也是一種經(jīng)常用來發(fā)現(xiàn)特征組合的有效思路。
Facebook 2014年的文章介紹了通過GBDT解決LR的特征組合問題,隨后Kaggle競賽也有實踐此思路,GBDT與LR融合開始引起了業(yè)界關(guān)注。
在介紹這個模型之前,我們先來介紹兩個問題:
1)為什么要使用集成的決策樹模型,而不是單棵的決策樹模型:一棵樹的表達能力很弱,不足以表達多個有區(qū)分性的特征組合,多棵樹的表達能力更強一些??梢愿玫陌l(fā)現(xiàn)有效的特征和特征組合
2)為什么建樹采用GBDT而非RF:RF也是多棵樹,但從效果上有實踐證明不如GBDT。且GBDT前面的樹,特征分裂主要體現(xiàn)對多數(shù)樣本有區(qū)分度的特征;后面的樹,主要體現(xiàn)的是經(jīng)過前N顆樹,殘差仍然較大的少數(shù)樣本。優(yōu)先選用在整體上有區(qū)分度的特征,再選用針對少數(shù)樣本有區(qū)分度的特征,思路更加合理,這應(yīng)該也是用GBDT的原因。
了解了為什么要用GBDT,我們就來看看到底二者是怎么融合的吧!
2、GBDT和LR的融合方案
GBDT和LR的融合方案,F(xiàn)aceBook的paper中有個例子:

圖中共有兩棵樹,x為一條輸入樣本,遍歷兩棵樹后,x樣本分別落到兩顆樹的葉子節(jié)點上,每個葉子節(jié)點對應(yīng)LR一維特征,那么通過遍歷樹,就得到了該樣本對應(yīng)的所有LR特征。構(gòu)造的新特征向量是取值0/1的。舉例來說:上圖有兩棵樹,左樹有三個葉子節(jié)點,右樹有兩個葉子節(jié)點,最終的特征即為五維的向量。對于輸入x,假設(shè)他落在左樹第一個節(jié)點,編碼[1,0,0],落在右樹第二個節(jié)點則編碼[0,1],所以整體的編碼為[1,0,0,0,1],這類編碼作為特征,輸入到LR中進行分類。
這個方案還是很簡單的吧,在繼續(xù)介紹下去之前,我們先介紹一下代碼實踐部分。
3、GBDT+LR代碼實踐
本文介紹的代碼只是一個簡單的Demo,實際中大家需要根據(jù)自己的需要進行參照或者修改。
github地址:https://github.com/princewen/tensorflow_practice/tree/master/recommendation/GBDT%2BLR-Demo
訓(xùn)練GBDT模型
本文使用lightgbm包來訓(xùn)練我們的GBDT模型,訓(xùn)練共100棵樹,每棵樹有64個葉子結(jié)點。
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 label
y_test = df_test['target'] # testing label
X_train = df_train[NUMERIC_COLS] # training dataset
X_test = df_test[NUMERIC_COLS] # testing dataset
# create dataset for lightgbm
lgb_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 transformation
num_leaf = 64
print('Start training...')
# train
gbm = lgb.train(params,
lgb_train,
num_boost_round=100,
valid_sets=lgb_train)
print('Save model...')
# save model to file
gbm.save_model('model.txt')
print('Start predicting...')
# predict and get data on leaves, training data
特征轉(zhuǎn)換
在訓(xùn)練得到100棵樹之后,我們需要得到的不是GBDT的預(yù)測結(jié)果,而是每一條訓(xùn)練數(shù)據(jù)落在了每棵樹的哪個葉子結(jié)點上,因此需要使用下面的語句:
y_pred = gbm.predict(X_train, pred_leaf=True)
打印上面結(jié)果的輸出,可以看到shape是(8001,100),即訓(xùn)練數(shù)據(jù)量*樹的棵樹
print(np.array(y_pred).shape)
print(y_pred[0])
結(jié)果為:
(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處理,如前面所說,假設(shè)第一棵樹落在43號葉子結(jié)點上,那我們需要建立一個64維的向量,除43維之外全部都是0。因此用于LR訓(xùn)練的特征維數(shù)共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_leafs
for 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
L2訓(xùn)練
然后我們可以用轉(zhuǎn)換后的訓(xùn)練集特征和label訓(xùn)練我們的LR模型,并對測試集進行測試:
lm = LogisticRegression(penalty='l2',C=0.05) # logestic model construction
lm.fit(transformed_training_matrix,y_train) # fitting the data
y_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、反思
現(xiàn)在的GBDT和LR的融合方案真的適合現(xiàn)在的大多數(shù)業(yè)務(wù)數(shù)據(jù)么?現(xiàn)在的業(yè)務(wù)數(shù)據(jù)是什么?是大量離散特征導(dǎo)致的高維度離散數(shù)據(jù)。而樹模型對這樣的離散特征,是不能很好處理的,要說為什么,因為這容易導(dǎo)致過擬合。下面的一段話來自知乎:

用蓋坤的話說,GBDT只是對歷史的一個記憶罷了,沒有推廣性,或者說泛化能力。
但這并不是說對于大規(guī)模的離散特征,GBDT和LR的方案不再適用,感興趣的話大家可以看一下參考文獻2和3,這里就不再介紹了。
剛才提到了阿里的蓋坤大神,他的團隊在2017年提出了兩個重要的用于CTR預(yù)估的模型,MLR和DIN,之后的系列中,我們會講解這兩種模型的理論和實戰(zhàn)!歡迎大家繼續(xù)關(guān)注!
參考文獻:
1、Facebook的paper:http://quinonero.net/Publications/predicting-clicks-facebook.pdf
2、http://www.cbdio.com/BigData/2015-08/27/content_3750170.htm
3、https://blog.csdn.net/shine19930820/article/details/71713680
4、https://www.zhihu.com/question/35821566
5、https://github.com/neal668/LightGBM-GBDT-LR/blob/master/GBFT%2BLR_simple.py