參考:
論文:《Practical Lessons from Predicting Clicks on Ads at Facebook》
本文主要介紹Facebook提出的CTR預估模型LR(Logistic Regression)+GBDT。當時深度學習還沒有應用到計算廣告領域,Facebook提出利用GBDT的葉節點編號作為非線性特徵的表示,或者說是組合特徵的一種方式。
LR+GBDT相比於單純的LR或者GBDT帶來了較大的性能提升,論文中給出數據為3%,這在CTR預估領域確實非常不錯。除此之外,Facebook還在在線學習、Data freshness、學習速率、樹模型參數、特徵重要度等方面進行了探索。
相比於搜索廣告領域,根據用戶query來給出候選廣告,然後利用Rank模型對候選廣告進行排序。這些廣告要麼顯式要麼隱式的和用戶query相關聯。但是在Facebook這樣的社交場閤中,廣告並沒有和用戶query相關聯,但是用戶看到的廣告一定程度上反映了用戶的人口統計特性和興趣特性。基於這個原因,在Facebook上展示的廣告相比於搜索廣告中的要多一些。
在實際的生產環境中,Facebook做了多個分類器,並把他們級聯起來。但是論文中分析的是最後的那一個prediction模型。它直接給出最後的CTR概率。
在介紹這個模型之前,我們先來介紹兩個問題:
1)為什麼要使用集成的決策樹模型,而不是單棵的決策樹模型:一棵樹的表達能力很弱,不足以表達多個有區分性的特徵組合,多棵樹的表達能力更強一些。可以更好的發現有效的特徵和特徵組合
論文目的是分析機器學習模型的影響因素,所以沒有使用實際利益相關的評測函數。而是主要從以下兩方面進行:
NE的公式如下:
AUC也是一個非常不錯的評價指標,但是它有個問題。比如當我們的模型預測的CTR概率都偏高了2倍,我們可以通過Calibration校準,使用一個全局的0.5的係數來修正。修正之後NE也會提高,而AUC卻保持不變。
GBDT和LR的融合方案,FaceBook的paper中有個例子:
圖中共有兩棵樹,x為一條輸入樣本,遍歷兩棵樹後,x樣本分別落到兩顆樹的葉子節點上,每個葉子節點對應LR一維特徵,那麼通過遍歷樹,就得到了該樣本對應的所有LR特徵。構造的新特徵向量是取值0/1的。舉例來說:上圖有兩棵樹,左樹有三個葉子節點,右樹有兩個葉子節點,最終的特徵即為五維的向量。對於輸入x,假設他落在左樹第一個節點,編碼[1,0,0],落在右樹第二個節點則編碼[0,1],所以整體的編碼為[1,0,0,0,1],這類編碼作為特徵,輸入到LR中進行分類。
訓練GBDT模型
本文使用lightgbm包來訓練我們的GBDT模型,訓練共100棵樹,每棵樹有64個葉子結點。
import lightgbm as lgb
import pandas as pd import numpy as np
from sklearn.metrics import mean_squared_error from sklearn.linear_model import LogisticRegression
print(Load data...) 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
# 特徵轉換
# 在訓練得到100棵樹之後,我們需要得到的不是GBDT的預測結果,而是每一條訓練數據落 #在了每棵樹的哪個葉子結點上,因此需要使用下面的語句:
y_pred = gbm.predict(X_train, pred_leaf=True)# 8001*100 查看每個樣本落在每棵樹的第幾個葉子上
print(np.array(y_pred).shape) print(y_pred[:10])
#然後我們需要將每棵樹的特徵進行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_leafs 8001*(100*64) 對每棵樹的特徵進行onehot處理,所以在y_pred的基礎上每一列擴展成64列(每棵樹有64個葉子) for i in range(0, len(y_pred)): temp = np.arange(len(y_pred[0])) * num_leaf + np.array(y_pred[i])#計算onehot在100*64列當中的位置 arange(100)*64 + 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
#然後我們可以用轉換後的訓練集特徵和label訓練我們的LR模型,並對測試集進行測試: lm = LogisticRegression(penalty=l2,C=0.05) # logestic model construction L2懲罰 C為正則化係數λ的倒數,通常默認為1 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
print(y_pred_test)
在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))
現在的GBDT和LR的融合方案真的適合現在的大多數業務數據麼?現在的業務數據是什麼?是大量離散特徵導致的高維度離散數據。而樹模型對這樣的離散特徵,是不能很好處理的,要說為什麼,因為這容易導致過擬合。下面的一段話來自知乎: