LR (逻辑回归) 算法因其简单有效,成为工业界最常用的算法之一。 但 LR 算法是线性模型,不能捕捉到非线性信息,需要大量特征工程找到特征组合。 为了发现有效的特征组合,Facebook 在 2014年介绍了通过 GBDT (Gradient Boost Decision Tree)+ LR 的方案 [1] (XGBoost 是 GBDT 的后续发展)。 随后 Kaggle 竞赛实践证明此思路的有效性 [2][3]。

背景

CTR预估,是互联网计算广告中的关键环节,预估准确性直接影响公司广告收入。 CTR预估中用的最多的模型是LR。 LR是广义线性模型,与传统线性模型相比,LR使用了Logit变换将函数值(目标值)映射到0-1区间[2], ,映射后的函数值就是CTR预估值。 LR这种线性模型很容易并行化,处理上亿条训练样本不是问题,但线性模型学习能力有限, 需要大量特征工程预先分析出有效的特征、特征组合,从而去间接增强LR的非线性学习能力。

LR模型中的特征组合很关键,但又无法直接通过特征笛卡尔积解决,只能依靠人工经验,耗时耗力同时并不能一定会带来效果提升。 Facebook2014年的文章介绍了通过GBDT(gradient boost decision tree)解决LR的特征组合问题,随后kaggle比赛也有实践此 思路,GBDT与LR融合开始引起业界关注。

前后方法对比

摘要

评价

https://blog.csdn.net/strwolf/article/details/56005701 https://zhuanlan.zhihu.com/p/25043821 https://www.cnblogs.com/bentuwuying/p/6264004.html http://www.xml-data.org/JSJYY/2017-10-2866.htm

    一共用了两个参数
  • Normalized Entropy (NE)
  • 分子实际上就是logistic regression的损失函数,分母就是平均的损失, 平均的损失实际上就等于整个数据集的entropy,所以叫normalized entropy, 这种是消除了不平衡数据集的影响
  • calibration
  • 这个比较简单,就是预测点击数除以实际点击数,对于点击率预测, 最关心的是点击率预测的准确性,而不太注重ROC这种rank order指标

目标

原理

XGBoost + LR 融合方式原理很简单。先用数据训练一个 XGBoost 模型, 然后将训练数据中的实例给 XGBoost 模型得到实例的叶子节点, 然后将叶子节点当做特征训练一个 LR 模型。XGBoost + LR 的结构如下所示。

原理 我第一接触到 XGBoost + LR 的时候,认为 XGBoost + LR 是尝试自动替代特征工程的方法。 深度学习在 CTR 领域便是在讲述这样的故事和逻辑:只需人工对原始特征进行简单的变换,深度学习能取的比大量人工特征的 LR 好的效果。

后来经过试验发现,保留原始特征+叶子节点特征的效果最好;

总结

融合现状

XGBoost  LR 在工业和竞赛实践中,都取得了不错的效果。 但 XGBoost 的叶子节点不能完全替代人工特征, XGBoost LR 并没有像深度学习那样试图带来自动特征工程的故事和逻辑。最终,XGBoost + LR 的格局没有超越特征工程。 GBDT与LR融合方式,Facebook的paper有个例子如下图2所示, 图2

实战

GBDT+LR

http://itindex.net/detail/58314-%E5%AE%9E%E8%B7%B5-ctr-xgboost 环境是python3.5.3 + scikit-learn 0.18.1

from scipy.sparse.construct import hstack
from sklearn.model_selection import train_test_split
from sklearn.datasets.svmlight_format import load_svmlight_file
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
import numpy as np

def gbdt_lr_train(libsvmFileName):

    # load样本数据
    X_all, y_all = load_svmlight_file(libsvmFileName)

    # 训练/测试数据分割
    X_train, X_test, y_train, y_test = train_test_split(X_all, y_all, test_size = 0.3, random_state = 42)

    # 定义GBDT模型
    gbdt = GradientBoostingClassifier(n_estimators=40, max_depth=3, verbose=0,max_features=0.5)

    # 训练学习
    gbdt.fit(X_train, y_train)

    # 预测及AUC评测
    y_pred_gbdt = gbdt.predict_proba(X_test.toarray())[:, 1]
    gbdt_auc = roc_auc_score(y_test, y_pred_gbdt)
    print('gbdt auc: %.5f' % gbdt_auc)

    # lr对原始特征样本模型训练
    lr = LogisticRegression()
    lr.fit(X_train, y_train)    # 预测及AUC评测
    y_pred_test = lr.predict_proba(X_test)[:, 1]
    lr_test_auc = roc_auc_score(y_test, y_pred_test)
    print('基于原有特征的LR AUC: %.5f' % lr_test_auc)

    # GBDT编码原有特征
    X_train_leaves = gbdt.apply(X_train)[:,:,0]
    X_test_leaves = gbdt.apply(X_test)[:,:,0]

    # 对所有特征进行ont-hot编码
    (train_rows, cols) = X_train_leaves.shape

    gbdtenc = OneHotEncoder()
    X_trans = gbdtenc.fit_transform(np.concatenate((X_train_leaves, X_test_leaves), axis=0))

    # 定义LR模型
    lr = LogisticRegression()
    # lr对gbdt特征编码后的样本模型训练
    lr.fit(X_trans[:train_rows, :], y_train)
    # 预测及AUC评测
    y_pred_gbdtlr1 = lr.predict_proba(X_trans[train_rows:, :])[:, 1]
    gbdt_lr_auc1 = roc_auc_score(y_test, y_pred_gbdtlr1)
    print('基于GBDT特征编码后的LR AUC: %.5f' % gbdt_lr_auc1)

    # 定义LR模型
    lr = LogisticRegression(n_jobs=-1)
    # 组合特征
    X_train_ext = hstack([X_trans[:train_rows, :], X_train])
    X_test_ext = hstack([X_trans[train_rows:, :], X_test])

    print(X_train_ext.shape)
    # lr对组合特征的样本模型训练
    lr.fit(X_train_ext, y_train)

    # 预测及AUC评测
    y_pred_gbdtlr2 = lr.predict_proba(X_test_ext)[:, 1]
    gbdt_lr_auc2 = roc_auc_score(y_test, y_pred_gbdtlr2)
    print('基于组合特征的LR AUC: %.5f' % gbdt_lr_auc2)


if __name__ == '__main__':
    gbdt_lr_train('data/sample_libsvm_data.txt')   

XGBoost+LR

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
import numpy as np
from scipy.sparse import hstack
from sklearn.preprocessing.data import OneHotEncoder


def xgboost_lr_train(libsvmFileNameInitial):

    # load样本数据
    X_all, y_all = load_svmlight_file(libsvmFileNameInitial)

    # 训练/测试数据分割
    X_train, X_test, y_train, y_test = train_test_split(X_all, y_all, test_size = 0.3, random_state = 42)

    # 定义xgb模型
    xgboost = xgb.XGBClassifier(nthread=4, learning_rate=0.08,
                            n_estimators=50, max_depth=5, gamma=0, subsample=0.9, colsample_bytree=0.5)
    # 训练xgb学习
    xgboost.fit(X_train, y_train)

    # 预测xgb及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)


    # 合并编码后的训练数据和测试数据
    All_leaves = np.concatenate((X_train_leaves, X_test_leaves), axis=0)
    All_leaves = All_leaves.astype(np.int32)

    # 对所有特征进行ont-hot编码
    xgbenc = OneHotEncoder()
    X_trans = xgbenc.fit_transform(All_leaves)

    (train_rows, cols) = X_train_leaves.shape

    # 定义LR模型
    lr = LogisticRegression()
    # lr对xgboost特征编码后的样本模型训练
    lr.fit(X_trans[:train_rows, :], y_train)
    # 预测及AUC评测
    y_pred_xgblr1 = lr.predict_proba(X_trans[train_rows:, :])[:, 1]
    xgb_lr_auc1 = roc_auc_score(y_test, y_pred_xgblr1)
    print('基于Xgb特征编码后的LR AUC: %.5f' % xgb_lr_auc1)

    # 定义LR模型
    lr = LogisticRegression(n_jobs=-1)
    # 组合特征
    X_train_ext = hstack([X_trans[:train_rows, :], X_train])
    X_test_ext = hstack([X_trans[train_rows:, :], X_test])

    # lr对组合特征的样本模型训练
    lr.fit(X_train_ext, y_train)

    # 预测及AUC评测
    y_pred_xgblr2 = lr.predict_proba(X_test_ext)[:, 1]
    xgb_lr_auc2 = roc_auc_score(y_test, y_pred_xgblr2)
    print('基于组合特征的LR AUC: %.5f' % xgb_lr_auc2)

if __name__ == '__main__':
    xgboost_lr_train("data/sample_libsvm_data.txt")

扩展

参考文章

https://blog.csdn.net/lilyth_lilyth/article/details/48032119

http://www.algorithmdog.com/xgboost-lr-more-feas

https://www.cnblogs.com/bentuwuying/p/6264004.html

[1].He X, Pan J, Jin O, et al. Practical lessons from predicting clicks on ads at facebook[C]. Proceedings of 20th ACM SIGKDD Conference on Knowledge Discovery and Data Mining. ACM, 2014: 1-9. [2].http://www.csie.ntu.edu.tw/~r01922136/Kaggle-2014-criteo.pdf [3].https://github.com/guestwalk/Kaggle-2014-criteo

TODO 中文

https://blog.csdn.net/u010352603/article/details/80681100

http://d0evi1.com/facebook-ad/