转载自:https://zhuanlan.zhihu.com/p/32356077
博主讲的非常好,
假设我们开了一家叫Surprise Me的饭馆
- 客人来了不用点餐,由算法从N道菜中选择一道菜推荐给客人
- 每道菜都有一定的失败概率:以1-p的概率不好吃,以p的概率做得好吃
- 算法的目标是让满意的客人越多越好。
解决方法:
def UCB(t, N):
upper_bound_probs = [avg_rewards[item] + calculate_delta(t, item) for item in range(N)]
item = np.argmax(upper_bound_probs)
reward = np.random.binomial(n=1, p=true_rewards[item])
return item, reward
for t in range(1, T): # T个客人依次进入餐馆
# 从N道菜中推荐一个,reward = 1 表示客人接受,reward = 0 表示客人拒绝并离开
item, reward = UCB(t, N)
total_reward += reward # 一共有多少客人接受了推荐
对上述内容我有个理解,UCB的思想是在经过k次观测之后得到的观测概率,它与真实概率有一个差值,我们想要找到这种差值,如何寻找,使用的是Chernoff-Hodeffding Bound的公式,
得到了一个不等式,根据这个不等式,我们可以通过让右边的最大,来使得左边的概率尽可能大,也就是估计概率尽可能的拟合真实概率,这就做到了探索和利用当前信息的一个平衡,
在任意的0-1取值的独立同分布下,它们的一个差值就可以使用这个根号表达式代替。
最后,我们附上完整的代码,跟第一讲不一样的地方已经重点加粗标注。
import numpy as np
T = 1000 # T个客人
N = 10 # N道菜
true_rewards = np.random.uniform(low=0, high=1, size=N) # 每道菜好吃的概率
estimated_rewards = np.zeros(N) # 每道菜好吃的估计概率
chosen_count = np.zeros(N) #各个菜被选中的次数
total_reward = 0
def calculate_delta(T, item):
if chosen_count[item] == 0:
return 1
else:
return np.sqrt(2 * np.log(T) / chosen_count[item])
def UCB(t, N):
upper_bound_probs = [estimated_rewards[item] + calculate_delta(t, item) for item in range(N)]
item = np.argmax(upper_bound_probs)
reward = np.random.binomial(n=1, p=true_rewards[item])
return item, reward
for t in range(1, T): # T个客人依次进入餐馆
# 从N道菜中推荐一个,reward = 1 表示客人接受,reward = 0 表示客人拒绝并离开
item, reward = UCB(t, N)
total_reward += reward # 一共有多少客人接受了推荐
# 更新菜的平均成功概率
estimated_rewards[item] = ((t - 1) * estimated_rewards[item] + reward) / t
chosen_count[item] += 1