ps://www.bilibili.com/video/BV1Ge4y1i7L6/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click&vd_source=f74787498485b746c394be401070ee69)
对于一个多臂老虎机问题,如果一根拉杆被拉动了一次,而其它的只拉动了一次,我们对已经多次拉动的拉杆已经非常熟悉了,就应该多尝试拉动次数较少的拉杆,因此我们一个不确定性度量u,他会随着一个动作被尝试次数的增加而减小。
引入u
import random
#随机选择的概率递减的贪婪算法
def choose_one():
#求出每个老虎机各玩了多少次
played_count = [len(i) for i in rewards]
played_count = np.array(played_count)
#求出上置信界
#分子是总共玩了多少次,取根号后让他的增长速度变慢
#分母是每台老虎机玩的次数,乘以2让他的增长速度变快
#随着玩的次数增加,分母会很快超过分子的增长速度,导致分数越来越小
#具体到每一台老虎机,则是玩的次数越多,分数就越小,也就是ucb的加权越小
#所以ucb衡量了每一台老虎机的不确定性,不确定性越大,探索的价值越大
fenzi = played_count.sum()**0.5
fenmu = played_count * 2
ucb = fenzi / fenmu
#ucb本身取根号
#大于1的数会被缩小,小于1的数会被放大,这样保持ucb恒定在一定的数值范围内
ucb = ucb**0.5
#计算每个老虎机的奖励平均
rewards_mean = [np.mean(i) for i in rewards]
rewards_mean = np.array(rewards_mean)
#ucb和期望求和
ucb += rewards_mean
return ucb.argmax()
choose_one()
完整代码
import numpy as np
import random
# 创建老虎机选择函数
def choose_one():
# 求出每个老虎机各玩了多少次
played_count = [len(i) for i in rewards]
played_count = np.array(played_count)
# 计算上置信界(UCB)
fenzi = played_count.sum() ** 0.5
fenmu = played_count * 2
ucb = fenzi / fenmu
ucb = ucb ** 0.5
# 计算每个老虎机的奖励平均
rewards_mean = [np.mean(i) for i in rewards]
rewards_mean = np.array(rewards_mean)
# UCB和期望求和
ucb += rewards_mean
return ucb.argmax()
# 玩老虎机的函数
def try_and_play():
i = choose_one()
# 玩老虎机,得到结果
reward = 0
if random.random() < probs[i]:
reward = 1
# 记录玩的结果
rewards[i].append(reward)
# 获取结果的函数
def get_result():
# 玩N次
for _ in range(5000):
try_and_play()
# 期望的最好结果
target = probs.max() * 5000
# 实际玩出的结果
result = sum([sum(i) for i in rewards])
return target, result
# 每个老虎机的中奖概率,0-1之间的均匀分布
probs = np.random.uniform(size=10)
# 记录每个老虎机的返回值
rewards = [[1] for _ in range(10)]
# 获取结果
target, result = get_result()
print("目标结果:", target)
print("实际结果:", result)