【腾讯转化率预估】贝叶斯平滑

1. 概述

​ 电商领域中经常需要计算或预测一些转化率指标,如最典型的CTR(点击率,Click-Through Rate),这些转化率可以是模型的预测值,也可以作为模型的特征(feature)使用。我们在比赛中就以转化率作为特征来使用。

以商品点击率预测为例,CTR的值等于点击量(Click)除以曝光量(Impression或Exposure)。以r表示点击率,

但在实际应用过程中会碰到两个问题:

  • 新商品点击率的预测与计算
    对于新上线的商品,其曝光为0,点击量也为0,此时这件商品的CTR应该设为0还是赋一个初始值?
  • 不同商品点击率之间的比较
    有两件商品A和B,其点击率分别为,但商品A的曝光只有10次,商品B的曝光有100次,这样比较是否合理?

第一个问题,初始值设0是可以的,但不太合理。当CTR作为特征使用时,表示这个商品完全没有点击,不太符合日常推断,通常是赋一个大于0的初始值。第二个问题,不合理。

解决以上两个问题可以使用平滑的技术解决。最简单的方法是在计算CTR的公式中分子分母同时加上一个数,加上之后可避免这两个问题。

但(2)式中a和b的值如何确定?若设置得不合理会出现数据被放大的情况。本文介绍如何使用贝叶斯平滑来确定a和b的值。

2. 贝叶斯平滑思想

​ 贝叶斯平滑的思想是给CTR预设一个经验初始值,再通过当前的点击量和曝光量来修正这个初始值。如果某商品的点击量和曝光量都是0,那么该商品的CTR就是这个经验初始值;如果商品A和商品B的曝光量差别很大,那么可以通过这个经验初始值来修正,使得曝光量大的商品的权重增大。

​ 贝叶斯平滑就是确定这个经验值的过程。贝叶斯平滑是基于贝叶斯统计推断的,因此经验值计算的过程依赖于数据的分布情况。

3. 点击率贝叶斯平滑的假设

​ 对于一件商品或一条广告,对于某次曝光,用户要么点击,要么没点击,这符合二项分布。因此下文中对于点击率类的贝叶斯平滑,都是基于以下假设:对于某件商品或广告,其是否被点击是一个伯努利分布(Bernoulli)/二项分布

​ 其中X表示某个广告是否被点击,点击取1,未被点击取0,是某件商品被点击的概率,即点击率

在贝叶斯框架下,我们假设点击率服从某个分布:

因为这是基于经验的,这个分布称为先验分布。贝叶斯参数估计可以同时解决最开始提出的两个问题。其过程是基于经验或历史数据先给出一个r的估计值,然后基于现有的数据在这个估计值上修正,得到最终的点击率估计,此时的估计值已经是修正过的。更美好的是我们可以分离出修正参数(即(2)式中的a和b)。

既然有先验分布,就有后验分布的后验分布记作。其中表示输入数据或特征,对于点击率预测, 就是点击次数和曝光量。因为已经看到了数据,才确定的分布,因此叫做『后验』分布。贝叶斯估计的实质就是求后验分布。即基于当前的点击次数和曝光量,求点击率的分布;而未看到数据之前点击率的分布是

总结一下,贝叶斯估计的过程可以简单认为:

用历史数据根据估计,记作;用当前数据根据估计,记作,然后用修正

为什么是beta分布?

由于是否点击是服从伯努利分布的,伯努利分布的共轭先验分布是Beta分布,因此我们认为点击率是服从Beta分布的。

共轭先验分布性质:
如果找到一个,它是的共轭先验,那么的后验分布和先验分布会有一样的形式。

也就是说

点击率的先验分布

当误差是平方误差的时候,可以解出:

也就是 的均值,也就是相当于针对当前数据I和C的“定制化”Beta分布。然后用Beta分布的期望作为点击率的经验值,因为这样的误差最小。

上面的内容给出了为什么很多文章会假设点击率服从Beta分布的理由,因为最终的平滑的因子是Beta分布(先验分布)中的两个参数。那么如何计算(估计)这两个参数?

4. 贝叶斯平滑因子的计算(矩估计)

综上,贝叶斯平滑的最终落脚点是要估计Beta分布(点击率r服从的分布)中的参数。下面给出比较直观的矩估计的方法,我们在比赛中也是采用的这种方法,其优点是计算速度快,但同时也就牺牲了一定的精确程度。

首先,矩估计的原理:样本与总体的原点矩是近似的 ,可以通过让它们相等来计算。

beta分布的期望(一阶矩)是:

beta分布的方差(二阶矩)是:

因此为了估计两个参数 ,可以采用二阶矩估计的方法,

我们可以用样本的均值代替期望,样本的方差代替总体的方差,此时就可以解出α和β的值。是样本均值,是样本方差,则解为:

代码:

class HyperParam(object):
def __init__(self, alpha, beta):
self.alpha = alpha
self.beta = beta
def sample_from_beta(self, alpha, beta, num, imp_upperbound):
sample = numpy.random.beta(alpha, beta, num)
I = []
C = []
for click_ratio in sample:
imp = random.random() * imp_upperbound
#imp = imp_upperbound
click = imp * click_ratio
I.append(imp)
C.append(click)
return I, C
# 矩估计,根据均值和方差
def update_from_data_by_moment(self, tries, success):
'''estimate alpha, beta using moment estimation'''
mean, var = self.__compute_moment(tries, success)
#print 'mean and variance: ', mean, var
#self.alpha = mean*(mean*(1-mean)/(var+0.000001)-1)
self.alpha = (mean+0.000001) * ((mean+0.000001) * (1.000001 - mean) / (var+0.000001) - 1)
#self.beta = (1-mean)*(mean*(1-mean)/(var+0.000001)-1)
self.beta = (1.000001 - mean) * ((mean+0.000001) * (1.000001 - mean) / (var+0.000001) - 1)
# 计算均值和方差,也就是一阶和二阶矩
def __compute_moment(self, tries, success):
'''moment estimation'''
ctr_list = []
# var = 0.0
mean = (success/tries).mean()
if len(tries)==1:
var = 0
else:
var = (success/tries).var()
return mean, var

5. 分层贝叶斯平滑

由于广告数据是分为:广告主 —>广告 —> 推广计划 —>广告创意 四个层级的,因此在做平滑的时候,可以依照层级关系进行平滑。

核心思想就是认为同一个推广计划的点击率服从一个beta分布,同一个广告的点击率服从一个beta分布,以此类推,同一个广告主也服从一个beta分布。因此我们队不同的推广计划、广告、广告主都求出不同的参数a和b。

当遇到新出现的广告创意时,就用其所属推广计划的a和b来估计(修正)其点击率,同样当出现一个新的推广计划时,就用其所属的广告的a和b来修正其点击率。

这样做的效果要比单纯从单一维度来平滑效果要好一些。

参考资料

阿拉丁吃米粉-贝叶斯参数估计的理解

阿拉丁吃米粉-http://blog.csdn.net/jinping_shi/article/details/78334362

笨兔勿应-CTR预估中的贝叶斯平滑方法(一)原理及实验介绍