如何生成一个范围内偏向一个值的随机数?
How to generate random numbers biased towards one value in a range?
比如说,如果我想生成一个介于 min
和 max
之间的无偏随机数,我会这样做:
var rand = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
但是如果我想生成一个介于 min
和 max
之间但更偏向 N
介于 min
和 max
之间的随机数怎么办在某种程度上 D
?最好用概率曲线来说明:
这是一种方法:
- 获取最小-最大范围内的随机数
- 获取随机归一化混合值
- 在随机混合的基础上混合随机和偏差
即伪:
Variables:
min = 0
max = 100
bias = 67 (N)
influence = 1 (D) [0.0, 1.0]
Formula:
rnd = random() x (max - min) + min
mix = random() x influence
value = 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>
说当您使用 Math.floor(Math.random() * (max - min + 1)) + min;
时,您实际上是在创建一个均匀分布。要获得图表中的数据分布,您需要的是具有非零偏度的分布。
获得这些分布的技术有多种。这是在 Whosebug 上找到的 example beta 发行版。
这里是从 link:
中总结的例子
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 更改为任何其他值以使其倾斜到其他值。
只是为了好玩,这里有一个依赖于 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);
})();
<canvas width=600></canvas>
趣味:用图像作为密度函数。对随机像素进行采样,直到得到黑色像素,然后取 x co-ordinate.
代码:
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
根据口味调整。
比如说,如果我想生成一个介于 min
和 max
之间的无偏随机数,我会这样做:
var rand = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
但是如果我想生成一个介于 min
和 max
之间但更偏向 N
介于 min
和 max
之间的随机数怎么办在某种程度上 D
?最好用概率曲线来说明:
这是一种方法:
- 获取最小-最大范围内的随机数
- 获取随机归一化混合值
- 在随机混合的基础上混合随机和偏差
即伪:
Variables: min = 0 max = 100 bias = 67 (N) influence = 1 (D) [0.0, 1.0] Formula: rnd = random() x (max - min) + min mix = random() x influence value = 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>
说当您使用 Math.floor(Math.random() * (max - min + 1)) + min;
时,您实际上是在创建一个均匀分布。要获得图表中的数据分布,您需要的是具有非零偏度的分布。
获得这些分布的技术有多种。这是在 Whosebug 上找到的 example beta 发行版。
这里是从 link:
中总结的例子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 更改为任何其他值以使其倾斜到其他值。
只是为了好玩,这里有一个依赖于 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);
})();
<canvas width=600></canvas>
趣味:用图像作为密度函数。对随机像素进行采样,直到得到黑色像素,然后取 x co-ordinate.
代码:
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
根据口味调整。