思路:
将每个概率值对应到[0,1]区间内的各个子区间(概率值大小体现在子区间的长度上),每次采样时,按照均匀分布随机生成一个[0,1]区间内的值,其落到哪个区间,则该区间概率值对应的元素即为被采样的元素;
算法:
1、先对概率值从大到小排列(不是必要过程,是便于加速的技巧,这样每次查找时优先检测随机数是否落在大概率的区间内,减少比较次数);
2、生成一个[0,1)区间内的随机数x (注意,Rand().nextDouble()得到的是[0,1)区间内的数,而wikipedia给出的算法中要求生成的是(0,1)区间的数);
3、将x与概率值列表中的各值pi逐个比较,并累加已比较过的前i-1个概率值的累加和sum:
若x落在[sum, sum+pi)区间内,则pi对应的元素被采样并返回 (注意区间的开闭应该参考步骤2中的情况);
否则,将pi累加入sum,继续将x与p(i+1)比较;
Tips:
若程序退出时仍未采到合法样本,则可能给定的概率分布不满足∑pi=1的条件(且x刚好落在[1-sum, 1)区间内);
应用场景:
机器学习(如强化学习)中,利用softmax函数定义policy,根据多项分布选择对应的action(使得agent有较大概率选到当前模型下的最佳action,又有一定的几率去探索其他action
);
softmax policy的另一种替代方式是epsilon-learning中用epsilon来控制探索和利用的几率的方式,即以epsilon的概率进行探索(随机选一个action),以1-epsilon的概率进行利用(选当前模型下最佳action);
算法代码:
/**
* sample from amultinomial distribution
* https://en.wikipedia.org/wiki/Multinomial_distribution#Sampling_from_a_multinomial_distribution
*
@param
pdist a list of <item,probablity>
*
@return
the selected item, i.e. result belongs to pdist.getFirstValues
*
@author
qxliuOct 16, 2017 11:47:33 AM
*/
public
static
int
sampleFromMultinomialDistribution
(
List
<
TwoTuple
<
Integer
,
Double
>>
pdist
){
List
<
TwoTuple
<
Integer
,
Double
>>
pidxlist
=
new
ArrayList
<>