hi各位大佬好,我是菜鸟小明哥,上周吹牛逼的东西这周要整出个雏形来,效果无所谓,要能跑。于是乎我翻阅了相关博文及原始paper,准备搞下基本的流程,这个毕竟也是最朴素的方法,简单的不会一两个感觉有点不接地气。脸书的原文:Practical Lessons from Predicting Clicks on Ads at Facebook,竟然是广告方面的,我喜欢。
For Recommendation in Deep learning QQ Group 102948747
For Visual in deep learning QQ Group 629530787
不接受这个网页的私聊/私信!!!
前情提要
fb将决策树与LR结合在一起取得了不错的效果,不必惊讶,最重要的是有正确的特征,那些捕获用户或广告历史信息的特征,一旦特征选对了,模型也用的好,那么其他因素就影响比较小了。因为更关注因子对模型的影响,所以采用预测的准确性,而不是直接与收益相关的指标。这里使用的是NE(归一化交叉熵)和标定刻度(平均估计CTR和经验CTR的比)。NE是预测的log_loss由背景CTR的熵归一化得到的,背景(background)CTR是训练集的平均经验CTR。NE越小模型预测的越好,这种归一化的原因是,背景CTR越接近0或1,更容易取得好的log_loss,所以归一化后NE对背景CTR就不敏感了。假设给定训练集有N个样本,标签分别为{-1,+1},估计的点击概率为,平均的经验CTR为p,那么NE为:
NE是很重要的,在计算相关信息增益RIG=1-NE。
Calibration是期望点击率和实际点击率的比值。比值与1的差值越小,模型越好。AUC也是评价排序质量的指标。如果一个模型过渡预测2倍,可采用一个全局乘子0.5固定标定刻度,相应的NE也会好,尽管AUC保持不变。
模型结构
采用的是提升决策树的拼接和概率稀疏线性分类器,简而言之就是bdt+线性分类器(LR也是一种分类器,具体线性非线性一直是个常见的问题,有的说,除了sigmoid,其他都是线性的,有的说sigmoid是非线性的,加上它自然是非线性的),如图下。输入的特征通过bdt进行转换,每棵树的输出作为线性分类器的种类特征输入,bdt是被证实是有力的特征转换,提升线性分类器的概率。
SGD应用于稀疏线性分类器。特征转换后,一个广告得到一个结构矢量,是第i个单位矢量,i1等是n个种类的输入特征的值。在训练阶段,假设二值标签表示点击与否。太难翻了,卧槽,如下,可视为一个点击与否的分数
是标准正态分布的累积密度分布函数,N是标准正态分布的密度函数。详见paper吧,这个有点难记,难理解,也不会作为面试的重点,除非面试官真的是牛逼。LR模型的infer是计算对数似然的偏导,再进行梯度方向一个前进:如下,
关于决策树特征转换:
有两种简单的线性分类器输入特征转换的方法来提高分类器的acc,对于连续特征,一个学习非线性转换的trick是,将特征分区(bin),视每个区的index为一个类别特征,这真的是常见的做法。第二个做法比较有效,建立元组输入特征,对于类别特征,这种暴力方法是进行笛卡尔乘积,例如,创建一个新的类别特征将所有的值视为一个类别(??这也太多了吧)。并不是所有的联合都是有用的,可以将无用的去掉。如果输入的特征是连续的,可以用KD树做一个联合分区(bin)。但发现bdt是一个非常方便的方法,将每棵树视为一个类别特征,使用1~K的特征编码。对于第一个图来说,有两个子树,第一颗子树有3片叶子,第二颗子树有2片叶子,如果一个样本在第一颗子树的第2个叶子及第二颗子树的第1个叶子结束,那么线性分类器的输入特征为[0,1,0,1,0]。bdt是采用的GBM(梯度提升机,哈哈,这里也有个GBM)。在每次迭代中,一个新的树生成,用来模拟之前树的残差。可将bdt视为一个超级特征编码,将真实值的向量转换为紧实的二值向量。
试验及分析
只有树的NE与LR,bdt+LR的NE比较,发现bdt+LR的NE最小,如下,根据上面的,NE越小模型越好。
bdt可以一天训练一次,而LR可以实时训练(在线训练)。下面是几种学习率的对比:
1,对于特征i的t次迭代:per-coordinate lr,alpha和beta可调
2,per-weight 均方根lr;3,per-weight lr;4,global lr;5,常数 lr
对比结果如下:可见第一个lr效果最好。常数的也不错,我觉得完全没必要搞那么复杂。另外LR即可,不必BOPR,如下
模型中树越多,需要的预测的时间越长。树个数在500时NE下降了不少,但多余1000则很少变化。下图submodel2的训练数据是很少的,比submodel0或者1少4倍。
特征重要性,之前提到,特征的选择很重要,但总有些特征不那么重要。试验说明,前50个特征已经达到重要性的90%,我觉得差不多够了。
提升模型中的特征可以分为两种,背景特征和历史特征。背景特征,例如,用户的设备,广告的上下文或出现的页面。历史特征,用户或者广告的点击率。对这些特征进行重要性排序,发现前10个重要的是历史特征,前20个中只有2个是背景特征。上面右边是对比结果,可见只有历史特征已经很不错了,背景特征在冷启动中很重要。对新用户和广告,背景特征是不可或缺的,对于可解释性CTR预测。
大数据量的处理:下采样,1)均匀抽样;2)负样本欠采样。结果表明,采样率为0.1,与全部数据训练的效果只有1%的差别。负样本欠采样率设置为0.025的效果最好。负样本欠采样可以加速训练和提高模型效果。
关于推荐
代码部分之前博文已经附了。参考我的博文。当然实际的关于推荐方面的代码还有待考虑,也就是说大部分是item特征及label(点击与否),难道说每个user的特征也是这么拼接在一起的吗?这样的话,user和item的组合,将有N_user*N_item个预测,也就是说从目前的点击行为训练得到。
>>> pd.get_dummies(df, prefix=['col1', 'col2'])
C col1_a col1_b col2_a col2_b col2_c
0 1 1 0 0 1 0
1 2 0 1 1 0 0
2 3 1 0 0 0 1
是否需要one-hot编码的问题,lightgbm之前有说无需one-hot,直接输入即可,那么我的理解是直接0~k编码即可。事实证明,我的做法是正确的。但对于LR则需要,然而树多了经过树的特征再经过one-hot输入LR维度已经相当大了,这就有点蛋疼了。然而我最终也没想到怎么给用户推荐。太难了。问问大佬吧。且听下回分解,挖个坑。