广告点击率预测 [离线部分]
2019-07-13 16:57 发布
生成海报
广告点击率预测 [离线部分]
2014-05-08 23:08:45 | 分类: 计算广告学 | 标签: 计算广告学 rtb dsp | 举报 | 字号 订阅
下载LOFTER 我的照片书 |
广告点击率预测
屈伟 / Koala++
先声明一下,本文所提到的所有的点击率预测的技术不是我在的团队使用的,因为我们团队使用的技术是保密的,所以我也不知道他们是怎么做的。事实上我不知道广告点击率怎么预测的,认识我的人都知道,我就是最喜欢舞那开始三板斧的人,然后我就想扔了板斧投降了。也希望各位能指正我所写的内容中的错误之处,给我一下学习第四斧的机会。
强调一下,按本文的方法来一天就能实现 pCTR 的功能。
Introduction
我所写的这一篇,从技术和算法上讲,比不上网上几个公司的 pCTR 的 PPT ,那几篇比较偏重理论,而且一般讲几种算法,让新接触 pCTR 的人很茫然,不知道如何开始实现。这就是我写这一篇文章的原因。如果你在一两天之内完成 pCTR 最粗糙的版本,这是真的可以做到的。 Andrew
Ng 说过:你应该最短的时候,比如一天的时候,完全一个粗糙的版本,看它有什么问题,再去解决。不要担心太粗糙太快速。
广告点击率预测 (pCTR
Predict Click-Through Rate) 是广告算法中最核心的技术了。 pCTR 要解决的问题是预测特定用户在特定广告位对特定广告当特定环境下的点击概率。为什么 pCTR 如此重要,因为广告排序的核心是 eCPM
= pCTR * CPC , CPC 是广告主对点击的出价,是个已知量,所以只有一个 pCTR 变量。当然在实际中不可能是如此简单的排序公式,比如还有质量得分 (Quality
Score) ,比如 Google 的质量 得分因素 。
pCTR 一般是从离线数据中学习得到的,离线数据是保存到类似 Hive 的分布式数据库中,通过机器学习的算法将 Hive 中的数据进行分析,得到一个 pCTR 模型,这个模型就可以预测 pCTR 了,大致流程就是这样。
下图中有淡绿 {MOD}和绿 {MOD}两块背景,分别表示离线部分和在线部分。看起来离线部分的工作很多,在线部分似乎没什么工作。其实要实现一个通过配置把模型加载进去的在线部分,的确没什么工作量,几行代码就完了。但想实现一个比这强一点的在线部分,都要用一周以上的时候来完成。
离线部分,真正能用的当然全要用 MapReduce 来写,粗糙版本就用 python 单机运行就行了,看起来有 Join , Norm , Binarize , Train 四个步骤,其实都是比较简单的。
Join 步骤就是将多个数据源的数据通过 Key 进行 Join ,和 Sql 里的 Join 是一个意思。
Norm 和 Binarize 是对数据进行一定的变换,这是由我们将要使用的 Logistic
Regression 算法决定的,其实很多算法都逃不了这两步的,所以不用担心会做无用功。
Train 这一步就是真正训练模型的工作了。我介绍的时候会用 liblinear 。
Offline
Join
这一步是将多个数据源的数据,通过类似 SQL 中的 Left
Join 将多个数据源合并起来,要合并起来是因为我们的训练数据是最终要是一个向量,所以离线的时候一定要先将数据合并成一行。
上图的例子解释一下:左图是 Hive 中的 Log ,左图是 User
Info 。左图中有一些字段,比如:广告 ID ,用户 ID ,广告位 ID ,时间,等等,右图中有用户 ID ,性别,年龄等等。通过 UserID 将两个数据 Join 后,就得到了下面的数据。
Note : 1. 上图只是举个例子,实现的时候,最好不要把 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 上报?答:在线部分我还没想出来如何能完全不修改在线部分的代码,完成特征的增减。如果你不停的让工程组的人添加特征相关代码,删除特征相关代码,我相信他们会找你拼命的。
整个 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 的交叉字段,再假设有个样本里性别为男,广告 ID 为 1234 ,交叉特征就是男 _1234 。
注: 1. 产生交叉特征的时候一定要搞分隔符,不然 12 和 1 交叉和 1 和 21 交叉出来结果一样。 2. 交叉哪些特征呢?自己把握了,当然不能一下子交叉五六个特征,这样特征特别稀疏,而且词典很大,给线上代码编写再来不必要的压力。 3. 如果实现这粗糙版本,这一步跳过,毕竟你不想搞了半天就得到一个过拟合的效果。
Norm
需要 Norm 的原因是因为我们要用 LR 算法,相信大家也知道不是所有的算法都有这个过程,比如 Normal
Equation 。大概解释一下要 Norm 的原因,可能大家都见过下面的图:
上图是梯度下降的轨迹。为什么是个椭圆,而不是圆,是因为特征的值域不同,如果值域相差,这个椭圆会变的非常扁。
举个例子,左图是两个特征值域在 [-10, 10] ,右边的两个特征分别是 [-10,
10], [-30, 30] ,可以看出下面的函数等高线一下圆,一个扁。那么圆和扁的后果是什么呢?想象爬山的时候,有两座山,一座山是类似半球形的,另一座山是把前一座山沿一个方向拉长几十倍,爬这两座山的时间上的区别。
虽然背后的道理是需要点时间去理解,但 Norm 的过程却是异常简单,最常用的两种方法, max-min 和 standard-score ,推荐 standard-score ,因为 max-min 可能一两个孤异点,把特征的作用给抹杀了。
Max-Min 方法:
Standard-Score 方法:
为什么我计算方差要用上面的公式,不是常用的方差公式,是因为这种计算广告只用一次 Map/Reduce ,而标准计算公式需要两次 Map/Reduce ,一次计算均值,一次计算方差。
注: 1. Norm 的时候注意缺失值的处理,特别是把缺失值设置成 0 或 -1 这种问题。 2.
Norm 和 Binarize 显然只会走其中一个逻辑的。
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 的图画出来,看一下指标不好的可能是什么原因。
我还喜欢的一个图是把特征一个个加入后,指标的变化曲线,还是因为公司保密的原因,我就不帖图了,可能有人会问为什么不直接用特征选择看一下就行了,或是 L1 看,是因为 Binarize 之后,特征和原始特征对应是可以对应,但这样还是不行我的方法来的直观。
还有一个问题,抽样了要还原吧,哎,就负例抽了多少比例,再除回去吧。你是不是已经愤怒了,到了最后一步你就这样耍我的?其实我真的认为除回去也是勉强能自圆其说的。想知道下不那么山寨的做法?看下 google 的论文: Ad
Click Prediction: a View from the Trenches ,里面的 Subsampling Training Data , CALIBRATING
PREDICTIONS 。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮