在协同过滤和矩阵分解存在的劣势就是仅利用了用户与物品相互行为信息进行推荐, 忽视了用户自身特征, 物品自身特征以及上下文信息等,导致生成的结果往往会比较片面。
2014年由Facebook提出的GBDT+LR模型, 该模型利用GBDT自动进行特征筛选和组合, 进而生成新的离散特征向量, 再把该特征向量当做LR模型的输入, 来产生最后的预测结果, 该模型能够综合利用用户、物品和上下文等多种不同的特征, 生成较为全面的推荐结果, 在CTR点击率预估场景下使用较为广泛。
下面首先会介绍逻辑回归和GBDT模型各自的原理及优缺点, 然后介绍GBDT+LR模型的工作原理和细节。
在推荐领域里面, 相比于传统的协同过滤, 逻辑回归模型能够综合利用用户、物品、上下文等多种不同的特征生成较为“全面”的推荐结果。
逻辑回归是在线性回归的基础上加了一个 Sigmoid 函数(非线形)映射,使得逻辑回归成为了分类算法, 学习逻辑回归模型, 首先应该记住一句话:逻辑回归假设数据服从伯努利分布,通过极大化似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类的目的。
相比于协同过滤和矩阵分解利用用户的物品“相似度”进行推荐, 逻辑回归模型将问题看成了一个分类问题, 通过预测正样本的概率对物品进行排序。这里的正样本可以是用户“点击”了某个商品或者“观看”了某个视频, 均是推荐系统希望用户产生的“正反馈”行为, 因此逻辑回归模型将推荐问题转化成了一个点击率预估问题。而点击率预测就是一个典型的二分类, 正好适合逻辑回归进行处理, 那么逻辑回归是如何做推荐的呢? 过程如下:
推断过程可以用下图来表示:
这里的关键就是每个特征的权重参数 w w w, 我们一般是使用梯度下降的方式, 首先会先随机初始化参数 w w w, 然后将特征向量(也就是我们上面数值化出来的特征)输入到模型, 就会通过计算得到模型的预测概率, 然后通过对目标函数求导得到每个 w w w的梯度, 然后进行更新 w w w
这里的目标函数长下面这样:
J ( w ) = − 1 m ( ∑ i = 1 m ( y i log f w ( x i ) + ( 1 − y i ) log ( 1 − f w ( x i ) ) ) J(w)=-\frac{1}{m}\left(\sum_{i=1}^{m}\left(y^{i} \log f_{w}\left(x^{i}\right)+\left(1-y^{i}\right) \log \left(1-f_{w}\left(x^{i}\right)\right)\right)\right. J(w)=−m1(i=1∑m(yilogfw(xi)+(1−yi)log(1−fw(xi))) 求导之后的方式长这样: w j ← w j − γ 1 m ∑ i = 1 m ( f w ( x i ) − y i ) x j i w_{j} \leftarrow w_{j}-\gamma \frac{1}{m} \sum_{i=1}^{m}\left(f_{w}\left(x^{i}\right)-y^{i}\right) x_{j}^{i} wj←wj−γm1i=1∑m(fw(xi)−yi)xji 这样通过若干次迭代, 就可以得到最终的 w w w了, 关于这些公式的推导,可以参考下面给出的文章链接, 下面我们分析一下逻辑回归模型的优缺点。
优点:
缺点:
所以如何自动发现有效的特征、特征组合,弥补人工经验不足,缩短LR特征实验周期,是亟需解决的问题, 而GBDT模型, 正好可以自动发现特征并进行有效组合。
GBDT全称梯度提升决策树,在传统机器学习算法里面是对真实分布拟合的最好的几种算法之一,在前几年深度学习还没有大行其道之前,GBDT在各种竞赛是大放异彩。原因有:
一是效果很好。
二是即可以用于分类也可以用于回归。
三是可以筛选特征。
所以这个模型依然是一个非常重要的模型。
GBDT是通过采用加法模型(即基函数的线性组合),以及不断减小训练过程产生的误差来达到将数据分类或者回归的算法, 其训练过程如下:
GBDT通过多轮迭代, 每轮迭代会产生一个弱分类器, 每个分类器在上一轮分类器的残差基础上进行训练。 GBDT对弱分类器的要求一般是足够简单, 并且低方差高偏差。 因为训练的过程是通过降低偏差来不断提高最终分类器的精度。 由于上述高偏差和简单的要求,每个分类回归树的深度不会很深。最终的总分类器是将每轮训练得到的弱分类器加权求和得到的(也就是加法模型)。
GBDT如何来进行二分类的,因为我们要明确一点就是gbdt 每轮的训练是在上一轮的训练的残差基础之上进行训练的, 而这里的残差指的就是当前模型的负梯度值, 这个就要求每轮迭代的时候,弱分类器的输出的结果相减是有意义的, 而gbdt 无论用于分类还是回归一直都是使用的CART 回归树, 那么既然是回归树, 是如何进行二分类问题的呢?
GBDT 来解决二分类问题和解决回归问题的本质是一样的,都是通过不断构建决策树的方式,使预测结果一步步的接近目标值, 但是二分类问题和回归问题的损失函数是不同的, 关于GBDT在回归问题上的树的生成过程, 损失函数和迭代原理可以参考给出的链接, 回归问题中一般使用的是平方损失, 而二分类问题中, GBDT和逻辑回归一样, 使用的下面这个:
L = arg min [ ∑ i n − ( y i log ( p i ) + ( 1 − y i ) log ( 1 − p i ) ) ] L=\arg \min \left[\sum_{i}^{n}-\left(y_{i} \log \left(p_{i}\right)+\left(1-y_{i}\right) \log \left(1-p_{i}\right)\right)\right] L=argmin[i∑n−(yilog(pi)+(1−yi)log(1−pi))] 其中, y i y_i yi是第 i i i个样本的观测值, 取值要么是0要么是1, 而 p i p_i pi是第 i i i个样本的预测值, 取值是0-1之间的概率,由于我们知道GBDT拟合的残差是当前模型的负梯度, 那么我们就需要求出这个模型的导数, 即 d L d p i \frac{dL}{dp_i} dpidL, 对于某个特定的样本, 求导的话就可以只考虑它本身, 去掉加和号, 那么就变成了 d l d p i \frac{dl}{dp_i} dpidl, 其中 l l l如下: l = − y i log ( p i ) − ( 1 − y i ) log ( 1 − p i ) = − y i log ( p i ) − log ( 1 − p i ) + y i log ( 1 − p i ) = − y i ( log ( p i 1 − p i ) ) − log ( 1 − p i ) \begin{aligned} l &=-y_{i} \log \left(p_{i}\right)-\left(1-y_{i}\right) \log \left(1-p_{i}\right) \ &=-y_{i} \log \left(p_{i}\right)-\log \left(1-p_{i}\right)+y_{i} \log \left(1-p_{i}\right) \ &=-y_{i}\left(\log \left(\frac{p_{i}}{1-p_{i}}\right)\right)-\log \left(1-p_{i}\right) \end{aligned} l=−yilog(pi)−(1−yi)log(1−pi) =−yilog(pi)−log(1−pi)+yilog(1−pi) =−yi(log(1−pipi))−log(1−pi) 如果对逻辑回归非常熟悉的话, ( log ( p i 1 − p i ) ) \left(\log \left(\frac{p_{i}}{1-p_{i}}\right)\right) (log(1−pipi))一定不会陌生吧, 这就是对几率比取了个对数, 并且在逻辑回归里面这个式子会等于 θ X \theta X θX, 所以才推出了 p i = 1 1 + e − θ X p_i=\frac{1}{1+e^-{\theta X}} pi=1+e−θX1的那个形式。 这里令 η i = p i 1 − p i \eta_i=\frac{p_i}{1-p_i} ηi=1−pipi, 即 p i = η i 1 + η i p_i=\frac{\eta_i}{1+\eta_i} pi=1+ηiηi, 则上面这个式子变成了:
l = − y i log ( η i ) − log ( 1 − e log ( η i ) 1 + e log ( η i ) ) = − y i log ( η i ) − log ( 1 1 + e log ( η i ) ) = − y i log ( η i ) + log ( 1 + e log ( η i ) ) \begin{aligned} l &=-y_{i} \log \left(\eta_{i}\right)-\log \left(1-\frac{e^{\log \left(\eta_{i}\right)}}{1+e^{\log \left(\eta_{i}\right)}}\right) \ &=-y_{i} \log \left(\eta_{i}\right)-\log \left(\frac{1}{1+e^{\log \left(\eta_{i}\right)}}\right) \ &=-y_{i} \log \left(\eta_{i}\right)+\log \left(1+e^{\log \left(\eta_{i}\right)}\right) \end{aligned} l=−yilog(ηi)−log(1−1+elog(ηi)elog(ηi)) =−yilog(ηi)−log(1+elog(ηi)1) =−yilog(ηi)+log(1+elog(ηi)) 这时候,我们对 l o g ( η i ) log(\eta_i) log(ηi)求导, 得 d l d log ( η i ) = − y i + e log ( η i ) 1 + e log ( η i ) = − y i + p i \frac{d l}{d \log (\eta_i)}=-y_{i}+\frac{e^{\log \left(\eta_{i}\right)}}{1+e^{\log \left(\eta_{i}\right)}}=-y_i+p_i dlog(ηi)dl=−yi+1+elog(ηi)elog(ηi)=−yi+pi 这样, 我们就得到了某个训练样本在当前模型的梯度值了, 那么残差就是 y i − p i y_i-p_i yi−pi。GBDT二分类的这个思想,其实和逻辑回归的思想一样,逻辑回归是用一个线性模型去拟合 P ( y = 1 ∣ x ) P(y=1|x) P(y=1∣x)这个事件的对数几率 l o g p 1 − p = θ T x log\frac{p}{1-p}=\theta^Tx log1−pp=θTx, GBDT二分类也是如此, 用一系列的梯度提升树去拟合这个对数几率, 其分类模型可以表达为: P ( Y = 1 ∣ x ) = 1 1 + e − F M ( x ) P(Y=1 \mid x)=\frac{1}{1+e^{-F_{M}(x)}} P(Y=1∣x)=1+e−FM(x)1
GBDT的优缺点:
我们可以把树的生成过程理解成自动进行多维度的特征组合的过程,从根结点到叶子节点上的整个路径(多个特征值判断),才能最终决定一棵树的预测值, 另外,对于连续型特征的处理,GBDT 可以拆分出一个临界阈值,比如大于 0.027 走左子树,小于等于 0.027(或者 default 值)走右子树,这样很好的规避了人工离散化的问题。这样就非常轻松的解决了逻辑回归那里自动发现特征并进行有效组合的问题, 这也是GBDT的优势所在。
但是GBDT也会有一些局限性, 对于海量的 id 类特征,GBDT 由于树的深度和棵树限制(防止过拟合),不能有效的存储;另外海量特征在也会存在性能瓶颈,当 GBDT 的 one hot 特征大于 10 万维时,就必须做分布式的训练才能保证不爆内存。所以 GBDT 通常配合少量的反馈 CTR 特征来表达,这样虽然具有一定的范化能力,但是同时会有信息损失,对于头部资源不能有效的表达。
所以, 我们发现其实GBDT和LR的优缺点可以进行互补。
这个模型也就是将是上面的进行结合:
训练时 GBDT 建树的过程相当于自动进行的特征组合和离散化,然后从根结点到叶子节点的这条路径就可以看成是不同特征进行的特征组合,用叶子节点可以唯一的表示这条路径,并作为一个离散特征传入 LR 进行二次训练。
比如上图中, 有两棵树,x为一条输入样本,遍历两棵树后,x样本分别落到两颗树的叶子节点上,每个叶子节点对应LR一维特征,那么通过遍历树,就得到了该样本对应的所有LR特征。构造的新特征向量是取值0/1的。 比如左树有三个叶子节点,右树有两个叶子节点,最终的特征即为五维的向量。对于输入x,假设他落在左树第二个节点,编码[0,1,0],落在右树第二个节点则编码[0,1],所以整体的编码为[0,1,0,0,1],这类编码作为特征,输入到线性分类模型(LR or FM)中进行分类。
预测时,会先走 GBDT 的每棵树,得到某个叶子节点对应的一个离散特征(即一组特征组合),然后把该特征以 one-hot 形式传入 LR 进行线性加权预测。
这个方案应该比较简单了, 下面有几个关键的点我们需要了解: