Bandit算法原理及Python实战

目录

1)什么是Bandit算法

为选择而生。

Bandit算法与推荐系统

怎么选择Bandit算法?

2)常用Bandit算法

Thompson sampling算法

UCB算法

Epsilon-Greedy算法

Greedy算法

3)Bandit算法Python实战

参考资料:


推荐系统里面有两个经典问题:EE和冷启动。Bandit算法是一种简单的在线学习算法,常常用于尝试解决这两个问题,本文为你介绍基础的Bandit算法原理及Python实战。

1)什么是Bandit算法

为选择而生

我们会遇到很多选择的场景。上哪个大学,学什么专业,去哪家公司,中午吃什么等等。这些事情,都让选择困难症的我们头很大。那么,有算法能够很好地对付这些问题吗?

当然有!那就是Bandit算法。

Bandit算法来源于历史悠久的赌博学,它要解决的问题是这样的:

一个赌徒,要去摇老虎机,走进赌场一看,一排老虎机,外表一模一样,但是每个老虎机吐钱的概率可不一样,他不知道每个老虎机吐钱的概率分布是什么,那么每次该选择哪个老虎机可以做到最大化收益呢?这就是多臂赌博机问题(Multi-armed bandit problem, K-armed bandit problem, MAB)。如下图所示:

图片描述

怎么解决这个问题呢?最好的办法是去试一试,不是盲目地试,而是有策略地快速试一试,这些策略就是Bandit算法。

这个多臂问题,推荐系统里很多问题都与它类似:

  1. 假设一个用户对不同类别的内容感兴趣程度不同,那么我们的推荐系统初次见到这个用户时,怎么快速地知道他对每类内容的感兴趣程度?这就是推荐系统的冷启动。
  2. 假设我们有若干广告库存,怎么知道该给每个用户展示哪个广告,从而获得最大的点击收益?是每次都挑效果最好那个么?那么新广告如何才有出头之日?
  3. 我们的算法工程师又想出了新的模型,有没有比A/B test更快的方法知道它和旧模型相比谁更靠谱?
  4. 如果只是推荐已知的用户感兴趣的物品,如何才能科学地冒险给他推荐一些新鲜的物品?

Bandit算法与推荐系统

在推荐系统领域里,有两个比较经典的问题常被人提起,一个是EE问题,另一个是用户冷启动问题。

什么是EE问题?又叫exploit-explore问题。exploit就是:对用户比较确定的兴趣,当然要利用开采迎合,好比说已经挣到的钱,当然要花;explore就是:光对着用户已知的兴趣使用,用户很快会腻,所以要不断探索用户新的兴趣才行,这就好比虽然有一点钱可以花了,但是还得继续搬砖挣钱,不然花完了就得喝西北风。

用户冷启动问题,也就是面对新用户时,如何能够通过若干次实验,猜出用户的大致兴趣。

我想,屏幕前的你已经想到了,推荐系统冷启动可以用Bandit算法来解决一部分。

这两个问题本质上都是如何选择用户感兴趣的主题进行推荐,比较符合Bandit算法背后的MAB问题。

比如,用Bandit算法解决冷启动的大致思路如下:用分类或者Topic来表示每个用户兴趣,也就是MAB问题中的臂(Arm),我们可以通过几次试验,来刻画出新用户心目中对每个Topic的感兴趣概率。这里,如果用户对某个Topic感兴趣(提供了显式反馈或隐式反馈),就表示我们得到了收益,如果推给了它不感兴趣的Topic,推荐系统就表示很遗憾(regret)了。如此经历“选择-观察-更新-选择”的循环,理论上是越来越逼近用户真正感兴趣的Topic的,



怎么选择Bandit算法?

现在来介绍一下Bandit算法怎么解决这类问题的。Bandit算法需要量化一个核心问题:错误的选择到底有多大的遗憾?能不能遗憾少一些?

王家卫在《一代宗师》里寄出一句台词:

人生要是无憾,那多无趣?

而我说:算法要是无憾,那应该是过拟合了。

所以说:怎么衡量不同Bandit算法在解决多臂问题上的效果?首先介绍一个概念,叫做累积遗憾(regret):

图片描述

图2 积累遗憾

这个公式就是计算Bandit算法的累积遗憾,解释一下:

首先,这里我们讨论的每个臂的收益非0即1,也就是伯努利收益。

然后,每次选择后,计算和最佳的选择差了多少,然后把差距累加起来就是总的遗憾。

wB(i)是第i次试验时被选中臂的期望收益, w*是所有臂中的最佳那个,如果上帝提前告诉你,我们当然每次试验都选它,问题是上帝不告诉你,所以就有了Bandit算法,我们就有了这篇文章。

这个公式可以用来对比不同Bandit算法的效果:对同样的多臂问题,用不同的Bandit算法试验相同次数,看看谁的regret增长得慢。

那么到底不同的Bandit算法有哪些呢?

2)常用Bandit算法

Thompson sampling算法

Thompson sampling算法简单实用,因为它只有一行代码就可以实现[3]。简单介绍一下它的原理,要点如下:

  1. 假设每个臂是否产生收益,其背后有一个概率分布,产生收益的概率为p。
  2. 我们不断地试验,去估计出一个置信度较高的“概率p的概率分布”就能近似解决这个问题了。
  3. 怎么能估计“概率p的概率分布”呢? 答案是假设概率p的概率分布符合beta(wins, lose)分布,它有两个参数: wins, lose。
  4. 每个臂都维护一个beta分布的参数。每次试验后,选中一个臂,摇一下,有收益则该臂的wins增加1,否则该臂的lose增加1。
  5. 每次选择臂的方式是:用每个臂现有的beta分布产生一个随机数b,选择所有臂产生的随机数中最大的那个臂去摇。

UCB算法

UCB算法全称是Upper Confidence Bound(置信区间上界),它的算法步骤如下[4]:

  • 初始化:先对每一个臂都试一遍;
  • 按照如下公式计算每个臂的分数,然后选择分数最大的臂作为选择:

图片描述

图3 UCB算法

  • 观察选择结果,更新t和Tjt。其中加号前面是这个臂到目前的收益均值,后面的叫做bonus,本质上是均值的标准差,t是目前的试验次数,Tjt是这个臂被试次数。

这个公式反映一个特点:均值越大,标准差越小,被选中的概率会越来越大,同时哪些被选次数较少的臂也会得到试验机会。

Epsilon-Greedy算法

这是一个朴素的Bandit算法,有点类似模拟退火的思想:

  1. 选一个(0,1)之间较小的数作为epsilon;
  2. 每次以概率epsilon做一件事:所有臂中随机选一个;
  3. 每次以概率1-epsilon 选择截止到当前,平均收益最大的那个臂。

是不是简单粗暴?epsilon的值可以控制对Exploit和Explore的偏好程度。越接近0,越保守,只想花钱不想挣钱。

Greedy算法

先随机试若干次,计算每个臂的平均收益,一直选均值最大那个臂。这个算法是人类在实际中最常采用的,不可否认,它还是比随机乱猜要好。

3)Bandit算法Python实战

下面是我们模拟10000次的实验各种算法对比,可以看出Thompson算法效果是最好的。

import numpy as np
import matplotlib.pyplot as plt
import math#老虎机个数
number_of_bandits=10
#每个老虎机的臂数
number_of_arms=10
#尝试数
number_of_pulls=10000
#eps
epsilon=0.3
#最小的decay
min_temp = 0.1
#衰减率
decay_rate=0.999def pick_arm(q_values,counts,strategy,success,failure):global epsilon#随机返回一个臂if strategy=="random":return np.random.randint(0,len(q_values))#贪心算法,每次都选取收益最大的那个臂if strategy=="greedy":best_arms_value = np.max(q_values)#返回收益最大的臂的位置best_arms = np.argwhere(q_values==best_arms_value).flatten()#返回自身最大臂# 等价于return best_arms[0]return best_arms[np.random.randint(0,len(best_arms))]#加epsilon,egreedy中,epsilon不变,egreedy_decay,epsilon变化if strategy=="egreedy" or strategy=="egreedy_decay": if  strategy=="egreedy_decay": epsilon=max(epsilon*decay_rate,min_temp)if np.random.random() > epsilon:best_arms_value = np.max(q_values)best_arms = np.argwhere(q_values==best_arms_value).flatten()return best_arms[np.random.randint(0,len(best_arms))]else:#以epsilon的概率随机选取一个臂return np.random.randint(0,len(q_values))#ucb,按照ucb公式,算每个臂的收益,取最大的收益的臂/1000次除以10=1000if strategy=="ucb":total_counts = np.sum(counts)q_values_ucb = q_values + np.sqrt(np.reciprocal(counts+0.001)*2*math.log(total_counts+1.0))best_arms_value = np.max(q_values_ucb)best_arms = np.argwhere(q_values_ucb==best_arms_value).flatten()return best_arms[np.random.randint(0,len(best_arms))]#thompson,利用beta分布选择臂if strategy=="thompson":sample_means = np.zeros(len(counts))for i in range(len(counts)):sample_means[i]=np.random.beta(success[i]+1,failure[i]+1)return np.argmax(sample_means)fig = plt.figure()
ax = fig.add_subplot(111)
for st in ["greedy","random","egreedy","egreedy_decay","ucb","thompson"]:#定义 bandits个数*拉的次数的数组(10,10000)best_arm_counts = np.zeros((number_of_bandits,number_of_pulls))#对于每个老虎机来说(0,10)for i in range(number_of_bandits):#随机一个老虎机10个臂的收益w,保存最大收益arm_means = np.random.rand(number_of_arms)best_arm = np.argmax(arm_means)#初始化臂的收益(10)为零q_values = np.zeros(number_of_arms)#初始化臂的拉动次数(10次)counts = np.zeros(number_of_arms)#初始化臂的成功次数success=np.zeros(number_of_arms)#初始化臂的失败次数failure=np.zeros(number_of_arms)#对于每次拉动for j in range(number_of_pulls):#根据不同的策略,选择臂aa = pick_arm(q_values,counts,st,success,failure)#当前臂a的收益,二项分布,收益为1或0reward = np.random.binomial(1,arm_means[a])#臂的次数+1counts[a]+=1.0#更新当前臂的收益(平均收益)q_values[a]+= (reward-q_values[a])/counts[a]#记录成功的收益success[a]+=reward#记录失败的收益failure[a]+=(1-reward)#更新best_arm_counts[i][j]best_arm_counts[i][j] = counts[best_arm]*100.0/(j+1)epsilon=0.3#横纵坐标ys = np.mean(best_arm_counts,axis=0)xs = range(len(ys))ax.plot(xs, ys,label = st)plt.xlabel('Steps')
plt.ylabel('Optimal pulls')plt.tight_layout()
plt.legend()
plt.ylim((0,110))
plt.show() 

参考资料:

[1] https://blog.csdn.net/heyc861221/article/details/80129310

[2] https://en.wikipedia.org/wiki/Thompson_sampling

[3] http://nbviewer.jupyter.org/github/CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/blob/master/Chapter6_Priorities/Chapter6.ipynb#

[4] https://blog.csdn.net/a358463121/article/details/52562940

[5] https://blog.csdn.net/z1185196212/article/details/53374194

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439626.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

*【 POJ - 1007 】DNA Sorting(枚举,类似三元组找第二元问题)

题干: One measure of unsortedness in a sequence is the number of pairs of entries that are out of order with respect to each other. For instance, in the letter sequence DAABEC, this measure is 5, since D is greater than four letters to its righ…

ava容器类4:Queue深入解读

Collection的其它两大分支:List和Set在前面已近分析过,这篇来分析一下Queue的底层实现。 前三篇关于Java容器类的文章: java容器类1:Collection,List,ArrayList,LinkedList深入解读 java容器类2:Map及HashMap深入解…

Waymo离线点云序列3D物体检测网络 (3D Auto Labeling): Offboard 3D Object Detection from Point Cloud Sequences

本文介绍一篇Waymo基于点云序列的3D物体检测网络:3D Auto Labeling,论文已收录于CVPR 2021。 这里重点是理解本文提出的 Object-centric Auto Labeling。 论文链接为:https://arxiv.org/abs/2103.05073 2021-09-02补充:本文作者…

【OpenJ_Bailian - 2711 】 合唱队形(dp,枚举中间顶点)

题干: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK&…

Waymo自动驾驶数据集介绍与使用教程

本文将对Waymo自动驾驶数据集(Waymo Open Dataset)进行介绍。 论文链接为:https://arxiv.org/abs/1912.04838v7 项目链接为:https://github.com/waymo-research/waymo-open-dataset 数据集链接为:https://waymo.com…

Java 并发基础——线程安全性

线程安全:多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么久称这个类是线程安全的。 在线程安全类中封…

详解一阶段3D物体检测网络 SE-SSD: Self-Ensembling Single-Stage Object Detector From Point Cloud

本文介绍一篇一阶段的3D物体检测网络:SE-SSD,论文已收录于 CVPR 2021。 这里重点是理解本文提出的 Consistency Loss 、Orientation-Aware Distance-IoU Loss、Shape-Aware Data Augmentation。 论文链接为:https://arxiv.org/pdf/2104.0980…

【POJ - 3744】Scout YYF I(概率dp,矩阵快速幂优化dp)

题干&#xff1a; 题目大意&#xff1a; 在一条不满地雷的路上&#xff08;无限长&#xff09;&#xff0c;你现在的起点在1处。在N个点处布有地雷&#xff0c;1<N<10。地雷点的可能坐标范围&#xff1a;[1,100000000]. 每次前进p的概率前进一步&#xff0c;1-p的概率…

详解3D点云分割网络 Cylindrical and Asymmetrical 3D Convolution Networksfor LiDAR Segmentation

本文介绍一篇3D点云分割网络&#xff1a;Cylinder3D&#xff0c;论文已收录于 CVPR 2021。 这里重点是理解本文提出的 Cylindrical Partition 和 Asymmetrical 3D Convolution Network。 论文链接为&#xff1a;https://arxiv.org/pdf/2011.10033.pdf 项目链接为&#xff1a;…

Java中泛型Class《T》、T与Class《?》

一.区别 单独的T 代表一个类型 &#xff0c;而 Class<T>代表这个类型所对应的类&#xff0c; Class<&#xff1f;>表示类型不确定的类 E - Element (在集合中使用&#xff0c;因为集合中存放的是元素)T - Type&#xff08;Java 类&#xff09;K - Key&#xff08;…

【CodeForces - 701D】As Fast As Possible(二分,模拟,数学公式)

题干&#xff1a; On vacations n pupils decided to go on excursion and gather all together. They need to overcome the path with the length l meters. Each of the pupils will go with the speed equal to v1. To get to the excursion quickly, it was decided to r…

自动驾驶3D物体检测研究综述 3D Object Detection for Autonomous Driving: A Survey

本文介绍一篇最新的自动驾驶3D物体检测研究综述&#xff08;2021年6月份发布&#xff09;&#xff0c;来源于中国人民大学&#xff0c;论文共26页&#xff0c;99篇参考文献。 论文链接为&#xff1a;https://arxiv.org/pdf/2106.10823.pdf 0. Abstract 自动驾驶被看作是避免人…

【CodeForces - 705C】Thor(模拟,STLset优化链表)

题干&#xff1a; Thor is getting used to the Earth. As a gift Loki gave him a smartphone. There are n applications on this phone. Thor is fascinated by this phone. He has only one minor issue: he cant count the number of unread notifications generated by …

Java中接口的多继承

我们知道Java的类只能继承一个类&#xff0c;但可以实现多个接口。但是你知道么&#xff1f;Java中的接口却可以继承多个接口。本文就来说一说Java中接口的多继承。 进入主题之前&#xff0c;先扩展一下。Java为什么只支持单继承呢&#xff1f; 我们不妨假设Java支持多继承&a…

详解基于IMU/GPS的行人定位: IMU/GPS Based Pedestrian Localization

本文介绍一篇使用 IMU/GPS 数据融合的行人定位论文&#xff0c;这里重点是理解本文提出的 Stop Detection 和 GPS Correction。 论文地址为&#xff1a;https://www.researchgate.net/publication/261452498_IMUGPS_based_pedestrian_localization 1. Introduction 低成本的 …

每次maven刷新jdk都要重新设置

pom.xml <java.version>17</java.version> 改为<java.version>1.8</java.version>

【CodeForces - 706D】Vasiliy's Multiset(01字典树)

题干&#xff1a; Author has gone out of the stories about Vasiliy, so here is just a formal task description. You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries: " x" — add integer …

LaTeX常用数学符号总结

本文汇总了在使用LaTeX中常用的数学符号&#xff0c;相关下载资源为&#xff1a;139分钟学会Latex&#xff08;免积分下载&#xff09;。 文章目录1. 希腊字母2. 集合运算符3. 数学运算符4. 三角符号、指数符号、对数符号5. 积分、微分、偏微分6. 矩阵和行列式7. 基本函数、分段…

基本类型优先于装箱基本类型

基本类型与包装类型的主要区别在于以下三个方面&#xff1a; 1、基本类型只有值&#xff0c;而包装类型则具有与它们的值不同的同一性&#xff08;identity&#xff09;。这个同一性是指&#xff0c;两个引用是否指向同一个对象&#xff0c;如果指向同一个对象&#xff0c;则说…

【CodeForces - 827A】String Reconstruction(并查集合并区间,思维)

题干&#xff1a; Ivan had string s consisting of small English letters. However, his friend Julia decided to make fun of him and hid the string s. Ivan preferred making a new string to finding the old one. Ivan knows some information about the string s. …