根据概率选择获胜者的随机数

时间:2012-01-31 00:38:44

标签: generics random

想象一下,你有一系列代表竞争对手的哈希值以及赢得奖品的概率(0到1之间的浮点数)。像:

  [ {:name => "Adam" , :prob => 0.5}
    {:name => "Ben" , :prob => 1.0}
    {:name => "Chris" , :prob => 0.1}
    {:name => "Daniel" , :prob => 0.2}
    {:name => "Ed" , :prob => 0.7}
    {:name => "Frey" , :prob => 0.5}
    {:name => "Gilbert" , :prob => 0.3}
  ]

我想有一个算法,我可以使用随机数选择三个获胜者但尊重每个人的概率。

样本的总概率为3.3

逻辑方法是计算随机值,如:

val = rand(33)/10.0

扫描阵列,直到找到达到随机数的人。

这种方法有效,但它意味着在阵列中进行扫描。

我想知道是否会有更直接的解决方案。有什么想法吗?

PS:想象一下,数组可能包含大量元素。

4 个答案:

答案 0 :(得分:2)

创建一个循环,直到选择3个获胜者。在此循环中,使用您选择的编程语言中提供的任何随机方法生成特定随机数。在此之后,开始迭代用户。如果任何用户的概率小于此随机数,则接受该用户为胜利者。如果在循环的任何迭代中没有选择赢家,例如,在列表中最低概率为0.2且生成的随机数为0.1的情况下,在这种情况下,继续循环的下一次迭代。当你获得3名获胜者时,突破循环。这种可能的伪代码可以如下:

int count=0;
while(count<3){
    temp=GenerateRandomNumber()
    int userIndex= AcceptWinner(UserListProbability,temp)
    //here keep iterating through the users to check which user's probability is less than temp and returns the index of the winner in the List

    if(userIndex==-1)//No winner selected
        continue;
    else{
        count++;
        Print List(userIndex)
    }
}

注意:列表应该排序

答案 1 :(得分:1)

我在想这个,我认为我的结果很有意义:

  1. 根据概率对矢量进行排序:[a = 0.1,b = 0.2,c = 0.3,d = 0.4]
  2. 选择一个随机数(例如0.5)
  3. 从头开始迭代并对概率值求和,并在它更高时停止: 答案= 0.1 + 0.2 + 0.3。那么,0.6> 0.5,我们重视'c'
  4. 我对此的要点是,向量末尾的值应该具有更高的被选择概率。我在python中实现了:

    values = [0.1,0.2,0.3,0.4]
    count_values = len(values)*[0]
    answer = len(values)*[0]
    
    iterations = 10000 
    
    for i in range(0,iterations):
        rand = float(random.randint(0,iterations))/iterations
        count = 0
        sum = 0
        while sum <= rand and count <= len(values):
            sum += values[count]
            count += 1
        count_values[count-1]+=1
    
    for i in range(0,len(count_values)):
        answer[i] = float(count_values[i])/iterations
    

    并且运行了几次,我计算了所有元素被选中的概率,它应该与我们的初始概率相匹配:

    [0.1043, 0.196, 0.307, 0.3927]
    [0.1018, 0.2003, 0.2954, 0.4025]
    [0.0965, 0.1997, 0.3039, 0.3999]
    

答案 2 :(得分:0)

我假设在你的例子中“概率”意味着“权重”(因此概率为1.0的人不能保证获胜,总概率不会总和为1.0)

您可以构建一个节点树,其中叶节点包含您的各个条目:

leaf1 = {:name => "Adam" , :prob => 0.5}
leaf2 = {:name => "Ben" , :prob => 1.0}

并且每个节点包含其下的节点之和

node1 = { :prob_sum => 1.5 , :children=> [ leaf1, leaf2] }

然后根节点包含整个结构的总和

root_node = { :prob_sum => 33 , :children => [ leaf9, leaf10] }

然后在零和根节点中包含的总和之间选择一个随机数。

my_random = rand( root_node.prob_sum )

然后遍历树。每个节点包含其下所有节点的总和,因此如果您的随机数大于节点,则减去该节点的值并跳过该分支。

def find_node( my_random ):
c = children.first()
while( c ):
     if ( c.prob_sum < my_random ):
         return c.find_node(my_random)
     my_random -= c.prob_sum
     c = c.next

假设您已经构建了一个平衡树,您应该在O(log n)

中得到结果

或者,您可以通过向当前数据集添加运行总计字段并根据运行总计进行二进制搜索来获得相同的结果。这可能更容易实现,但只有在您的工作集适合内存时才适用。

答案 3 :(得分:0)

目前还有一种方法可行,但存在一些问题。

今天我创建了一个数组,并为该数组中的每个人设置了100个概率。

然后可以直接对数组内容进行随机。

第一个问题是它在每个方面(内存,处理......)都很昂贵而且它不能扩展。

我选择第二个和第三个人时遇到的第二个问题是我先取出第一个或者随机循环,直到找到另一个人。

尽管如此,对于小型数据集(就像我到目前为止,但会随着时间的推移而增加),这个解决方案运行良好。