[英]Can I achieve weighted randomness with a function that returns weighted booleans?
我有一种模仿不公平硬币的方法。 您可以传入一个百分比,它会通过返回 boolean 来告诉您是否成功。 所以如果你用.25 调用它,它会在 25% 的时间内返回true
。
我试图弄清楚我是否可以使用这个 function 来创建一个加权随机性 function,它的工作原理如下: There is a 25% chance it returns x, a 40% chance it returns y, and a 35% chance it returns z.
这只是一个例子。 我希望 function 可以处理无限数量的字母,但加在一起的百分比应该等于 1。
诀窍是,我希望能够按照我刚才描述的方式来思考它。 换句话说:
result = function ({.25, x}, {.4, y}, {.35, z})
result
应该是 x 25% 的时间,依此类推。 我可以用我的不公平币实现这个 function 吗?
这是我在下面的评论中的措辞。它可能会澄清我的要求:
如果我在这里犯了错误,请纠正我的逻辑,但是假设 XY 和 Z 都有。3333...我不能用我的不公平硬币来传递。3333...如果返回 true,那就意味着你得到了结果是 X。 如果返回 false,再次调用我的不公平。5 如果返回 true,则返回 Y,否则返回 Z。如果正确,如果数字 AREN'T.3333 并且如果有,我不知道如何使它工作三个以上
假设你有一个 function unfairCoin(p)
,这是一个 function 以已知概率p
产生正面,否则产生反面。 例如,它可以这样实现:
function unfairCoin(p) {
return Math.random() < p ? True : false;
}
假设所有涉及的概率总和为 1,这是一个算法,可以解决您的问题给定unfairCoin
:
cumu
设置为 1。p
)并以概率p / cumu
接受项目(例如,通过unfairCoin(p / cumu)
)。 如果该项目被接受,则退回该项目。cumu
中减去p
。该算法的预期时间复杂度取决于概率的顺序。 一般来说,该算法的时间复杂度是线性的,但如果将概率按降序排序,则预期时间复杂度是恒定的。
编辑(7 月 30 日):正如我刚刚发现的那样,Keith Schwarz 在Darts, Dice, and Coins中已经描述了这个精确的算法,在“用有偏差的硬币模拟加载的模具”中。 该页面还包含其正确性的证明。
另一种解决方案使用拒绝抽样,但需要使用公平的硬币投掷生成随机 integer:
n
为项目数。 例如,可以使用 J. Lumbroso 的Fast Dice Roller来做到这一点,它只使用公平的硬币投掷 ( unfairCoin(0.5)
); 请参阅下面的代码。 选择给定索引处的项目(从 0 开始)。p
)并以概率p
接受它(例如,通过unfairCoin(p)
)。 如果该项目被接受,则退回该项目; 否则,go 执行步骤 1。该算法的预期时间复杂度取决于最低概率和最高概率之间的差异。
给定每个项目的权重,除了前面给出的算法之外,还有许多其他方法可以做出加权选择; 请参阅我关于加权选择算法的说明。
以下是实现快速骰子滚轮的 JavaScript 代码。 请注意,它使用拒绝事件和循环来确保它是公正的。
function randomInt(minInclusive, maxExclusive) {
var maxInclusive = (maxExclusive - minInclusive) - 1
var x = 1
var y = 0
while(true) {
x = x * 2
var randomBit = (Math.random() < 0.5 ? 0 : 1)
y = y * 2 + randomBit
if(x > maxInclusive) {
if (y <= maxInclusive) { return y + minInclusive }
// Rejection
x = x - maxInclusive - 1
y = y - maxInclusive - 1
}
}
}
另一方面,如果你有一个 function COIN
以未知的概率输出正面而反之,那么有两个问题需要解决才能获得解决方案:
换句话说,任务是将有偏差的硬币变成装好的骰子。
让我们看看如何解决这两个问题。
假设您有一个 function COIN()
以未知概率输出正面,否则输出反面。 (如果已知硬币产生正面的概率为 0.5,那么您已经拥有一枚公平的硬币,可以跳过此步骤。)
在这里,我们可以使用 1951 年的冯诺依曼算法,将有偏见的硬币变成公平的硬币。 它是这样工作的:
COIN()
两次。 现在我们有一个公平的硬币FAIRCOIN()
。
(请注意,还有其他以这种方式生产公平硬币的方法,统称为随机提取器,但冯诺依曼方法可能是最简单的。)
现在,将公平硬币变成骰子的方法要复杂得多。 可以说有很多方法可以解决这个问题,其中最新的称为快速加载骰子滚轮,它只使用公平的硬币产生一个加载的骰子(实际上,它平均使用多达 6 次公平的硬币投掷超过生产每个加载的模具辊的最佳数量)。 该算法实现起来并不简单,但请参阅我的Python 实现和Fast Loaded Dice Roller的作者的实现。
请注意,要使用快速加载骰子滚轮,您需要将每个概率表示为 integer 权重(例如您的示例中的 25、40、35)。
看看这个:
function weightedRandom(array) {
// expected array: [[percent, var], [percent, var], ...] where sum of percents is 1
var random=Math.random();
var sofar=0;
var index=-1;
for(var i=0; i<array.length; i++) {
if(sofar<random) index=i;
sofar+=array[i][0];
};
return array[index][1];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.