1. 程式人生 > >GBDT原理及利用GBDT構造新的特徵GBDT-FFM 點選率預估方案的Python實現

GBDT原理及利用GBDT構造新的特徵GBDT-FFM 點選率預估方案的Python實現

本帖轉發源自:

https://blog.csdn.net/shine19930820/article/details/71713680

看了許多GBDT構建特徵的資料整理而成,具體資料見Reference。

1. 背景

1.1 Gradient Boosting

Gradient Boosting是一種Boosting的方法,它主要的思想是,每一次建立模型是在之前建立模型損失函式的梯度下降方向。損失函式是評價模型效能(一般為擬合程度+正則項),認為損失函式越小,效能越好。而讓損失函式持續下降,就能使得模型不斷改性提升效能,其最好的方法就是使損失函式沿著梯度方向下降(講道理梯度方向上下降最快)。

Gradient Boost是一個框架,裡面可以套入很多不同的演算法。

1.2 Gradient Boosting Decision Tree

每一次建立樹模型是在之前建立模型損失函式的梯度下降方向。即利用了損失函式的負梯度在當前模型的值作為迴歸問題提升樹演算法的殘差近似值,去擬合一個迴歸樹。

1.3 GBDT應用-迴歸和分類

GBDT分類:每一顆樹擬合當前整個模型的損失函式的負梯度,構建新的樹加到當前模型中形成新模型,下一棵樹擬合新模型的損失函式的負梯度。下面是其在Python的sklearn包下簡單呼叫方法。

from sklearn import ensemble
clf = ensemble.GradientBoostingClassifier()
gbdt_model = clf.fit(X_train, y_train)  # Training model
predicty_x = gbdt_model.predict_proba(test1217_x)[:, 1] # predict: probablity of 1 # 包含的引數 # loss = loss, learning_rate = learning_rate, n_estimators = n_estimators, # min_samples_split = min_samples_split, # min_samples_leaf = min_samples_leaf, # min_weight_fraction_leaf = min_weight_fraction_leaf,
# max_depth = max_depth, init = init, subsample = subsample, # max_features = max_features, # random_state = random_state, verbose = verbose, # max_leaf_nodes = max_leaf_nodes, warm_start = warm_start, # presort = presort
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

GBDT迴歸:每一顆樹擬合當前整個模型的殘差,構建新的樹加到當前模型中形成新模型,下一棵樹擬合新模型的損失函式的負梯度。

from sklearn import ensemble
clf = ensemble.GradientBoostingRegressor()
gbdt_model = clf.fit(X_train, y_train)  # Training model
y_upper = gbdt_model.predict(x_test)  # predict
# 包含的引數和上面一致。
  • 1
  • 2
  • 3
  • 4
  • 5

GBDT運用的正則化技巧,防止模型過於複雜,參考這篇文章GBDT運用的正則化技巧

2. GBDT構建新的特徵思想

特徵決定模型效能上界,例如深度學習方法也是將資料如何更好的表達為特徵。如果能夠將資料表達成為線性可分的資料,那麼使用簡單的線性模型就可以取得很好的效果。GBDT構建新的特徵也是使特徵更好地表達資料。

主要參考Facebook[1],原文提升效果:

在預測Facebook廣告點選中,使用一種將決策樹與邏輯迴歸結合在一起的模型,其優於其他方法,超過3%。

主要思想:GBDT每棵樹的路徑直接作為LR輸入特徵使用。

用已有特徵訓練GBDT模型,然後利用GBDT模型學習到的樹來構造新特徵,最後把這些新特徵加入原有特徵一起訓練模型。構造的新特徵向量是取值0/1的,向量的每個元素對應於GBDT模型中樹的葉子結點。當一個樣本點通過某棵樹最終落在這棵樹的一個葉子結點上,那麼在新特徵向量中這個葉子結點對應的元素值為1,而這棵樹的其他葉子結點對應的元素值為0。新特徵向量的長度等於GBDT模型裡所有樹包含的葉子結點數之和。

混合模型結構。

上圖為混合模型結構。輸入特徵通過增強的決策樹進行轉換。 每個單獨樹的輸出被視為稀疏線性分類器的分類輸入特徵。 增強的決策樹被證明是非常強大的特徵轉換。

例子1:上圖有兩棵樹,左樹有三個葉子節點,右樹有兩個葉子節點,最終的特徵即為五維的向量。對於輸入x,假設他落在左樹第一個節點,編碼[1,0,0],落在右樹第二個節點則編碼[0,1],所以整體的編碼為[1,0,0,0,1],這類編碼作為特徵,輸入到線性分類模型(LR or FM)中進行分類。

論文中GBDT的引數,樹的數量最多500顆(500以上就沒有提升了),每棵樹的節點不多於12。

3. GBDT與LR融合方案

在CTR預估中,如何利用AD ID是一個問題。

直接將AD ID作為特徵建樹不可行,而onehot編碼過於稀疏,為每個AD ID建GBDT樹,相當於發掘出區分每個廣告的特徵。而對於曝光不充分的樣本即長尾部分,無法單獨建樹。

綜合方案為:使用GBDT對非ID和ID分別建一類樹。

  1. 非ID類樹:

    不以細粒度的ID建樹,此類樹作為base,即這些ID一起構建GBDT。即便曝光少的廣告、廣告主,仍可以通過此類樹得到有區分性的特徵、特徵組合。

  2. ID類樹:

    以細粒度 的ID建一類樹(每個ID構建GBDT),用於發現曝光充分的ID對應有區分性的特徵、特徵組合。如何根據GBDT建的兩類樹,對原始特徵進行對映?以如下圖3為例,當一條樣本x進來之後,遍歷兩類樹到葉子節點,得到的特徵作為LR的輸入。當AD曝光不充分不足以訓練樹時,其它樹恰好作為補充。

方案如圖:

混合模型結構。

其中kaggle競賽一般樹的數目最多為30,通過GBDT轉換得到特徵空間相比於原始ID低了很多。

4. 原始碼內容

Flowchart

generate GBDT features:

例子2:下圖假設訓練了3顆深度2的樹模型,對於輸入X,在第1個樹屬於節點4,在第2個樹屬於節點7,第3顆樹屬於節點6,所以生成的特徵為”1:4 2:7 3:6”

Flowchart

generate features for FFM

  • 數值型特徵:進行變換:vlog(v)2v←⌊log(v)2⌋

  • 類別特徵:出現小於10的類轉換到一個特殊的value,即合為一種。

  • GBDT特徵直接使用。
  • 使用hashing trick將三類特徵對映到1M-dimensionl。

5. Python實現

上面的原始碼用到了多執行緒實現,Python的sklearn庫中提供了該方法,下面簡單的實踐:

首先要明確使用libFFM還是邏輯迴歸,兩者不同之處在於:

libFFM適用於例子2的情況,即只用使用每棵樹的index。

邏輯迴歸適用於例子1的情況,須將節點使用one-hot編碼,核心程式碼如下:其中關鍵方法為樹模型(GBDT)的apply()方法。

# 弱分類器的數目
n_estimator = 10
# 隨機生成分類資料。
X, y = make_classification(n_samples=80000)  
# 切分為測試集和訓練集,比例0.5
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5)
# 將訓練集切分為兩部分,一部分用於訓練GBDT模型,另一部分輸入到訓練好的GBDT模型生成GBDT特徵,然後作為LR的特徵。這樣分成兩部分是為了防止過擬合。
X_train, X_train_lr, y_train, y_train_lr = train_test_split(X_train, y_train, test_size=0.5)
# 呼叫GBDT分類模型。
grd = GradientBoostingClassifier(n_estimators=n_estimator)
# 呼叫one-hot編碼。
grd_enc = OneHotEncoder()
# 呼叫LR分類模型。
grd_lm = LogisticRegression()


'''使用X_train訓練GBDT模型,後面用此模型構造特徵'''
grd.fit(X_train, y_train)

# fit one-hot編碼器
grd_enc.fit(grd.apply(X_train)[:, :, 0])

''' 
使用訓練好的GBDT模型構建特徵,然後將特徵經過one-hot編碼作為新的特徵輸入到LR模型訓練。
'''
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_proba(grd_enc.transform(grd.apply(X_test)[:, :, 0]))[:, 1]
# 根據預測結果輸出
fpr_grd_lm, tpr_grd_lm, _ = roc_curve(y_test, y_pred_grd_lm)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

總結

對於樣本量大的資料,線性模型具有訓練速度快的特點,但線性模型學習能力限於線性可分資料,所以就需要特徵工程將資料儘可能地從輸入空間轉換到線性可分的特徵空間。GBDT與LR的融合模型,其實使用GBDT來發掘有區分度的特徵以及組合特徵,來替代人工組合特徵。工業種GBDT+LR、GBDT+FM都是應用比較廣泛。

References