生成具有对数分布和自定义斜率的随机数

ser*_*erg 9 javascript algorithm math statistics distribution

我试图生成具有对数分布的随机整数.我使用以下公式:

idx = Math.floor(Math.log((Math.random() * Math.pow(2.0, max)) + 1.0) / Math.log(2.0));
Run Code Online (Sandbox Code Playgroud)

这样可以很好地生成1000次迭代这样的序列(每个数字表示生成索引的次数):

[525, 261, 119, 45, 29, 13, 5, 1, 1, 1]
Run Code Online (Sandbox Code Playgroud)

小提琴

我现在正在尝试调整此分布的斜率,因此它不会快速下降并产生类似于:

[150, 120, 100, 80, 60, ...]
Run Code Online (Sandbox Code Playgroud)

盲目地玩系数并没有给我我想要的东西.任何想法如何实现呢?

Dou*_*are 5

您提到了对数分布,但看起来您的代码是设计成生成截断的几何分布的,尽管它有缺陷。有一个以上的分布称为对数分布,但没有一个是常见的。请说明您是否确实是其中之一。

您计算floor [log_2 U],其中U从1到(2 ^ max)+1均匀分布。这有1/2 ^ max的机会产生最大值,但是您将其限制为max-1。因此,您有1/2的最大几率产生0,2 / 2 ^的最大几率产生1,4 / 2 ^的最大几率产生2,...最大为1/2 + 1/2 ^的最大几率有机会产生max-1。

您的代码中存在但问题描述中所缺少的是,您正在用

idx = (max-idx) - 1
Run Code Online (Sandbox Code Playgroud)

此后,产生0的机会是1/2 + 1/2 ^ max,产生k的机会是1/2 ^(k + 1)。

我认为让U在[1,2 ^ max + 1]上保持一致是一个错误。相反,我认为您希望U在[1,2 ^ max]上保持一致。那么您生成idx = k的机会是2 ^(max-k-1)/((2 ^ max)-1)。

idx = Math.floor(Math.log((Math.random()*(Math.pow(2.0, max)-1.0)) + 1.0) / Math.log(2.0));
Run Code Online (Sandbox Code Playgroud)

zmii的评论是,通过将两个2.0替换为一个更接近1.0的值可以使分布更平坦。对于较小的max值,其结果不令人满意的原因是,您从[1,1.3 ^ max + 1]而不是[1,1.3 ^ max]进行均匀采样。当max较小且底数较小时,额外+1的差异较大。请尝试以下操作:

var zmii = 1.3;
idx = Math.floor(Math.log((Math.random()*(Math.pow(zmii, max)-1.0))+1.0) / Math.log(zmii));
Run Code Online (Sandbox Code Playgroud)