点击率预估用来判断一条广告被用户点击的概率,对每次广告的点击做出预测,把用户最有可能点击的广告找出来,是广告技术最重要的算法之一。
关注微信公众号 datayx 然后回复 广告 即可获取。
这次我们使用Kaggle上的Display Advertising Challenge挑战的criteo数据集。
https://www.kaggle.com/c/criteo-display-ad-challenge/
下载数据集请在终端输入下面命令(脚本文件路径:./data/download.sh): wget –no-check-certificate https://s3-eu-west-1.amazonaws.com/criteo-labs/dac.tar.gz tar zxf dac.tar.gz rm -f dac.tar.gz mkdir raw mv ./*.txt raw/
解压缩以后,train.txt文件11.7G,test.txt文件1.35G。 数据量太大了,我们只使用前100万条数据。 head -n 1000000 test.txt > test_sub100w.txt head -n 1000000 train.txt > train_sub100w.txt 然后将文件名重新命名为train.txt和test.txt,文件位置不变。
Target variable that indicates if an ad was clicked (1) or not (0).
A total of 13 columns of integer features (mostly count features).
A total of 26 columns of categorical features. The values of these features have been hashed onto 32 bits for anonymization purposes.
数据中含有Label字段,表示这条广告是否被点击,I1-I13一共13个数值特征(Dense Input),C1-C26共26个Categorical类别特征(Sparse Input)。
模型包含三部分网络,一个是FFM(Field-aware Factorization Machines),一个是FM(Factorization Machine),另一个是DNN,其中FM网络包含GBDT和FM两个组件。通常在数据预处理的部分,需要做特征交叉组合等特征工程,以便找出帮助我们预测的特征出来,这绝对是技术活。
这次我们跳过特征工程的步骤,把这些组件和深度神经网络组合在一起,将挑选特征的工作交给模型来处理。其中FFM使用了LibFFM,FM使用了LibFM,GBDT使用了LightGBM,当然你也可以使用xgboost。
给入训练数据后,GBDT会训练出若干棵树,我们要使用的是GBDT中每棵树输出的叶子结点,将这些叶子结点作为categorical类别特征输入给FM。有关决策树的使用,请参照Facebook的这篇文章Practical Lessons from Predicting Clicks on Ads at Facebook。
http://quinonero.net/Publications/predicting-clicks-facebook.pdf
我们来看DNN的部分。将输入数据分成两部分,一部分是数值特征(Dense Input),一部分是类别特征(Sparse Input)。我们仍然不适用One Hot编码,将类别特征传入嵌入层,得到多个嵌入向量,再将这些嵌入向量和数值特征连接在一起,传入全连接层,一共连接三层全连接层,使用Relu激活函数。然后再将第三层全连接的输出和FFM、FM的全连接层的输出连接在一起,传入最后一层全连接层。
我们要学习的目标Label表示广告是否被点击了,只有1(点击)和0(没有点击)两种状态。所以我们网络的最后一层要做Logistic回归,在最后一层全连接层使用Sigmoid激活函数,得到广告被点击的概率。
使用LogLoss作为损失函数,FTRL作为学习算法。
FTRL有关的Paper:Ad_click_prediction_a_view_from_the_trenches
https://www.researchgate.net/publication/262412214_Ad_click_prediction_a_view_from_the_trenches
**
**
首先要为DNN、FFM和GBDT的输入做预处理。对于数值特征,我们将I1-I13转成0-1之间的小数。类别特征我们将某类别使用次数少于cutoff(超参)的忽略掉,留下使用次数多的feature作为某类别字段的特征,然后将这些特征以各自字段为组进行编号。
比如有C1和C2两个类别字段,C1下面有特征a(大于cutoff次)、b(少于cutoff次)、c(大于cutoff次),C2下面有特征x和y(均大于cutoff次),这样留下来的特征就是C1:a、c和C2:x、y。然后以各自字段为分组进行编号,对于C1字段,a和c的特征id对应0和1;对于C2字段,x和y也是0和1。
对于类别特征的输入数据处理,FFM和GBDT各不相同,我们分别来说。
GBDT的处理要简单一些,C1-C26每个字段各自的特征id值作为输入即可。 GBDT的输入数据格式是:Label I1-I13 C1-C26 所以实际输入可能是这样:0 小数1 小数2 ~ 小数13 1(C1特征Id) 0(C2特征Id) ~ C26特征Id 其中C1特征Id是1,说明此处C1字段的feature是c,而C2字段的feature是x。
下面是一段生成的真实数据: 0 0.05 0.004983 0.05 0 0.021594 0.008 0.15 0.04 0.362 0.166667 0.2 0 0.04 2 3 0 0 1 1 0 3 1 0 0 0 0 3 0 0 1 4 1 3 0 0 2 0 1 0
FFM的输入数据要复杂一些,详细可以参看官方Github
上的说明,摘抄如下:
It is important to understand the difference between field
and feature
. For example, if we have a raw data like this:
以下代码来自百度deep_fm的preprocess.py
,稍稍添了些代码,我就不重复造轮子了:)
数据准备好了,开始调用LibFFM,训练FFM模型。 learning rate是0.1,迭代32次,训练好后保存的模型文件是model_ffm。
因为数据中大部分都是负例,正例较少,如果模型全部猜0就能有75%的准确率,所以准确率这个指标是不可信的。
我们需要关注正例的精确率和召回率,当然最主要还是要看LogLoss的值,因为比赛采用的评价指标是LogLoss,而不是采用AUC值。
以上就是点击率预估的完整过程,没有进行完整数据的训练,并且有很多超参可以调整,从只跑了一次epoch的结果来看,验证集上的LogLoss是0.46,其他数据都在75%~80%之间,这跟FFM、GBDT和FM网络训练的准确率差不多。
https://blog.csdn.net/chengcheng1394/article/details/78940565