生活随笔
收集整理的這篇文章主要介紹了
GBDT和LR结合使用分析
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?文章來源:https://www.deeplearn.me/1797.html
?
GBDT+LR 的特征組合方案是工業(yè)界經(jīng)常使用的組合,尤其是計(jì)算廣告 CTR 中應(yīng)用比較廣泛,方案的提出者是 Facebook 2014 的一篇論文。
相關(guān)的開發(fā)工具包,sklearn 和 xgboost(ps:xgboost 是一個大殺器,并且支持 hadoop 分布式,你可以部署實(shí)現(xiàn)分布式操作,博主部署過,布置過程較為負(fù)責(zé),尤其是環(huán)境變量的各種設(shè)置)
特征決定模型性能上界,例如深度學(xué)習(xí)方法也是將數(shù)據(jù)如何更好的表達(dá)為特征。如果能夠?qū)?shù)據(jù)表達(dá)成為線性可分的數(shù)據(jù),那么使用簡單的線性模型就可以取得很好的效果。GBDT 構(gòu)建新的特征也是使特征更好地表達(dá)數(shù)據(jù)。
主要參考 Facebook[1],原文提升效果:
在預(yù)測 Facebook 廣告點(diǎn)擊中,使用一種將決策樹與邏輯回歸結(jié)合在一起的模型,其優(yōu)于其他方法,超過 3%。
主要思想:GBDT 每棵樹的路徑直接作為 LR 輸入特征使用。
用已有特征訓(xùn)練 GBDT 模型,然后利用 GBDT 模型學(xué)習(xí)到的樹來構(gòu)造新特征,最后把這些新特征加入原有特征一起訓(xùn)練模型。構(gòu)造的新特征向量是取值 0/1 的,向量的每個元素對應(yīng)于 GBDT 模型中樹的葉子結(jié)點(diǎn) 。當(dāng)一個樣本點(diǎn)通過某棵樹最終落在這棵樹的一個葉子結(jié)點(diǎn)上,那么在新特征向量中這個葉子結(jié)點(diǎn)對應(yīng)的元素值為 1,而這棵樹的其他葉子結(jié)點(diǎn)對應(yīng)的元素值為 0。新特征向量的長度等于 GBDT 模型里所有樹包含的葉子結(jié)點(diǎn)數(shù)之和。
上圖為混合模型結(jié)構(gòu)。輸入特征通過增強(qiáng)的決策樹進(jìn)行轉(zhuǎn)換。 每個單獨(dú)樹的輸出被視為稀疏線性分類器的分類輸入特征。 增強(qiáng)的決策樹被證明是非常強(qiáng)大的特征轉(zhuǎn)換。
例子 1:上圖有兩棵樹,左樹有三個葉子節(jié)點(diǎn),右樹有兩個葉子節(jié)點(diǎn),最終的特征即為五維的向量。對于輸入 x,假設(shè)他落在左樹第一個節(jié)點(diǎn),編碼[1,0,0],落在右樹第二個節(jié)點(diǎn)則編碼[0,1],所以整體的編碼為[1,0,0,0,1],這類編碼作為特征,輸入到線性分類模型(LR or FM)中進(jìn)行分類。
需要注意的是在 sklearn 或者 xgboost 輸出的結(jié)果都是葉子節(jié)點(diǎn)的 index,所以需要自己動手去做 onehot 編碼,然后交給 lr 訓(xùn)練,onehot 你可以在 sklearn 的預(yù)處理包中調(diào)用即可
論文中 GBDT 的參數(shù),樹的數(shù)量最多 500 顆(500 以上就沒有提升了),每棵樹的節(jié)點(diǎn)不多于 12。
下面給出二者相結(jié)合的代碼演示
?
# -*- coding: utf-8 -*- # @Time : 2018/2/27 上午 10:39 # @Author : Tomcj # @File : gbdt_lr.py # @Software: PyCharm import xgboost as xgb from sklearn.datasets import load_svmlight_file from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import roc_curve, auc, roc_auc_score from sklearn.externals import joblib from sklearn.preprocessing import OneHotEncoder import numpy as np from scipy.sparse import hstack ? ? ? def xgb_feature_encode(libsvmFileNameInitial): ? # load 樣本數(shù)據(jù) X_all, y_all = load_svmlight_file(libsvmFileNameInitial) ? # 訓(xùn)練/測試數(shù)據(jù)分割 X_train, X_test, y_train, y_test = train_test_split(X_all, y_all, test_size = 0.3, random_state = 42) ? # 定義模型 xgboost = xgb.XGBClassifier(nthread=4, learning_rate=0.08, n_estimators=50, max_depth=5, gamma=0, subsample=0.9, colsample_bytree=0.5) # 訓(xùn)練學(xué)習(xí) xgboost.fit(X_train, y_train) ? ? # 預(yù)測及 AUC 評測 y_pred_test = xgboost.predict_proba(X_test)[:, 1] xgb_test_auc = roc_auc_score(y_test, y_pred_test) print('xgboost test auc: %.5f' % xgb_test_auc) ? # xgboost 編碼原有特征 X_train_leaves = xgboost.apply(X_train) X_test_leaves = xgboost.apply(X_test) # 訓(xùn)練樣本個數(shù) train_rows = X_train_leaves.shape[0] # 合并編碼后的訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù) X_leaves = np.concatenate((X_train_leaves, X_test_leaves), axis=0) X_leaves = X_leaves.astype(np.int32) ? (rows, cols) = X_leaves.shape ? # 記錄每棵樹的編碼區(qū)間 cum_count = np.zeros((1, cols), dtype=np.int32) ? for j in range(cols): if j == 0: cum_count[0][j] = len(np.unique(X_leaves[:, j])) else: cum_count[0][j] = len(np.unique(X_leaves[:, j])) + cum_count[0][j-1] ? print('Transform features genenrated by xgboost...') # 對所有特征進(jìn)行 ont-hot 編碼,注釋部分是直接使用 onehot 函數(shù),結(jié)果輸出保證是 libsvm 格式也可以使用 #sklearn 中的 dump_svmlight_file 操作,這個文件代碼是參考別人的代碼,這些點(diǎn)都是可以優(yōu)化的。 ? # onehot=OneHotEncoder() # onehot.fit(X_leaves) # x_leaves_encode=onehot.transform(X_leaves) for j in range(cols): keyMapDict = {} if j == 0: initial_index = 1 else: initial_index = cum_count[0][j-1]+1 for i in range(rows): if X_leaves[i, j] not in keyMapDict: keyMapDict[X_leaves[i, j]] = initial_index X_leaves[i, j] = initial_index initial_index = initial_index + 1 else: X_leaves[i, j] = keyMapDict[X_leaves[i, j]] ? # 基于編碼后的特征,將特征處理為 libsvm 格式且寫入文件 print('Write xgboost learned features to file ...') xgbFeatureLibsvm = open('xgb_feature_libsvm', 'w') for i in range(rows): if i < train_rows: xgbFeatureLibsvm.write(str(y_train[i])) else: xgbFeatureLibsvm.write(str(y_test[i-train_rows])) for j in range(cols): xgbFeatureLibsvm.write(' '+str(X_leaves[i, j])+':1.0') xgbFeatureLibsvm.write('\n') xgbFeatureLibsvm.close() ? ? def xgboost_lr_train(xgbfeaturefile, origin_libsvm_file): ? # load xgboost 特征編碼后的樣本數(shù)據(jù) X_xg_all, y_xg_all = load_svmlight_file(xgbfeaturefile) X_train, X_test, y_train, y_test = train_test_split(X_xg_all, y_xg_all, test_size = 0.3, random_state = 42) ? # load 原始樣本數(shù)據(jù) X_all, y_all = load_svmlight_file(origin_libsvm_file) X_train_origin, X_test_origin, y_train_origin, y_test_origin = train_test_split(X_all, y_all, test_size = 0.3, random_state = 42) ? ? # lr 對原始特征樣本模型訓(xùn)練 lr = LogisticRegression(n_jobs=-1, C=0.1, penalty='l1') lr.fit(X_train_origin, y_train_origin) joblib.dump(lr, 'lr_orgin.m') # 預(yù)測及 AUC 評測 y_pred_test = lr.predict_proba(X_test_origin)[:, 1] lr_test_auc = roc_auc_score(y_test_origin, y_pred_test) print('基于原有特征的 LR AUC: %.5f' % lr_test_auc) ? # lr 對 load xgboost 特征編碼后的樣本模型訓(xùn)練 lr = LogisticRegression(n_jobs=-1, C=0.1, penalty='l1') lr.fit(X_train, y_train) joblib.dump(lr, 'lr_xgb.m') # 預(yù)測及 AUC 評測 y_pred_test = lr.predict_proba(X_test)[:, 1] lr_test_auc = roc_auc_score(y_test, y_pred_test) print('基于 Xgboost 特征編碼后的 LR AUC: %.5f' % lr_test_auc) ? # 基于原始特征組合 xgboost 編碼后的特征 X_train_ext = hstack([X_train_origin, X_train]) del(X_train) del(X_train_origin) X_test_ext = hstack([X_test_origin, X_test]) del(X_test) del(X_test_origin) ? # lr 對組合后的新特征的樣本進(jìn)行模型訓(xùn)練 lr = LogisticRegression(n_jobs=-1, C=0.1, penalty='l1') lr.fit(X_train_ext, y_train) joblib.dump(lr, 'lr_ext.m') # 預(yù)測及 AUC 評測 y_pred_test = lr.predict_proba(X_test_ext)[:, 1] lr_test_auc = roc_auc_score(y_test, y_pred_test) print('基于組合特征的 LR AUC: %.5f' % lr_test_auc) ? if __name__ == '__main__': xgb_feature_encode("/Users/leiyang/xgboost/demo/data/agaricus.txt.train") xgboost_lr_train("xgb_feature_libsvm","/Users/leiyang/xgboost/demo/data/agaricus.txt.train") ?
下面給出一個 ipynb 文件,也是從官方的文件改過來的,主要是對 GBDT 輸出到 lr 部分?jǐn)?shù)據(jù)觀察
?
view rawgbdt_lr.ipynb?hosted with ? by?GitHub
總結(jié)
以上是生活随笔 為你收集整理的GBDT和LR结合使用分析 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。