簡體   English   中英

我可以使用返回加權布爾值的 function 實現加權隨機性嗎?

[英]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

  1. cumu設置為 1。
  2. 對於從第一個開始的每個項目:
    1. 獲取與所選項目相關的概率(稱為p )並以概率p / cumu接受項目(例如,通過unfairCoin(p / cumu) )。 如果該項目被接受,則退回該項目。
    2. 如果該項目未被接受,則從cumu中減去p

該算法的預期時間復雜度取決於概率的順序。 一般來說,該算法的時間復雜度是線性的,但如果將概率按降序排序,則預期時間復雜度是恆定的。

編輯(7 月 30 日):正如我剛剛發現的那樣,Keith Schwarz 在Darts, Dice, and Coins中已經描述了這個精確的算法,在“用有偏差的硬幣模擬加載的模具”中。 該頁面還包含其正確性的證明。


另一種解決方案使用拒絕抽樣,但需要使用公平的硬幣投擲生成隨機 integer:

  1. 在區間 [0, n) 內生成均勻隨機 integer 索引,其中n為項目數。 例如,可以使用 J. Lumbroso 的Fast Dice Roller來做到這一點,它只使用公平的硬幣投擲 ( unfairCoin(0.5) ); 請參閱下面的代碼。 選擇給定索引處的項目(從 0 開始)。
  2. 獲取與所選項目相關的概率(稱為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未知的概率輸出正面而反之,那么有兩個問題需要解決才能獲得解決方案:

  1. 如何將有偏見的硬幣變成公平的硬幣。
  2. 如何將一個公平的硬幣變成一個裝好的骰子。

換句話說,任務是將有偏差的硬幣變成裝好的骰子。

讓我們看看如何解決這兩個問題。

從有偏見的硬幣到公平的硬幣

假設您有一個 function COIN()以未知概率輸出正面,否則輸出反面。 (如果已知硬幣產生正面的概率為 0.5,那么您已經擁有一枚公平的硬幣,可以跳過此步驟。)

在這里,我們可以使用 1951 年的馮諾依曼算法,將有偏見的硬幣變成公平的硬幣。 它是這樣工作的:

  1. 翻轉COIN()兩次。
  2. 如果兩個結果都是正面或兩個結果都是反面,go 到步驟 1。
  3. 如果第一個結果是正面,另一個是反面,則以正面為最終結果。
  4. 如果第一個結果是反面,另一個是正面,則以反面作為最終結果。

現在我們有一個公平的硬幣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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM