DSP

广告点击率预测 [离线部分]

2019-07-13 16:57发布

广告点击率预测 [离线部分]  

2014-05-08 23:08:45|  分类: 计算广告学 |  标签:计算广告学  rtb  dsp  |举报|字号 订阅        下载LOFTER我的照片书  | 广告点击率预测 屈伟 / Koala++          先声明一下,本文所提到的所有的点击率预测的技术不是我在的团队使用的,因为我们团队使用的技术是保密的,所以我也不知道他们是怎么做的。事实上我不知道广告点击率怎么预测的,认识我的人都知道,我就是最喜欢舞那开始三板斧的人,然后我就想扔了板斧投降了。也希望各位能指正我所写的内容中的错误之处,给我一下学习第四斧的机会。          强调一下,按本文的方法来一天就能实现pCTR的功能。

Introduction

         我所写的这一篇,从技术和算法上讲,比不上网上几个公司的pCTRPPT,那几篇比较偏重理论,而且一般讲几种算法,让新接触pCTR的人很茫然,不知道如何开始实现。这就是我写这一篇文章的原因。如果你在一两天之内完成pCTR最粗糙的版本,这是真的可以做到的。Andrew Ng说过:你应该最短的时候,比如一天的时候,完全一个粗糙的版本,看它有什么问题,再去解决。不要担心太粗糙太快速。          广告点击率预测(pCTR Predict Click-Through Rate)是广告算法中最核心的技术了。pCTR要解决的问题是预测特定用户在特定广告位对特定广告当特定环境下的点击概率。为什么pCTR如此重要,因为广告排序的核心是eCPM = pCTR * CPCCPC是广告主对点击的出价,是个已知量,所以只有一个pCTR变量。当然在实际中不可能是如此简单的排序公式,比如还有质量得分(Quality Score),比如Google的质量得分因素          pCTR一般是从离线数据中学习得到的,离线数据是保存到类似Hive的分布式数据库中,通过机器学习的算法将Hive中的数据进行分析,得到一个pCTR模型,这个模型就可以预测pCTR了,大致流程就是这样。   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            下图中有淡绿 {MOD}和绿 {MOD}两块背景,分别表示离线部分和在线部分。看起来离线部分的工作很多,在线部分似乎没什么工作。其实要实现一个通过配置把模型加载进去的在线部分,的确没什么工作量,几行代码就完了。但想实现一个比这强一点的在线部分,都要用一周以上的时候来完成。          离线部分,真正能用的当然全要用MapReduce来写,粗糙版本就用python单机运行就行了,看起来有JoinNormBinarizeTrain四个步骤,其实都是比较简单的。 Join步骤就是将多个数据源的数据通过Key进行Join,和Sql里的Join是一个意思。 NormBinarize是对数据进行一定的变换,这是由我们将要使用的Logistic Regression算法决定的,其实很多算法都逃不了这两步的,所以不用担心会做无用功。 Train这一步就是真正训练模型的工作了。我介绍的时候会用liblinear   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog

Offline

Join

  广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            这一步是将多个数据源的数据,通过类似SQL中的Left Join将多个数据源合并起来,要合并起来是因为我们的训练数据是最终要是一个向量,所以离线的时候一定要先将数据合并成一行。          上图的例子解释一下:左图是Hive中的Log,左图是User Info。左图中有一些字段,比如:广告ID,用户ID,广告位ID,时间,等等,右图中有用户ID,性别,年龄等等。通过UserID将两个数据Join后,就得到了下面的数据。          Note1. 上图只是举个例子,实现的时候,最好不要把User Info中的User ID在合并的时候去掉,否则在你的字段配置文件会有困难。2. Hadoop实现的时候,一定要考虑key skew的问题,否则会出现out of memory的问题。3. 要考虑Join的时候有多个Key的情况。4. 数据格式最好要求严一些,因为处理数据一些就是脚本来写,而如果把工作都放到了Join里,那就是Hadoop Java了。5. 如果是要实现粗糙版本,这一步应该是可以跳过的,因为一般来讲,对pCTR重要的特征都是已经上报了的。6. Left Join的时候,要设置Null值,设置的时候注意点,不要设置0之类的,Norm的时候又忘了。          另一个问题:为什么有Join这个问题呢?直接让工程组的人把我要的字段都写到Log里,我一句select就完了呀!其实这个问题有很多答案,比较合理的答案是:有多少pCTR模型,比如有电商的广告的pCTR,游戏广告的pCTR等等,每个pCTR都用不同的特征,如果都上报,会很浪费,问题又来了:那你不能pb上报?答:在线部分我还没想出来如何能完全不修改在线部分的代码,完成特征的增减。如果你不停的让工程组的人添加特征相关代码,删除特征相关代码,我相信他们会找你拼命的。   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            整个Join过程的示意图如上,我画的还是比较仔细的,在Join Ad Info的时候,用的是多个Key Join,而下面的几个矩形的大小是不同的,因为它们Key的个数肯定是不同的。

Cross Feature

         有时候和别人交流的时候说LR模型是线性模型,别人很疑惑的说sigmoid函数明显不是线性函数呀?我给一下图就明白了,图中的decision boundary是一条直线。为什么是直线?因为weight向量和特征向量x线性关系。          那如果我就这两个特征,我想得到不是直线的decision boundary怎么搞呢?两个方法:1. 让算法支持,比如用神经网络,2. 自己把高维特征给造出来。说一下神经网络算法,神经网络上次实践时发现也不是完全不靠交叉特征就能hold住的。再下面一张图就是引入高维特征后的decision boundary(另一个数据集,我懒得找图了):          交叉特征几乎没什么工作,就是两个字段值拼到一起。举个例子:比如User Info里有个性别字段,Ad Info里有个字段是广告ID,现在我想产生一个性别和广告ID的交叉字段,再假设有个样本里性别为男,广告ID1234,交叉特征就是男_1234          注:1. 产生交叉特征的时候一定要搞分隔符,不然121交叉和121交叉出来结果一样。2. 交叉哪些特征呢?自己把握了,当然不能一下子交叉五六个特征,这样特征特别稀疏,而且词典很大,给线上代码编写再来不必要的压力。3. 如果实现这粗糙版本,这一步跳过,毕竟你不想搞了半天就得到一个过拟合的效果。     广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog  

Norm

         需要Norm的原因是因为我们要用LR算法,相信大家也知道不是所有的算法都有这个过程,比如Normal Equation。大概解释一下要Norm的原因,可能大家都见过下面的图:   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            上图是梯度下降的轨迹。为什么是个椭圆,而不是圆,是因为特征的值域不同,如果值域相差,这个椭圆会变的非常扁。   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            举个例子,左图是两个特征值域在[-10, 10],右边的两个特征分别是[-10, 10], [-30, 30],可以看出下面的函数等高线一下圆,一个扁。那么圆和扁的后果是什么呢?想象爬山的时候,有两座山,一座山是类似半球形的,另一座山是把前一座山沿一个方向拉长几十倍,爬这两座山的时间上的区别。          虽然背后的道理是需要点时间去理解,但Norm的过程却是异常简单,最常用的两种方法,max-minstandard-score,推荐standard-score,因为max-min可能一两个孤异点,把特征的作用给抹杀了。 Max-Min方法:   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog   Standard-Score方法:   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            为什么我计算方差要用上面的公式,不是常用的方差公式,是因为这种计算广告只用一次Map/Reduce,而标准计算公式需要两次Map/Reduce,一次计算均值,一次计算方差。          注:1. Norm的时候注意缺失值的处理,特别是把缺失值设置成0-1这种问题。2. NormBinarize显然只会走其中一个逻辑的。

Binarize

         二值化一样是因为要用LR算法的原因,如果用决策树那就没这问题了。LR需要二值化是因为一些离散值是不可比的。比如性别的男和女,无法比较大小。而一些看起来可比的值,其实逻辑上也不可比了,比如年龄,29岁并不比23岁大。可比的例子,比如:已经曝光的次数,出价。          我下面举个例子来说明Binarize的过程: 性别 [男,女],学历 [小学,初中,高中,本科,硕士,博士] 性别词典 [],学历词典 [小学,初中,高中,本科,硕士,博士] 全局词典 [,小学,初中,高中,本科,硕士,博士] 用户A(本科),二值化结果 [1, 0, 0, 0, 0, 1, 0, 0] 用户B(硕士),二值化结果 [0, 1, 0, 0, 0, 0, 1, 0]          我发现我给别人解释逻辑的时候,最常被问到的就是如果是我事先不知道词典是什么怎么办?事实上,实现的时候和文本分类一样,是要扫两次数据的,第一次产生词典,第二次将样本转化1, 0向量,当然一般用稀疏矩阵的表示方法,0就不写了。

Training

         已经说了是要一天做完pCTR,那显然自己写就有点不现实了,下载一下liblinear,然后就可以开始训练了,当然一般点击率都很低的,Feeds,搜索广告高一些x%,展示广告一般就0.x%,我做的产品点击率就低的没脸提了。按一切从简一切从暴的原则,正例全保留,负例按正例的倍数抽吧。          我一般是按Andrew Ng说的,先把Bias-Variance的图画出来,看一下指标不好的可能是什么原因。   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog   广告点击率预测 [离线部分] - quweiprotoss - Koala++s blog            我还喜欢的一个图是把特征一个个加入后,指标的变化曲线,还是因为公司保密的原因,我就不帖图了,可能有人会问为什么不直接用特征选择看一下就行了,或是L1看,是因为Binarize之后,特征和原始特征对应是可以对应,但这样还是不行我的方法来的直观。          还有一个问题,抽样了要还原吧,哎,就负例抽了多少比例,再除回去吧。你是不是已经愤怒了,到了最后一步你就这样耍我的?其实我真的认为除回去也是勉强能自圆其说的。想知道下不那么山寨的做法?看下google的论文:Ad Click Prediction: a View from the Trenches,里面的Subsampling Training DataCALIBRATING PREDICTIONS