题 如何生成偏向某个范围内一个值的随机数?


比如说,如果我想生成一个无偏的随机数 min 和 max, 我会做:

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

但是如果我想在它们之间生成一个随机数怎么办? min 和 max 但更偏向于价值 N 之间 min 和 max 到一个程度 D?最好用概率曲线来说明它:

enter image description here


20
2018-03-29 02:43


起源


en.wikipedia.org/wiki/Gaussian_function - SpiderPig
可能重复 在Javascript中生成特定范围内的随机数? - Ryan
@ryan不是重复的,因为它是随机的,没有偏见。 OP要求有偏见的结果。 - epistemex
你不需要另一个参数;控制“传播”的东西? - Salman A
@SalmanA:我知道可以让它更复杂,因此我认为它不需要更多的参数。 - c00000fd


答案:


这是一种方式:

  • 获取最小 - 最大范围内的随机数
  • 获取随机标准化混合值
  • 基于随机混合随机混合偏差

即,伪:

变量:
  min = 0
  最大= 100
  偏差= 67(N)
  影响= 1(D)[0.0,1.0]

式:
  rnd = random()x(max  -  min)+ min
  mix = random()x影响力
    = rnd x(1  -  mix)+ bias x mix

混合因子可以通过次要因子来减少,以设定应该影响的程度(即。 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);
})();
<canvas width=600></canvas>


29
2018-03-29 03:10



非常好。感谢您的演示。 - c00000fd
@ c00000fd没问题!我忘了提到偏差可以通过超过1并在混合中压低结果来影响更大。但你可能已经看到了这一点。祝你的项目好运! - epistemex
如果我想要值为1或0会发生什么,但我希望结果为67%1? - codenamezero


只是为了好玩,这里有一个依赖于它的版本 高斯函数,如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);
})();
<canvas width=600></canvas>


3
2018-03-29 17:50



谢谢。如果你添加像Ken Fyrstenberg这样的实时样本,那将会非常有帮助。看到PRNG的有效性或偏见真的很有帮助。 - c00000fd
@ c00000fd补充说!考虑“钟”的形状和位置以及其他参数可以帮助改进结果。 - גלעד ברקן


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

有不同的技术来获得这些类型的分布。这是一个  在stackoverflow上找到的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更改为任何其他值,以使其偏向其他值。


2
2018-03-29 03:27



感谢您的解释。虽然此链接可能会回答这个问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面发生更改,则仅链接答案可能会变为无效。 - Lea Cohen
谢谢你的提醒Lea。 - LumiG


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

enter image description here

码:

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

适应口味。


1
2018-03-30 16:32