【问题标题】:How to generate random numbers biased towards one value in a range?如何生成偏向某个范围内的一个值的随机数?
【发布时间】:2015-06-02 05:17:40
【问题描述】:

说,如果我想在minmax 之间生成一个无偏随机数,我会这样做:

var rand = function(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

但是,如果我想在minmax 之间生成一个随机数,但更偏向minmax 之间的值N 到一定程度D 怎么办?最好用概率曲线来说明:

【问题讨论】:

标签: javascript algorithm math probability


【解决方案1】:

这是一种方法:

  • 获取最小-最大范围内的随机数
  • 获取随机归一化混合值
  • 在随机混合的基础上混合随机和偏差

即,伪:

变量: 最小值 = 0 最大值 = 100 偏差 = 67 (N) 影响 = 1 (D) [0.0, 1.0] 公式: rnd = random() x (max - min) + min 混合 = 随机() x 影响 = rnd x (1 - mix) + 偏差 x 混合

混合因子可以通过一个次要因子来降低,以设置它应该影响多少(即mix * factor,其中因子为 [0, 1])。

演示

这将绘制一个有偏差的随机范围。上带的影响为 1,下带的影响为 0.75。偏置在这里设置为范围内的 2/3 位置。 底部带没有(故意的)偏差进行比较。

var ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "red"; ctx.fillRect(399,0,2,110);  // draw bias target
ctx.fillStyle = "rgba(0,0,0,0.07)";

function getRndBias(min, max, bias, influence) {
    var rnd = Math.random() * (max - min) + min,   // random in range
        mix = Math.random() * influence;           // random mixer
    return rnd * (1 - mix) + bias * mix;           // mix full range and bias
}

// plot biased result
(function loop() {
  for(var i = 0; i < 5; i++) {  // just sub-frames (speedier plot)
    ctx.fillRect( getRndBias(0, 600, 400, 1.00),  4, 2, 50);
    ctx.fillRect( getRndBias(0, 600, 400, 0.75), 55, 2, 50);
    ctx.fillRect( Math.random() * 600          ,115, 2, 35);
  }
  requestAnimationFrame(loop);
})();
&lt;canvas width=600&gt;&lt;/canvas&gt;

【讨论】:

  • 非常好。感谢演示。
  • @c00000fd 没问题!我忘了提到,通过高于 1 并限制混合中的结果,偏差会产生更大的影响。但你可能已经看到了。祝你的项目好运!
  • 如果我想要值为 1 或 0,但我希望结果是 67% 1s,会发生什么?
  • 生成一个1到100之间的随机数,如果大于等于67则取0,否则取1
【解决方案2】:

乐趣:使用图像作为密度函数。对随机像素进行采样,直到得到黑色像素,然后取 x 坐标。

代码:

getPixels = require("get-pixels"); // npm install get-pixels

getPixels("distribution.png", function(err, pixels) {
  var height, r, s, width, x, y;
  if (err) {
    return;
  }
  width = pixels.shape[0];
  height = pixels.shape[1];
  while (pixels.get(x, y, 0) !== 0) {
    r = Math.random();
    s = Math.random();
    x = Math.floor(r * width);
    y = Math.floor(s * height);
  }
  return console.log(r);
});

示例输出:

0.7892316638026386
0.8595335511490703
0.5459279934875667
0.9044852438382804
0.35129814594984055
0.5352215224411339
0.8271261665504426
0.4871773284394294
0.8202084102667868
0.39301465335302055

按口味调整。

【讨论】:

  • 这是愚蠢而精彩的,我真的笑出声来。也是本页最准确的!
  • ikr @MooingDuck
  • 女士们先生们,才华横溢与疯狂之间的微妙而模糊的界限。
【解决方案3】:

只是为了好玩,这是一个依赖于 Gaussian function 的版本,正如 SpiderPig 对您的问题的评论中提到的那样。高斯函数应用于 1 到 100 之间的随机数,其中钟的高度表示最终值与N 的接近程度。我将D 的度数解释为最终值接近N 的可能性,因此D 对应于钟的宽度——D 越小,偏差的可能性就越小。显然,该示例可以进一步校准。

(我复制了 Ken Fyrstenberg 的 canvas 方法来演示该功能。)

function randBias(min, max, N, D) {
  var a = 1,
      b = 50,
      c = D;

  var influence = Math.floor(Math.random() * (101)),
    x = Math.floor(Math.random() * (max - min + 1)) + min;

  return x > N 
         ? x + Math.floor(gauss(influence) * (N - x)) 
         : x - Math.floor(gauss(influence) * (x - N));

  function gauss(x) {
    return a * Math.exp(-(x - b) * (x - b) / (2 * c * c));
  }
}

var ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(399, 0, 2, 110);
ctx.fillStyle = "rgba(0,0,0,0.07)";

(function loop() {
  for (var i = 0; i < 5; i++) {
    ctx.fillRect(randBias(0, 600, 400, 50), 4, 2, 50);
    ctx.fillRect(randBias(0, 600, 400, 10), 55, 2, 50);
    ctx.fillRect(Math.random() * 600, 115, 2, 35);
  }
  requestAnimationFrame(loop);
})();
&lt;canvas width=600&gt;&lt;/canvas&gt;

【讨论】:

  • 谢谢。如果您像 Ken Fyrstenberg 在他的帖子中所做的那样添加一个实时样本,那将真的很有帮助。了解 PRNG 的有效性或偏见确实很有帮助。
  • @c00000fd 添加了!考虑“钟”的形状和位置以及其他参数,可以帮助改进结果。
【解决方案4】:

假设当您使用Math.floor(Math.random() * (max - min + 1)) + min; 时,您实际上是在创建一个统一分布。要获得图表中的数据分布,您需要的是具有非零偏度的分布。

有不同的技术来获得这些分布。这是在 stackoverflow 上找到的 example 的 beta 分发版。


以下是链接中总结的示例:

unif = Math.random()  // The original uniform distribution.

我们可以通过这样做将其转移到 beta 发行版中

beta = sin(unif*pi/2)^2 // The standard beta distribution

要获得图表中显示的偏度,

beta_right = (beta > 0.5) ? 2*beta-1 : 2*(1-beta)-1;

您可以将值 1 更改为任何其他值,以使其偏斜为其他值。

【讨论】:

  • 感谢您的解释。虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
猜你喜欢
  • 2021-03-02
  • 1970-01-01
  • 2020-10-23
  • 2021-05-04
  • 2022-01-22
  • 2018-04-08
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
相关资源
最近更新 更多