在上一篇文章,提到了Facebook 2014年发表的一篇采用GBDT构建特征的论文: Practical lessons from predicting clicks on ads at facebook 。为了深入学习GBDT,本文将重点分析这篇文章的思路,即CTR预估经典模型:GBDT+LR,一个曾风靡Kaggle、至今在工业界仍存有余温的传奇模型。同时采用scikit-learn里面的GBDT和LR来完成GBDT+LR的实验。
背景介绍
论文开篇介绍在计算广告领域,Facebook日活用户超过7.5亿,活跃广告超过1百万,这种数据规模对Facebook来说也是一大挑战。在这种情形下,Facebook是怎幺做的呢? 引入了一个组合决策树和LR的模型 ,该模型比单一的LR或GBDT的效果都要好,不仅将点击率提升了3%,还大大提升了整个系统的性能。除此之外,Facebook还在online learning、data freshness, 学习率等参数上进行了探索。
模型结构
Facebook论文的Section 1给出了一个重要结论: 只要有正确的特征和正确的模型,其他因素对模型结果的影响就非常小 。那幺,正确的特征是什幺呢?论文对比了两类特征,一类是用户或广告的历史信息特征(historical features),另一类是contextual features(上下文特征),相比之下historical features要优于contextual features。正确的模型指的 boosted decision tree + LR ,其中boosted decision tree又相当于对重要的特征做了feature selection。
在Section 3描述了论文的核心模型,整个hybird模型框架示意图如下:
图1:混合模型框架.输入特征经提升树转换,而单颗树的输出又被当作LR的输入.
对于线性分类器,有两种特征转换方式可以提升分类器的精度。
- 对于连续特征,可以对特征分bin,然后将bin的index作为类别特征,如此线性分类器就可以学习特征的非线性映射,这种方式里,学习有效的bin边界非常重要。
- 对于类别特征,可以采用笛卡尔积(Cartesian product)枚举出所有的二元特征组合。缺点是得到的特征会包含冗余特征。
为此,基于GBDT的特征转换方法诞生了。
基于GBDT的特征转换:将单棵决策树的结果看作是一个类别特征,取值为样本落入在决策树的叶子节点的编号。例如,图1中提升树包含两棵子树,第一棵子树包含3个叶子节点,第二棵树包含2个叶子节点。对于输入样本x(包含多个特征),采用提升决策树(GBDT)进行训练,最终对于第一棵子树上,样本分裂之后落到第二个叶子节点,对于第二棵子树,样本落到了第1个叶子节点,那幺通过特征进行转化之后就是 [0,1,0,1,0]
。
代码实现
下面通过封装scikit-learn中的GBDT和LR,来实现GBDT+LR的实验。为了代码展示的更美观,这里将GBDT+LR封装到一个类里面 GradientBoostingWithLR
,输入数据集的格式与scikit-learn的iris数据格式一致(为了方便,后面也采取iris数据集进行训练和预测)。
GBDT+LR核心方法
import numpy as np from sklearn.ensemble.gradient_boosting import GradientBoostingClassifier from sklearn.linear_model.logistic import LogisticRegression from sklearn.metrics.ranking import roc_auc_score from sklearn.preprocessing.data import OneHotEncoder class GradientBoostingWithLR(object): def __init__(self): self.gbdt_model = None self.lr_model = None self.gbdt_encoder = None self.X_train_leafs = None self.X_test_leafs = None self.X_trans = None def gbdt_train(self, X_train, y_train): """定义GBDT模型 """ gbdt_model = GradientBoostingClassifier(n_estimators=10, max_depth=6, verbose=0, max_features=0.5) # 训练学习 gbdt_model.fit(X_train, y_train) return gbdt_model def lr_train(self, X_train, y_train): """定义LR模型 """ lr_model = LogisticRegression() lr_model.fit(X_train, y_train) # 预测及AUC评测 return lr_model def gbdt_lr_train(self,X_train, y_train,X_test): """训练gbdt+lr模型 """ self.gbdt_model = self.gbdt_train(X_train, y_train) # 使用GBDT的apply方法对原有特征进行编码 self.X_train_leafs = self.gbdt_model.apply(X_train)[:,:,0] # 对特征进行ont-hot编码 self.gbdt_encoder = OneHotEncoder(categories='auto') self.gbdt_encoder.fit(self.X_train_leafs) self.X_trans = self.gbdt_encoder.fit_transform(self.X_train_leafs) #采用LR进行训练 self.lr_model = self.lr_train(self.X_trans, y_train) return self.lr_model def gbdt_lr_pred(self, model, X_test, y_test): """预测及AUC评估 """ self.X_test_leafs = self.gbdt_model.apply(X_test)[:,:,0] (train_rows, cols) =self.X_train_leafs.shape X_trans_all = self.gbdt_encoder.fit_transform(np.concatenate((self.X_train_leafs, self.X_test_leafs), axis=0)) y_pred = model.predict_proba(X_trans_all[train_rows:])[:, 1] auc_score = roc_auc_score(y_test, y_pred) print('GBDT+LR AUC score: %.5f' % auc_score) return auc_score def model_assessment(self, model, X_test, y_test, model_name="GBDT"): """模型评估 """ y_pred = model.predict_proba(X_test)[:,1] auc_score = roc_auc_score(y_test, y_pred) print("%s AUC score: %.5f" % (model_name,auc_score)) return auc_score
训练与预测
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split def load_data(): """ 调用sklearn的iris数据集,将多类数据构造成2分类数据,同时切分训练测试数据集 """ iris_data = load_iris() X = iris_data['data'] y = iris_data['target'] == 2 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) return X_train,X_test,y_train, y_test X_train,X_test,y_train, y_test = load_data() gblr = GradientBoostingWithLR() gbdt_lr_model = gblr.gbdt_lr_train(X_train, y_train, X_test) gblr.model_assessment(gblr.gbdt_model, X_test, y_test) gblr.gbdt_lr_pred(gbdt_lr_model, X_test, y_test)
训练样本落入的叶子节点情况如下(head 10):
采用ont-hot编码之后,结果如下(1条样例):
由于数据集较小,最后预测的结果随机性比较大,在参数没有优化的情况下,有时候GBDT的结果反而好于GBDT+LR,所以调参的重要性也是非常大的。
结束语
OK,对于GBDT+LR的介绍到此结束,本文主要是补充一下GBDT的应用以及如何构建GBDT+LR模型(当然你也可以采用其他方式),文中如有纰漏,还望指出。接下来,将介绍boosting模型的下一个进阶算法:XGBoost。
References
- He, Xinran, et al. “
Practical lessons from predicting clicks on ads at facebook.
- “ Proceedings of the Eighth International Workshop on Data Mining for Online Advertising. ACM, 2014.
- Friedman, Jerome H. “Greedy function approximation: a gradient boosting machine.” Annals of statistics (2001): 1189-1232.
Quick Introduction to Boosting Algorithms in Machine Learning
GBDT+LR code practice
Be First to Comment