简体   繁体   English

我可以使用返回加权布尔值的 function 实现加权随机性吗?

[英]Can I achieve weighted randomness with a function that returns weighted booleans?

I have a method that mimics an unfair coin.我有一种模仿不公平硬币的方法。 You can pass in a percentage, and it tells you whether or not you succeeded by returning a boolean.您可以传入一个百分比,它会通过返回 boolean 来告诉您是否成功。 So if you call it with.25, it'll return true 25% of the time.所以如果你用.25 调用它,它会在 25% 的时间内返回true

I'm trying to figure out if I can use this function to create a weighted randomness function that works like this: There is a 25% chance it returns x, a 40% chance it returns y, and a 35% chance it returns z.我试图弄清楚我是否可以使用这个 function 来创建一个加权随机性 function,它的工作原理如下: There is a 25% chance it returns x, a 40% chance it returns y, and a 35% chance it returns z. This is just an example.这只是一个例子。 I would want the function to work for an unlimited amount of letters, but the percentages added together should equal 1.我希望 function 可以处理无限数量的字母,但加在一起的百分比应该等于 1。

The trick is, I want to be able to think about it the way I just described above.诀窍是,我希望能够按照我刚才描述的方式来思考它。 In other words:换句话说:

result = function ({.25, x}, {.4, y}, {.35, z})

result should be x 25% of the time, and so on. result应该是 x 25% 的时间,依此类推。 Can I implement this function with my unfairCoin?我可以用我的不公平币实现这个 function 吗?


Here's how I worded it in a comment below.it might clarify what I'm asking for:这是我在下面的评论中的措辞。它可能会澄清我的要求:

Correct my logic if I'm making a mistake here, but let's say XY and Z all had.3333... Couldn't I use my unfair coin to pass in.3333... If that returns true, that means you get X as a result.如果我在这里犯了错误,请纠正我的逻辑,但是假设 XY 和 Z 都有。3333...我不能用我的不公平硬币来传递。3333...如果返回 true,那就意味着你得到了结果是 X。 If it returns false, call my unfair again with.5 if that returns true, return Y, otherwise return Z. If that is correct, I don't know how to get this working if the numbers AREN'T.3333 and if there's more than three如果返回 false,再次调用我的不公平。5 如果返回 true,则返回 Y,否则返回 Z。如果正确,如果数字 AREN'T.3333 并且如果有,我不知道如何使它工作三个以上

If you have coins with a known probability of heads如果你有已知正面概率的硬币

Assume you have a function unfairCoin(p) , which is a function that produces heads with a known probability p and tails otherwise.假设你有一个 function unfairCoin(p) ,这是一个 function 以已知概率p产生正面,否则产生反面。 For example, it could be implemented like this:例如,它可以这样实现:

function unfairCoin(p) {
   return Math.random() < p ? True : false;
}

Here is an algorithm that solves your problem given unfairCoin , assuming all the probabilities involved sum to 1:假设所有涉及的概率总和为 1,这是一个算法,可以解决您的问题给定unfairCoin

  1. Set cumu to 1.cumu设置为 1。
  2. For each item starting with the first:对于从第一个开始的每个项目:
    1. Get the probability associated with the chosen item (call it p ) and accept the item with probability p / cumu (eg, via unfairCoin(p / cumu) ).获取与所选项目相关的概率(称为p )并以概率p / cumu接受项目(例如,通过unfairCoin(p / cumu) )。 If the item is accepted, return that item.如果该项目被接受,则退回该项目。
    2. If the item was not accepted, subtract p from cumu .如果该项目未被接受,则从cumu中减去p

This algorithm's expected time complexity depends on the order of the probabilities.该算法的预期时间复杂度取决于概率的顺序。 In general, the algorithm's time complexity is linear, but if the probabilities are sorted in descending order, the expected time complexity is constant.一般来说,该算法的时间复杂度是线性的,但如果将概率按降序排序,则预期时间复杂度是恒定的。

EDIT (Jul. 30): As I've just found out, this exact algorithm was already described by Keith Schwarz in Darts, Dice, and Coins , in "Simulating a Loaded Die with a Biased Coin".编辑(7 月 30 日):正如我刚刚发现的那样,Keith Schwarz 在Darts, Dice, and Coins中已经描述了这个精确的算法,在“用有偏差的硬币模拟加载的模具”中。 That page also contains a proof of its correctness.该页面还包含其正确性的证明。


An alternative solution uses rejection sampling, but requires generating a random integer using fair coin tosses:另一种解决方案使用拒绝抽样,但需要使用公平的硬币投掷生成随机 integer:

  1. Generate a uniform random integer index in the interval [0, n), where n is the number of items.在区间 [0, n) 内生成均匀随机 integer 索引,其中n为项目数。 This can be done, for example, using the Fast Dice Roller by J. Lumbroso, which uses only fair coin tosses ( unfairCoin(0.5) );例如,可以使用 J. Lumbroso 的Fast Dice Roller来做到这一点,它只使用公平的硬币投掷 ( unfairCoin(0.5) ); see the code below.请参阅下面的代码。 Choose the item at the given index (starting at 0).选择给定索引处的项目(从 0 开始)。
  2. Get the probability associated with the chosen item (call it p ) and accept it with probability p (eg, via unfairCoin(p) ).获取与所选项目相关的概率(称为p )并以概率p接受它(例如,通过unfairCoin(p) )。 If the item is accepted, return that item;如果该项目被接受,则退回该项目; otherwise, go to step 1.否则,go 执行步骤 1。

This algorithm's expected time complexity depends on the difference between the lowest and highest probability.该算法的预期时间复杂度取决于最低概率和最高概率之间的差异。

Given the weights for each item, there are many other ways to make a weighted choice besides the algorithms given earlier;给定每个项目的权重,除了前面给出的算法之外,还有许多其他方法可以做出加权选择; see my note on weighted choice algorithms .请参阅我关于加权选择算法的说明

Fast Dice Roller Implementation快速骰子滚子实施

The following is JavaScript code that implements the Fast Dice Roller.以下是实现快速骰子滚轮的 JavaScript 代码。 Note that it uses a rejection event and a loop to ensure it's unbiased.请注意,它使用拒绝事件和循环来确保它是公正的。

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
    }
  }
}

If you have coins with an unknown probability of heads如果您的硬币正面概率未知

If on the other hand, you have a function COIN that outputs heads with an unknown probability and tails otherwise, then there are two problems to solve to get to the solution:另一方面,如果你有一个 function COIN未知的概率输出正面而反之,那么有两个问题需要解决才能获得解决方案:

  1. How to turn a biased coin into a fair coin.如何将有偏见的硬币变成公平的硬币。
  2. How to turn a fair coin into a loaded die.如何将一个公平的硬币变成一个装好的骰子。

In other words, the task is to turn a biased coin into a loaded die.换句话说,任务是将有偏差的硬币变成装好的骰子。

Let's see how these two problems can be solved.让我们看看如何解决这两个问题。

From biased to fair coins从有偏见的硬币到公平的硬币

Assume you have a function COIN() that outputs heads with an unknown probability and tails otherwise.假设您有一个 function COIN()以未知概率输出正面,否则输出反面。 (If the coin is known to have probability 0.5 of producing heads then you already have a fair coin and can skip this step.) (如果已知硬币产生正面的概率为 0.5,那么您已经拥有一枚公平的硬币,可以跳过此步骤。)

Here we can use von Neumann's algorithm from 1951 of turning a biased coin into a fair coin.在这里,我们可以使用 1951 年的冯诺依曼算法,将有偏见的硬币变成公平的硬币。 It works like this:它是这样工作的:

  1. Flip COIN() twice.翻转COIN()两次。
  2. If both results are heads or both are tails, go to step 1.如果两个结果都是正面或两个结果都是反面,go 到步骤 1。
  3. If the first result is heads and the other is tails, take heads as the final result.如果第一个结果是正面,另一个是反面,则以正面为最终结果。
  4. If the first result is tails and the other is heads, take tails as the final result.如果第一个结果是反面,另一个是正面,则以反面作为最终结果。

Now we have a fair coin FAIRCOIN() .现在我们有一个公平的硬币FAIRCOIN()

(Note that there are other ways of producing fair coins this way, collectively called randomness extractors , but the von Neumann method is perhaps the simplest.) (请注意,还有其他以这种方式生产公平硬币的方法,统称为随机提取器,但冯诺依曼方法可能是最简单的。)

From fair coins to loaded dice从公平的硬币到装好的骰子

Now, the method to turn fair coins into loaded dice is much more complex.现在,将公平硬币变成骰子的方法要复杂得多。 It suffices to say that there are many ways to solve this problem, and the newest of them is called the Fast Loaded Dice Roller , which produces a loaded die using just fair coins (in fact, it uses on average up to 6 fair coin tosses more than the optimal amount to produce each loaded die roll).可以说有很多方法可以解决这个问题,其中最新的称为快速加载骰子滚轮,它只使用公平的硬币产生一个加载的骰子(实际上,它平均使用多达 6 次公平的硬币投掷超过生产每个加载的模具辊的最佳数量)。 The algorithm is not exactly trivial to implement, but see my Python implementation and the implementation by the Fast Loaded Dice Roller 's authors.该算法实现起来并不简单,但请参阅我的Python 实现Fast Loaded Dice Roller的作者的实现。

Note that to use the Fast Loaded Dice Roller, you need to express each probability as an integer weight (such as 25, 40, 35 in your example).请注意,要使用快速加载骰子滚轮,您需要将每个概率表示为 integer 权重(例如您的示例中的 25、40、35)。

Look into this:看看这个:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM