目录
问题描述
有K个摇臂赌博机,赌徒在投入一个硬币后,从K个摇臂机中随机选择一个按下,每个摇臂机以某概率吐出一定数量的硬币,这个概率赌徒并不知道,赌徒通过多次尝试,获得最大的利益。
贪心算法
1.每次尝试以概率eplison进行探索,即以均匀概率选取一个摇臂机,以1-eplison选取平均奖励最高的摇臂机。
2.再以奖励策略reward输出摇臂机的奖励,用了两个摇臂机,
(1)prob={1:0.4,2:0.2},第一个摇臂机摇出硬币的概率为0.4,摇不出硬币的概率为0.6,第二个摇臂机摇出硬币的概率为0.2,摇不出硬币的概率为0.8
(2)R={1:1,2:1},第一个摇臂机摇出硬币奖励为1,第二个摇出硬币奖励为1
选择出一个摇臂机后,如果选取了第一个摇臂机,取一个随机数random,如果该随机数小于0.4,那么获得奖励,返回奖励R[k]
,否则奖励为0,返回0
3.更新获得的总奖励 r,r+=v,y.append(r/T)记录每次总平均奖励,用以后面画图
4.更新每个摇臂机的平均奖励
count[k]为上一次摇臂机K的选中次数,count[k]+1为摇臂机K的本次选中次数,v为本次奖励
5.更新摇臂机K的选中次数,次数加1,count[k]=count[k]+1
Softmax算法
与贪心算法不同的是:当摇臂机的平均奖赏相差不大时,那选择摇臂机的概率相差不大,如果平均奖赏相差大,那么平均奖赏概率大的摇臂机被选中的概率也大,softmax算法的摇臂机概率分布基于Bolzmann分布。
每个摇臂机的选中概率公式为,除此之外,两个算法无甚差别。
# -*- coding: UTF-8 -*-
from numpy import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
e=2.17
#奖励函数
def reward(k,prob,R):
if random.random()<prob[k]:
return R[k]
else: return 0
#贪心算法
def greedyAlgorithm(Knum,R,prob,T,eplison,count,Q):
r=0
y=[]
for i in range(T):
randValue=random.random()
if randValue<eplison:
k=random.choice(Knum)
else:
k=max(Q,key=Q.get)
#选择的摇臂机以概率prob[k]获得奖励
v=reward(k,prob,R)
r+=v
y.append((r-v)/T)
#摇臂k的平均奖赏
#Q[k]+=(v-Q[k])/(count[k]+1)等同于下式
Q[k]=(Q[k]*count[k]+v)/(count[k]+1)
count[k]=count[k]+1
if i>=100:#当尝试次数很大时,摇臂的奖赏可以很好近似出来,再无需探索,那么可以置eplison为1/根号下i
eplison=1.0/pow(i,.5)
print("the total reward is: ",r)
print("the average reward is: ",r/T)
print("the times of each machine are :",count)
print("the even reward of each machine is :",Q)
return y
def Softmax(T,Q,eplison,count,R,probOfReward):
r=0
y=[]
probK=dict(zip(list(range(1,3)),[0]*2))
for i in range(T):
probKTotal=0
chanceOfRandom=random.random()
sum=(pow(e,Q[1]/eplison)+pow(e,Q[2]/eplison))
for n in Q:
operated=0
t=pow(e,Q[n]/eplison)
probK[n]=t/sum
probKTotal+=probK[n]
if chanceOfRandom<probKTotal and operated==0:
kk=n
operated=1
v=reward(kk,probOfReward,R)
r+=v
y.append(r/T)
Q[kk]=(Q[kk]*count[kk]+v)/(count[kk]+1)
count[kk]=1+count[kk]
print("the total reward is: ",r)
print("the average reward is: ",r/T)
print("the times of each machine are :",count)
print("the even reward of each machine is :",Q)
return y
if __name__=="__main__":
#5个摇臂
Knum=[i+1 for i in range(2)]
#每个摇臂对应的奖赏
R={1:1,2:1}
#每个摇臂摇到奖赏的概率
prob={1:0.4,2:0.2}
#摇臂次数
T=3000
#探索概率
eplison=0.01
#每个摇臂奖赏为0
count=dict(zip(list(range(1,3)),[0]*2))
#每个摇臂机的平均奖励
Q=dict(zip(list(range(1,3)),[0]*2))
#zip对应下标打包成元组的形式,而dict为字典,对应的元组成一个字典的一个元素
print("greedy:")
GreedyEvenW=greedyAlgorithm(Knum,R,prob,T,eplison,count,Q)
x=range(1,T+1)
y1=GreedyEvenW
plt.plot(x,y1,color='red',label='$greedy$',linewidth=0.8)
plt.title('rate')
plt.xlabel('x/times')
plt.ylabel('y/even reward')
#Softmax
print("softmax:")
softmaxEven=Softmax(T,Q,eplison,count,R,prob)
y2=softmaxEven
plt.plot(x,y2,color='black',label='$Softmax$',linewidth=0.8)
plt.legend(('greedy','Softmax'))
plt.show()
结果如下:
如果要看变化率的话,需要求导,这只是5000次的平均奖励变化,多次调试后,贪心算法的平均奖励保持在0.4,而softmax的平均奖励保持在0.2,在最初会有激增。