汤普森采样(Thompson sampling): 理论支持

目录

  • 一、UCB与TS算法数学原理
    • 1、Upper Confidence Bounds 数学原理
    • 2、Thompson sampling 数学原理
      • a、TS 基本数据原理
        • 1. beta 分布
        • 2. 共轭分布与共轭先验
        • 3. 采样的编程实现
      • b、TS 算法流程
        • 1. TS算法基础版本
        • 2. Batched Thompson Sampling[1]
  • 二、UCB与TS算法的优缺点
    • 1、TS算法的优缺
      • a、TS的一些基本性质
      • b、结合推荐场景,TS为什么有效
      • c、TS的不足
    • 2、UCB算法的优缺
      • a、UCB算法的一些基本性质
      • b、ucb 优点
      • c、ucb 缺点
      • 3、TS与UCB对比总结
  • 三、参考资源

一、UCB与TS算法数学原理

1、Upper Confidence Bounds 数学原理

汤普森采样(Thompson sampling): 理论支持_第1张图片
汤普森采样(Thompson sampling): 理论支持_第2张图片

Python demo

# !/usr/bin/python
# -*- coding=utf-8 -*-
# Name:         UCB
# Description:
# Author:       liu
# Date:         2021/9/14
# Mail:         

from __future__ import absolute_import
from __future__ import print_function
from __future__ import division

import numpy as np

N = 3  # 物品总数
T = 100  # 试验次数/轮数
epsilon = 0.1  # 贪婪系数
P = [0.5, 0.6, 0.55]  # 每个物品的真实被转化率
Round = [0, 0, 0]  # 每个物品被选中的次数
Reward = [0, 0, 0]  # 每个物品被转化的次数


def pull(N, epsilon, P):
    """通过epsilon-greedy来选择物品

    Args:
        N(int) :- 物品总数
        epsilon(float) :- 贪婪系数
        P(iterables) :- 每个物品被转化率
    Returns:
        本次选择的物品
    """
    # 通过一致分布的随机数来确定是搜索还是利用
    exploration_flag = True if np.random.uniform() <= epsilon else False

    # 如果选择探索
    if exploration_flag:
        i = int(min(N - 1, np.floor(N * np.random.uniform())))

    # 如果选择利用
    else:
        i = np.argmax(P)
    return i


def calculate_delta(Round, i):
    """利用所有物品被选中的次数和i物品被选中的次数来计算delta

    Args:
        Round(iterables) :- 每个物品被选择的次数
        i(int) :- 物品序号
    Returns:
        使得置信度为1-2/ sum(Round) ** 2的delta
    """
    round_i = Round[i]
    if round_i == 0:
        return 1
    else:
        return np.sqrt(np.log(sum(Round)) / round_i)


def calculate_empirical(Round, Reward, i):
    """利用所有物品被选中和获得奖励的次数来计算实证参数

    Args:
        Round(iterables) :- 每个物品被选择的次数
        Reward(iterables) :- 每个物品获得奖励的次数
        i(int) :- 物品序号
    Returns:
        i物品的实证参数
    """
    round_i = Round[i]
    if round_i == 0:
        return 1
    else:
        return Reward[i] / round_i


def trial_ucb(Reward, Round, rounds=T):
    """做rounds轮试验

    Args:
        Reward(iterables) :- 每个物品的被转化次数
        Round(iterables) :- 每个物品被选择的次数
        rounds(int) :- 一共试验的次数
    Returns:
        一共的转化数

    rewards来记录从头到位的奖励数
    """
    rewards = 0
    for t in range(rounds):
        P_ucb = [calculate_empirical(Round, Reward, i) + calculate_delta(Round, i) for i in range(len(Round))]
        i = pull(N, epsilon, P_ucb)
        Round[i] += 1
        reward = np.random.binomial(1, P[i])
        Reward[i] += reward
        rewards += reward
    return rewards


if __name__ == '__main__':
    trial_ucb(Reward, Round, rounds=T)

2、Thompson sampling 数学原理

a、TS 基本数据原理

1. beta 分布

Beta分布Bernoulli分布二项式分布 共轭先验,是(0, 1)上的随机变量的一种分布,它有两个大于0的参数α,β,概率密度函数为:
f B e ( θ ; α , β ) = θ α − 1 ( 1 − θ ) β − 1 B ( α , β ) f_{Be}(\theta ;\alpha,\beta )=\frac{\theta^{\alpha -1 } (1-\theta ) ^{\beta -1}}{B(\alpha,\beta)} fBe(θ;α,β)=B(α,β)θα1(1θ)β1其中: B ( α , β ) : = ∫ 0 1 θ α − 1 ( 1 − θ ) β − 1 d θ = Γ ( α ) Γ ( β ) Γ ( α + β ) B(\alpha,\beta):=\int_{0}^{1} \theta ^{\alpha -1}(1-\theta )^{\beta -1}\mathrm{d}\theta =\frac{\Gamma (\alpha) \Gamma (\beta)}{\Gamma (\alpha + \beta)} B(α,β):=01θα1(1θ)β1dθ=Γ(α+β)Γ(α)Γ(β)

  • 1> 其中B(α,β)B函数Γ(x)是伽马函数,B函数可以理解为归一化因子(Normalizer),其存在是为了使得概率的积分为1
  • 2> beta分布的支撑集: θ ∈ ( 0 , 1 ) \theta \in(0, 1) θ(0,1) 意义为二元随机变量X 其中一种结果x0的概率,所以Beta分布是一种“概率的概率分布”,其具体形式是为了满足贝叶斯推断过程中其内涵的一致性确定出来的。一般被用于建模伯努利试验事件成功的概率的概率分布。
  • 3>B函数在计算机求解中一般用Γ函数(分布)换算(如上面公式),计算机的内部实现就由积分变成阶乘
  • 4>Beta分布直观理解(可视化)
    汤普森采样(Thompson sampling): 理论支持_第3张图片
    图1 Probability density function (PDF)
    汤普森采样(Thompson sampling): 理论支持_第4张图片图2 Cumulative distribution function (CDF)

2. 共轭分布与共轭先验

  • 1> Beta分布二项分布的关系 (解释建模问题)
    进行n次伯努利试验,其出现试验成功的概率p服从一个先验概率密度分布: B e t a ( α , β ) Beta(\alpha,\beta) Beta(α,β),试验结果出现k次试验成功,则试验成功的概率p的后验概率密度分布为: B e t a ( α + k , β + n − k ) Beta(\alpha +k ,\beta + n -k) Beta(α+k,β+nk),解释为什么beta分布用建模伯努利实验

  • 2> 共轭分布与共轭先验 (解释参数更新问题)
    a、 {先验概率分布}*{实验数据/似然函数/似然概率} ∝ {后验概率分布} ,∝表示等比于。通过贝叶斯推理,可发现先验概率与后验概率具有同样的数学形式,所以也称它们为共轭分布(Conjugate Distribution),称先验概率似然函数共轭先验(Conjugate Prior)
    b、在MAB问题中,Bernoulli分布正好有Beta分布作为共轭先验,有了共轭先验,就容易做贝叶斯更新。为什么?因为beta 分布的更新只要考虑两个参数即可。
    c、所以 Thompson sampling,允许我们利用每个物品被转化率先验知识来设定每个beta分布的参数。
    d、在业务中的应用:α表示为点击的次数β表示为曝光了但没有点击的次数,所以α+β表示曝光数

3. 采样的编程实现

Python:np.random.beta(α, β)   #  返回值[0,1] 概率大小,其中α > 0,β > 0
C++:boost::random::beta_distribution<>(alpha, beta)  // alpha > 0,beta > 0

b、TS 算法流程

1. TS算法基础版本

汤普森采样(Thompson sampling): 理论支持_第5张图片

  • 为每个物品预估一对Beta分布的参数,可通过历史数据计算出来
  • 每次试验前从每个物品点击曝光数据的Beta分布中随机采样获得对应的被转化率得分
  • 选择被转化率最大的物品,进行输出/播放
  • 根据用户对物品是否转化,来更新该物品的Beta分布参数,具体来说,就是被转化则α加 1否则 β 加 1。(这个过程可以实时计算或者小时粒度进行在线计算)
  • python demo:
# !/usr/bin/python
# -*- coding=utf-8 -*-
# Name:         demo
# Description:
# Author:       liu
# Date:         2021/9/14
# Mail:         

from __future__ import absolute_import
from __future__ import print_function
from __future__ import division


import numpy as np

N = 3                # 物品总数
T = 100              # 试验次数/轮数
epsilon = 0.1        # 贪婪系数
P = [0.5, 0.6, 0.55]  # 每个物品的真实被转化率
Round = [0, 0, 0]    # 每个物品被选中的次数

Alpha = [25, 50, 75]  # 每个物品被转化率的Beta先验参数
Beta = [75, 50, 25]

# 在代码中加入了 epsilon-greedy 策略,这个过程不是必要的


def pull(N, epsilon, P):
    """通过epsilon-greedy来选择物品

    Args:
        N(int) :- 物品总数
        epsilon(float) :- 贪婪系数
        P(iterables) :- 每个物品被转化率
    Returns:
        本次选择的物品
    """
    # 通过一致分布的随机数来确定是搜索还是利用
    exploration_flag = True if np.random.uniform() <= epsilon else False

    # 如果选择探索
    if exploration_flag:
        i = int(min(N-1, np.floor(N*np.random.uniform())))

    # 如果选择利用
    else:
        i = np.argmax(P)
    return i


def trial_thompson(Alpha, Beta, rounds=T):
    """做rounds轮试验

    Args:
        Alpha, Beta(iterables) :- 每个物品被转化率的Beta分布的参数
        rounds(int) :- 一共试验的次数
    Returns:
        一共的转化数

    rewards来记录从头到位的奖励数
    """
    rewards = 0
    for t in range(rounds):
        P_thompson = [np.random.beta(Alpha[i], Beta[i]) for i in range(len(Round))]
        i = pull(N, epsilon, P_thompson)
        Round[i] += 1
        reward = np.random.binomial(1, P[i])
        Alpha[i] += reward
        Beta[i] += 1 - reward
        rewards += reward
    return rewards


if __name__ == '__main__':
    trial_thompson(Alpha, Beta, rounds=T)

2. Batched Thompson Sampling[1]

汤普森采样(Thompson sampling): 理论支持_第6张图片

BTS算法特点Beta 分布只在每批次的结束时进行更新,例如一个小时一次等

二、UCB与TS算法的优缺点

1、TS算法的优缺

a、TS的一些基本性质

  • (1)Beta分布主要有αβ两个参数,这两个参数决定了分布的形状,从上图及其均值和方差的公式可以看出
  • (2)α/(α+β)也就是均值,其越大,概率密度分布的中心位置越靠近1,依据此概率分布产生的随机数也多说都靠近1,反之则都靠近0
  • (3)α+β越大,则分布越窄,也就是集中度越高,这样产生的随机数更接近中心位置,从方差公式上也能看出来
  • (4)实现相对简单,计算量较小
  • (5)TS更大程度上利用了先验知识
  • (6)TS 基于贝叶斯思想,全部用概率分布来表达不确定性

b、结合推荐场景,TS为什么有效

  • (1)如果一个候选项被选中的次数越多,也就是α+β (曝光)越大,它的分布就会变窄,换言之,这个候选项的收益已经非常确定了,不管分布中心靠近0,还是靠近1,都几乎比较确定。用它产生的随机数,基本上就在中心位置附近,接近平均收益。
  • (2)如果一个候选项不但α+β 很大,即分布很窄,而且α/(α+β) 也很大(点击率很高),靠近1,那就确定这是个好的候选项,平均收益很好,每次选择很占优势,就进入利用阶段(Exploitation)。反之则有可能平均分布比较靠近0几乎再无出头之日
  • (3)如果一个候选的α+β很小(曝光很少),分布很宽,也就是没有被选择太多次,说明这个候选项是好是坏还不确定,那么分布就是跳跃的,这次可能好,下次就可能坏,也就是还有机会被选中,没有完全抛弃。那么用它产生随机数就有可能得到一个较大的随机数,就在排序时被优先输出,这就是所说的探索作用(Exploration)

c、TS的不足

  • (1)返回的结果具有一定随机性,不是确定的事件

2、UCB算法的优缺

a、UCB算法的一些基本性质

  • (1)UCB是一种乐观的算法,选择置信区间上界排序(如果是悲观保守的做法,是选择置信区间下界排序)
  • (2)置信因子c一般是固定的,同一个粒度下一般是相同
  • (3)上界修正项,是根据霍夫丁不等式推导出来的

b、ucb 优点

  • (1)充分利用历史信息进行选择

c、ucb 缺点

  • (1)算法是确定性的,结果也是固定的,在模型更新前,推荐结果不会改变
  • (2)在先验知识利用方面,仅在置信区间上界利用,也就是部分使用了概率分布
  • (3)相对TS计算量大些

3、TS与UCB对比总结

  • a、UCB算法部分使用概率分布(仅置信区间上界)来量化不确定性,而TS基于贝叶斯思想,全部用概率分布来表达不确定性(避免马太效应)
  • b、UCB采用确定的选择策略,可能导致每次返回结果相同(不是推荐想要的),而TS则是随机化策略
  • c、TS实现相对更简单,UCB计算量更大(可能需要离线/异步计算),在计算机广告、文章推荐领域,效果与UCB不相上下
  • d、TS是逐步完善的模型,从采样的角度讲,TS的探索能力更好

三、参考资源

[1] 《 Bandit算法在携程推荐系统中的应用与实践》
[2] 《汤普森采样(Thompson sampling) 》
[3] 《多臂老虎机之Thompson Sampling》
[4] 《Bate分布公式推导》
[5] 《Beta分布,共轭先验与贝叶斯推断》
[6] 《Multi-armed bandit and Thompson Sampling in C++ and Python》

声明: 总结学习,有问题或不当之处,可以批评指正哦,谢谢。

你可能感兴趣的:(机器学习,概率论,人工智能)