用概率从n中选择k

时间:2017-06-20 21:07:20

标签: algorithm random

我列出了n个元素(e_i)。对于每个i,e_i具有选择概率p_i。

我想编写一个算法来从这些n中选择k个元素,但是当我选择它们时,我必须尊重每个元素的概率。我不知道该怎么做,我也不知道有哪些算法可以做到:/

你可以指导我的反思吗?

3 个答案:

答案 0 :(得分:4)

假设您有3个可能的值:A, B, C和: P(A) = 0.2, P(B) = 0.3, P(C) = 0.5。然后,您将累积概率放在数组p = [0.2, 0.5, 1]中。在每个选择中,您将生成[0, 1]范围内的随机数(使用您使用的语言的内置库)。根据该数字,您将作为响应返回大于或等于随机生成的数字的最小数字(实际上是对应于该数字A,B或C的类)。

提示:如果使用最佳方法,可以在O(logN)时间内获得该类。

这是一个例子: 如果您生成0.4的值,则会返回B,因为0.5是最小的数字>= 0.4。如果您生成0.01,则会返回A

这就是我的想法,我会让你尝试实现它。如果您需要更多帮助,我也可以编写一些(伪)代码。

答案 1 :(得分:2)

假设您需要k 不同的元素,您可以执行以下操作:跟踪未选定元素的总remaining概率。反复(k次)选择r范围内的随机数[0,remaining]。扫描概率,累加概率,直到总和超过r。选择相应的元素。然后 - 按此概率减少remaining,然后将该元素的概率归零,以便不再被选中。

这是一个Python实现:

from random import random

def choose(probs,k):
    choices = []
    remaining = 1
    p = probs[:] #create a local copy
    for i in range(k):
        r = remaining * random()
        i = 0
        s = p[i]
        while s < r:
            i += 1
            s += p[i]
        choices.append(i)
        remaining -= p[i]
        p[i] = 0 #so won't be chosen again
    return choices

#test:

dist = [0.2, 0.4, 0.1, 0.1, 0.1, 0.05, 0.05]

for i in range(10):
    print(choose(dist,4))

典型输出:

[2, 5, 1, 3]
[1, 0, 6, 4]
[0, 4, 1, 6]
[1, 2, 3, 0]
[1, 5, 2, 4]
[3, 1, 0, 2]
[1, 2, 0, 4]
[1, 2, 0, 4]
[2, 5, 1, 4]
[1, 2, 0, 3]

请注意经常选择01,但56相对较少。

作为一个实现细节:上述算法应该始终在原则上工作,但是舍入误差和非常接近r的{​​{1}}值可能导致下标超出范围错误。对于某些用例,这应该是非常罕见的,您不必担心它,但您可以添加错误捕获到例如在所有非零概率的总和舍入到恰好低于remaining且所选择的remaining恰好落在那个狭窄的间隙的情况下,选择具有最后非零概率的元素。

答案 2 :(得分:0)

因此,元素ix可以表示为(e_ix,p_ix),因为它们是它的两个组成部分。你显然已经知道要为所有这些填写什么值。我会想出一个例子,所以我可以告诉你如何在不为你做的情况下做到这一点:

(A,1)(B,2)(C,3)

您需要做的是将每个值分配给一个范围。我会做一个简单的方法,从左到右,从零开始。

因此,我们需要1个插槽用于A,2个用于B,3个用于C.我们可能的索引将是0,1,2,3,4和5.

0-&gt; A
1-> B
2-> B
3-> C
4-> C
5-> C

这是一个基本的例子,你的权重可能是浮点数,但它应该给你一个开始。

编辑:浮点示例

(D,2)(E,.5123)(F,1)

D&lt; 2
2&lt; = E&lt; 2.5123
2.5123&lt; = F&lt; 3.5123