拍卖与博弈:计算广告中的底价问题

2024-09-03 18:38

本文主要是介绍拍卖与博弈:计算广告中的底价问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

流量变现和RTB

现代计算广告中,最广泛的流量交易模式为实时竞价模式,即Real-Time-Bidding(RTB)。实时竞价顾名思义,就是在流量到达时被放到交易市场进行公开的,实时的竞拍,参与竞拍的广告主赢得竞拍后,即可获得对这个流量的投放权,整个流程如图示。
RTB
以新浪微博的信息流广告为例,当我们刷微博时,微博的信息流(或者timeline)中会夹杂着广告,假设微博将信息流的第4和第10位作为广告位,那么每次你刷新微博后,list中的第4和第10条微博总会是推广(广告)微博。于是当用户A进入微博的信息流界面时,除了从服务器请求微博内容之外,还会同时向RTB请求广告内容,这个请求称之为曝光请求。RTB接受到该曝光请求后,将此次曝光放入流量市场进行实时拍卖,诸多广告主的投放系统(DSP)接到拍卖的事件后,立即对该曝光请求进行出价,一般来说根据曝光质量和属性不同,各个广告主对其出价也不尽相同。例如信息流第4位的曝光出价就比信息流第10位出价高,因为排在前面的广告更能引起用户注意,再如篮球鞋销售商对男性微博用户的曝光请求出价要比女性微博用户的曝光出价要高,因为篮球鞋的受众群体主要是男性。在广告主出价完成后,RTB则向出价最高的广告主请求广告内容,并且将此内容返回到微博客户端,于是用户在刷微博时就看到了这个广告,完成了一次广告曝光。这整个请求、竞价、返回广告的过程会在毫秒级别内完成。

第二高价和底价问题

在RTB的流量竞拍中是按照第二高价来计费的,这意味着如果第 t t t次曝光n个广告主对其出价分别为 b 1 ( t ) , b 2 ( t ) , b 3 ( t ) , . . . , b n ( t ) b_1(t),b_2(t),b_3(t),...,b_n(t) b1(t),b2(t),b3(t),...,bn(t),且有 b 1 ( t ) > b 2 ( t ) > b 3 ( t ) > . . . > b n ( t ) b_1(t)>b_2(t)>b_3(t)>...>b_n(t) b1(t)>b2(t)>b3(t)>...>bn(t),那么广告主1竞价胜出,但是媒体方只会向广告主1收费 b 2 b_2 b2元。这种计费方式主要可以让广告主失去调价的动力,否则在广告主竞价胜出之后,会立即调低出价,以期望使用更低的价格拿到曝光,从而提高自身收益。但是从媒体方的角度来说,第二高价的机制存在着 δ = b 1 ( t ) − b 2 ( t ) \delta = b_1(t)-b_2(t) δ=b1(t)b2(t)的利润空间没有充分利用,于是引出了底价机制。底价机制指的是RTB在竞价拍卖的过程中,设置一个最低价格 α \alpha α, 称之为底价。当 b 1 ( t ) < α b_1(t)<\alpha b1(t)<α时则RTB则拒绝售卖该流量,或者将流量导入其它交易市场售卖。当 b 1 ( t ) ≥ α > b 2 ( t ) b_1(t) \ge \alpha>b_2(t) b1(t)α>b2(t)时,按照 α \alpha α向胜出的广告主收费,当 b 2 ( t ) ≥ α b_2(t) \ge \alpha b2(t)α时,则按照 b 2 ( t ) b_2(t) b2(t)向胜出的广告主收费。总结起来,在第 t t t次竞价中,向竞价胜出的广告主收费 r ( t ) r(t) r(t)如式(1)所示。
r ( t ) = { α , b 1 ( t ) ≥ α > b 2 ( t ) b 2 ( t ) , b 2 ( t ) ≥ α 0 , α > b 1 ( t ) (1) r(t)=\left\{\begin{array}{ll}{\alpha,} & {b_{1}(t) \geq \alpha>b_{2}(t)} \\ {b_{2}(t),} & {b_{2}(t) \geq \alpha} \\ {0,} & {\alpha>b_{1}(t)}\end{array}\right. \tag{1} r(t)=α,b2(t),0,b1(t)α>b2(t)b2(t)αα>b1(t)(1)
r ( t ) r(t) r(t)的表达式中可以看到,当满足 b 1 ( t ) ≥ α > b 2 ( t ) b_1(t) \ge \alpha > b_2(t) b1(t)α>b2(t)时,媒体放可以比原来的纯二价计费方式多赚 β ( t ) = α − b 2 ( t ) \beta(t)=\alpha-b_2(t) β(t)=αb2(t),但也要注意到当 α > b 1 ( t ) \alpha > b_1(t) α>b1(t)时也存在损失 b 2 ( t ) b_2(t) b2(t)的风险。于是一个很自然的想法就是:

α \alpha α能自动调整,让 α \alpha α b 1 ( t ) b_1(t) b1(t)较大时, α \alpha α也能随之增大,反之则减小。 – 原则[1]

这就是动态底价的概念,我们重新把这个可以变化的底价定义为 α ( t ) \alpha(t) α(t),表示在第 t t t次竞价中的底价。式子(1)重新表述为式(2)。
r ′ ( t ) = { α ( t ) , b 1 ( t ) ≥ α ( t ) > b 2 ( t ) b 2 ( t ) , b 2 ( t ) ≥ α ( t ) 0 , α ( t ) > b 1 ( t ) (2) r^{\prime}(t)=\left\{\begin{array}{ll}{\alpha(t),} & {b_{1}(t) \geq \alpha(t)>b_{2}(t)} \\ {b_{2}(t),} & {b_{2}(t) \geq \alpha(t)} \\ {0,} & {\alpha(t)>b_{1}(t)}\end{array}\right. \tag{2} r(t)=α(t),b2(t),0,b1(t)α(t)>b2(t)b2(t)α(t)α(t)>b1(t)(2)
目前动态底价的算法主要有三种:

  1. 基于贝叶斯推断的底价估计算法
  2. 基于均值统计的底价估计算法
  3. 基于经验的One-Shot底价调整算法

下面逐一介绍这三个算法。

基于贝叶斯推断的底价估计算法

该算法首先假设在一次RTB竞价的过程中,最高出价 B 1 B_1 B1为满足对数高斯分布的随机变量,并且假设其方差已知(可以当成超参数来调),而其均值的先验分布为高斯分布,即:
B 1 ∼ lognorm ⁡ ( μ , σ 2 ) μ ( t ) ∼ N ( θ ( t ) , δ 2 ( t ) ) (3) \begin{aligned} B_{1} & \sim \operatorname{lognorm}\left(\mu, \sigma^{2}\right) \\ \mu(t) & \sim \mathcal{N}\left(\theta(t), \delta^{2}(t)\right) \end{aligned} \tag{3} B1μ(t)lognorm(μ,σ2)N(θ(t),δ2(t))(3)
假设 μ ( t ) \mu(t) μ(t)的分布在系统上线前已经由历史时刻 [ 0 , t ] [0,t] [0,t]的数据拟合得到了 θ ( t ) \theta(t) θ(t) δ 2 ( t ) \delta^2(t) δ2(t),当系统在线运行时, t + 1 t+1 t+1竞拍结束后得到一个最高出价的样本 b 1 ( t + 1 ) b_1(t+1) b1(t+1),这样由于对数高斯分布和高斯分布为共轭分布,可以直接后验分布
p ( θ ( t ) ∣ b 1 ( t + 1 ) ) = N ( θ ( t + 1 ) ∣ θ ( t ) , δ 2 ( t ) ) (4) \begin{aligned} p(\theta(t) | b_1(t+1))=\mathcal{N}\left(\theta(t+1) | \theta(t), \delta^{2}(t)\right) \end{aligned} \tag{4} p(θ(t)b1(t+1))=N(θ(t+1)θ(t),δ2(t))(4)
其中
θ ( t + 1 ) = θ ( t ) δ 2 ( t ) + σ 2 b 1 ( t + 1 ) σ 2 + δ 2 ( t ) δ 2 ( t + 1 ) = δ 2 ( t ) σ 2 σ 2 + δ 2 ( t ) (5) \begin{aligned} \theta(t+1) &=\frac{\theta(t) \delta^{2}(t)+\sigma^{2} b_{1}(t+1)}{\sigma^{2}+\delta^{2}(t)} \\ \delta^{2}(t+1) &=\frac{\delta^{2}(t) \sigma^{2}}{\sigma^{2}+\delta^{2}(t)} \end{aligned} \tag{5} θ(t+1)δ2(t+1)=σ2+δ2(t)θ(t)δ2(t)+σ2b1(t+1)=σ2+δ2(t)δ2(t)σ2(5)
这样根据最大后验估计的原则,我们可以使用 θ ( t ) \theta(t) θ(t)来作为 μ \mu μ的估计,并且根据式(3)可知,可以将 l o g ( θ ( t ) ) log(\theta(t)) log(θ(t))作为对 B 1 B_1 B1的估计。根据原则[1], 只要简单地设置:
α ( t + 1 ) = l o g ( θ ( t + 1 ) ) (6) \alpha(t+1) = log(\theta(t+1)) \tag{6} α(t+1)=log(θ(t+1))(6)
可以看到基于贝叶斯推断的方法首先估计了 b 1 ( t + 1 ) b_1(t+1) b1(t+1),然后通过设置 α ( t + 1 ) \alpha(t+1) α(t+1)逼近 b 1 ( t + 1 ) b_1(t+1) b1(t+1)的方式来最大化本次曝光的收益。

基于均值统计的底价估计算法

均值估计的想法其实十分朴素:本次曝光的收益应当不低于历史平均收益。于是很直接的,使用 t − 1 t-1 t1时刻的历史平均收益来作为 α ( t ) \alpha(t) α(t)的估计:
α ( t ) = 1 M ∑ i = t − M t − 1 r ( i ) (7) \alpha(t)=\frac{1}{M} \sum_{i=t-M}^{t-1} r(i) \tag{7} α(t)=M1i=tMt1r(i)(7)
当然,线上系统的运行环境是会发生改变的,比如说流量分布,竞争环境,等等。所以收益分布应当也不是一个静态的分布,并且当样本越靠近当前时刻,则越有可能采样于当前的收益分布,所以计算平均收益时,应当使用加权平均的方式来进行,并且设置离当前时刻越近的数据,权重就越高:
α ( t ) = 1 M ∑ i = t − M t − 1 w ( i , t ) r ( i ) (8) \alpha(t)=\frac{1}{M} \sum_{i=t-M}^{t-1} w(i, t) r(i) \tag{8} α(t)=M1i=tMt1w(i,t)r(i)(8)
其中 w ( i , t ) w(i,t) w(i,t)的选择可以多种多样,只要满足当前时刻越近的数据,权重就越高的原则即可。

ONE-SHOT底价调整算法

ONE-SHOT其实是一个调整算法而不是一个估计算法。其工作的流程是:

  1. 给定一个初始底价 α ( t ) \alpha(t) α(t)
  2. 根据一定规则在 α ( t ) \alpha(t) α(t)的基础上调整得到 α ( t + 1 ) \alpha(t+1) α(t+1)

初始底价可以根据经验直接指定,也可以通过式子(7)对历史数据统计给出。而调整的原则在于:

当底价低于 b 1 b_1 b1时,则应当缓慢提高底价,当底价高于 b 1 b_1 b1时应当迅速降低底价 --原则[2]

原则[2]提出的基本思想是:当底价低于 b 1 b_1 b1时,虽然此时收益并非是最大化的,但毕竟有 b 2 b_2 b2作为保证,收益不会太低,所以底价上涨探索最优的收费不必太过于急切,但如果底价高于 b 1 b1 b1时,收益将会直接变为0,所以需要快速降低底价,让 b 2 b_2 b2来保证收益。

根据原则[2],当然可以设置固定的小步伐 s u s_u su和大步伐 s l s_l sl来调整底价。但是为了平滑和鲁棒性,可以根据式(9)来执行调整过程。
{ α ( t + 1 ) = ( 1 − ϵ t λ h ) a ( t ) if  α ( t ) > b 1 ( t ) α ( t + 1 ) = ( 1 + ϵ t λ e ) a ( t ) if  b 1 ( t ) ≥ α ( t ) ≥ b 2 ( t ) α ( t + 1 ) = ( 1 + ϵ t λ l ) α ( t ) if  b 2 ( t ) > α ( t ) (9) \left\{\begin{array}{ll}{\alpha(t+1)=\left(1-\epsilon^{t} \lambda_{h}\right) a(t)} & {\text { if } \alpha(t)>b_{1}(t)} \\ {\alpha(t+1)=\left(1+\epsilon^{t} \lambda_{e}\right) a(t)} & {\text { if } b_{1}(t) \geq \alpha(t) \geq b_{2}(t)} \\ {\alpha(t+1)=\left(1+\epsilon^{t} \lambda_{l}\right) \alpha(t)} & {\text { if } b_{2}(t)>\alpha(t)}\end{array}\right. \tag{9} α(t+1)=(1ϵtλh)a(t)α(t+1)=(1+ϵtλe)a(t)α(t+1)=(1+ϵtλl)α(t) if α(t)>b1(t) if b1(t)α(t)b2(t) if b2(t)>α(t)(9)
其中 ϵ ∈ ( 0 , 1 ] \epsilon \in (0, 1] ϵ(0,1] λ h , λ e , λ l ∈ [ 0 , 1 ] \lambda_h, \lambda_e, \lambda_l \in [0, 1] λh,λe,λl[0,1], ϵ \epsilon ϵ是一个时间衰减系数,如果RTB只希望在启动后个某个时间段调整底价,并且最终收敛,则可以通过这个参数来调整。而 λ h \lambda_h λh则用于调整当 α ( t ) > b 1 ( t ) \alpha(t) > b_1(t) α(t)>b1(t)时底价的降低速度。而同理 λ l \lambda_l λl用来调整当 α ( t ) < b 2 ( t ) \alpha(t) < b_2(t) α(t)<b2(t)时底价的提升速度。 λ e \lambda_e λe则用于调整探索最优收益的速度。从业务上来说,往往会设置 λ h > λ l > λ e \lambda_h>\lambda_l>\lambda_e λh>λl>λe,即当前收益越高,调整速度越慢,这与原则[2]的基本思想是一致的。

其他讨论

上述三种底价算法里,基于贝叶斯推断的算法的数学理论是最完备的,但必须要考虑到这种算法存在最高出价符合对数高斯分布这个假设前提的。这个假设并非放之四海而皆准的,各个广告系统的业务不一样,符合的分布也不一样,需要选择合适的分布,才能做出好的效果。并且需要注意的是,该算法优化的是单次曝光收益,并没有从全局的视角来考虑底价问题,不一定在整体收益上是最高的。

基于统计均值的算法是最朴素的,也是最容易实现的,不失为一个短平快的解决方案,它应当作为任何动态底价第一版本的最好选择,至少你能有一个Baseline去观察你的系统,判断动态底价对于你的广告系统来说是否是必要的,是否真的能提升收入。

而ONE-SHOT算法虽然没有数学理论支撑,但它作为一种博弈思维的产物,有从业务和全局的视角去考虑底价问题,从直觉上来看是最值得尝试的一种。当然,我想ONE-SHOT算法应当还有许多改进的空间,比如 λ h , λ e , λ l \lambda_h, \lambda_e,\lambda_l λh,λe,λl参数的值可以跟贝叶斯推断来动态调整的值,也可以通过反馈控制的方法来动态调整。

但最终,无论如何,这里都没办法给哪一种算法的优劣性下一个断论,毕竟业务多种多样,只能认真做好A/B Test,好好调参,根据实际业务表现来选择算法了。

这篇关于拍卖与博弈:计算广告中的底价问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133728

相关文章

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

解决systemctl reload nginx重启Nginx服务报错:Job for nginx.service invalid问题

《解决systemctlreloadnginx重启Nginx服务报错:Jobfornginx.serviceinvalid问题》文章描述了通过`systemctlstatusnginx.se... 目录systemctl reload nginx重启Nginx服务报错:Job for nginx.javas

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

解决Cron定时任务中Pytest脚本无法发送邮件的问题

《解决Cron定时任务中Pytest脚本无法发送邮件的问题》文章探讨解决在Cron定时任务中运行Pytest脚本时邮件发送失败的问题,先优化环境变量,再检查Pytest邮件配置,接着配置文件确保SMT... 目录引言1. 环境变量优化:确保Cron任务可以正确执行解决方案:1.1. 创建一个脚本1.2. 修

Python 标准库time时间的访问和转换问题小结

《Python标准库time时间的访问和转换问题小结》time模块为Python提供了处理时间和日期的多种功能,适用于多种与时间相关的场景,包括获取当前时间、格式化时间、暂停程序执行、计算程序运行时... 目录模块介绍使用场景主要类主要函数 - time()- sleep()- localtime()- g