Generics 根据概率选择赢家的随机数
假设您有一个代表竞争对手及其获奖概率的哈希数组(介于0和1之间的浮动)。比如: 我想有一个算法,我可以选择三个赢家使用随机数,但尊重每个人的概率 样本的总概率为3.3 逻辑方法是计算随机值,如下所示:Generics 根据概率选择赢家的随机数,generics,random,Generics,Random,假设您有一个代表竞争对手及其获奖概率的哈希数组(介于0和1之间的浮动)。比如: 我想有一个算法,我可以选择三个赢家使用随机数,但尊重每个人的概率 样本的总概率为3.3 逻辑方法是计算随机值,如下所示: val = rand(33)/10.0 然后扫描数组,直到我找到那个达到随机数的人 这种方法可行,但它意味着在阵列中进行扫描 我想知道是否会有一个更直接的解决办法。有什么想法吗 PS:想象一下数组可能有大量元素。我在考虑这个问题,我认为我的结果是有意义的: 根据概率对向量排序:[a=0.1,b=
val = rand(33)/10.0
然后扫描数组,直到我找到那个达到随机数的人
这种方法可行,但它意味着在阵列中进行扫描
我想知道是否会有一个更直接的解决办法。有什么想法吗
PS:想象一下数组可能有大量元素。我在考虑这个问题,我认为我的结果是有意义的:
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
我假设在你的例子中,“概率”意味着“权重”(因此概率为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] }
然后在0和根节点中包含的和之间选择一个随机数
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
def find_节点(my_random):
c=儿童。第一个()
而(三):
如果(c.prob_sum
假设您已经构建了一个平衡树,您应该在O(logn)中得到结果
或者,您可以通过向当前数据集中添加一个“运行总计”字段并基于该“运行总计”进行二进制搜索来获得相同的结果。这可能更容易实现,但只有当您的工作集可以放在内存中时才适用。还有一种方法目前仍在使用,但存在一些问题 今天,我创建了一个数组,并为该数组中的每个人输入概率*100个条目 然后可以直接对数组内容执行随机操作 第一个问题是,它在各个方面(内存、处理等)都很昂贵,而且无法扩展 第二个问题是,当我选择第二个和第三个人物时,我要么把第一个人物拿出来,要么随机循环,直到另一个人被选中
尽管如此,对于小数据集(如我到目前为止所做的,但会随着时间的推移而增加),此解决方案工作得很好。创建一个循环,该循环将一直运行到选择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)
}
}
int count=0;
虽然(countI在下面发布了我的解决方案,但是,考虑到你处理的是概率,我认为所有概率的总和应该等于1。在你的例子中,Ben有100%的几率被选中。是的,你是对的。只是我实际上使用了配额的概念,为了简化问题,我将配额改为0我实际上很喜欢你的第二种方法,把运行总数相加,然后进行二进制搜索,因为在系统中,“权重/概率”因为每个人都会随着时间的推移而变化,我需要重建树。对于有序表,我只需要保持它们的有序。谢谢。我只是不明白为什么要对向量进行排序?不进行排序,这就是我在问题中提到的方法。谢谢。因为我们求和权重,例如,如果它们没有排序,则概率最高刚开始的时候(如0.6),永远不会选择较小的(如0.1)。无论如何,测试一万次此处发布的所有解决方案,看看它们是否正确,结果必须与概率匹配。这里的复杂性也是O(n)
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
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)
}
}