LR在CTR中的实践经验

比如我们要开个网站卖书,使用LR模型预估一下用户点击某本书的概率。

1 为什么选用LR

  1. 离线训练和在线预测非常快
  2. 内存占用少
  3. 效果跟xgboost、深度模型差不多
  4. 模型简单,方便调参
  5. 模型易于解释,排查问题方便

第4点和第5点非常重要,工作实践中大多数时间都是在排查问题,根据badcase调参数。

2 特征选择

用户侧特征:uid、性别、年龄、城市、like_words、等等

商品侧特征:itemid、价格、出版社、key_words、等等

匹配特征:like_words和key_words的交集、等等

上下文特征:浏览时间、入网方式、客户端、等等

2.1 尽量不用统计特征

有些统计特征对预测点击率非常有用,比如:这本书历史上的点击率、用户平均每个月买几本书、图书的好评率/销量是多少。但是不建议使用这些统计特征,原因有二:

  1. 在构造样本时统计类特征很容易出错,因为统计类特征是动态变化的。比如图书销量,你要统计每一次特征的浏览发生之前该图书的销量,那才是用户当时看到的销量。这种统计方法说起来也不复杂,但实操过程中很容易出错。
  2. LR仅利用大规模离散特征就能取得不错的效果。用户和图书历史的点击率通过uid和itemid这两个特征就可以学习到,当然这两个特征必须要one-hot。

2.2 一定要找到影响点击率的主要特征

什么是“主要特征”?如果该特征取不同的值可能会导致点击率有十倍百倍的差异,且该特征的不同取值在样本中的占比都比较大。按照这个定义,你可能会发现like_words和key_words的交集并不是主要特征,而图书的展现位置才是,第2页的点击率跟第一页的点击率可能会差10倍之多。

如果不把主要特征加进来,模型可能就是失效的。

2.3 可以使用替代特征

如果某些比较好的特征甚至是主要特征,刚好是统计类特征,怎么办?尽量找到表态特征替代它。举例:

用户过去1个月登录过几次  -->  用户的app版本号。这两个特征都可以把比较活跃和非常不活跃的用户区分开。

用户下单频率  -->  用户的会员等级。这两个特征都可以把经常购物和不经常购物的用户区分开。

4 特征的形式

LR模型适合使用大规模离散特征,xgboost适合使用小规模统计类的连续特征。在使用时LR,连续特征只需要进行简单的离散化操作,比如直接用round,或者先取对数再round。

4.1 one-hot

把所有特征都离散化之后,再进行one-hot,这样id类的特征会变成高维稀疏特征,比如你有1亿个用户,那么光uid就对应1亿个特征。训练模型时只需要针对那些非 0 的维度更新相应的参数就可以了,模型训练的 时间复杂度只跟 X 的非 0 维度数有关。同样,模型存储时只存储有过更新的参 数即可,内存开销与 X 的总维度没有关系。

4.2 特征哈希

one-hot 形式得知道总共有多少种取值,才 能对各个取值编号,在线实时训练模型时我们不可能事先取得所有的样本,也 就无法穷举离散特征的所有取值。一种解决办法是将特征哈希到一个固定的值 域,比如全国的城市数大概在 210 量级,可以把城市名哈希成 [1,214] 上的一个 整数,城市就用 214 维的 one-hot 向量来表示,不同城市被哈希为同一个数字的 概率几乎为 0,且哈希之后的值直接对应 one-hot 向量中 1 元素的下标。

更简单的方法是把所有特征都hash到同一个很大(比如2^64)的空间,即把uid、年龄、城市、itemid等等全部使用同一个hash函数进行映射,当然需要把特征名和特征值拼接起来再做hash。由于hash后的空间很大,所以不同特征之间冲突的概率很低。

4.3 特征组合

LR是线性模型,表达能力有限。模型不足,特征来补。通过人工组合特征来使LR具有非线性表达能力。比如“性别_男_手机_ios”可能是个有用的特征,通常两个特征组合就可以了,超过3阶的人工特征组合都没有什么收益,这也是为什么xgboost的深度不建议超过5的原因。特征组合会导致特征维度极具膨胀,所以不建议高维特征(比如uid)跟其他特征进行组合,不建议高阶组合。

其实树模型学习的就是特征组合,所以可以用xgboost来代替人工的特征组合。

5 调参

这里的调参,指的是上线后根据发现的badcase来调整参数。

在CTR项目中一个好的模型主要在学习的就是item的热度,试想一下你打算在电商网站上买一本机器学习相关的书,你大概率会点击那些非常热门的图书,在大多数推荐场景中热度高于个性化因素。

使用FTRL进行训练的好处在于:学习率是动态调整的,且不同特征上的学习率是不同的。这一点在我的书里面有详细的解释。

有些场景下商品的热度变化得比较快,模型需要及时感知到这种变化,itemid对应的学习率就需要调得大一些。

正则化的目的是防止模型去拟合少数的样本。在你的系统中如果点击率很低,则历史样本需要很多得到的点击率才比较可信,此时需要加大itemid上的正则系数。

posted @ 2020-02-15 20:46  高性能golang  阅读(1324)  评论(0编辑  收藏  举报