如何在python中实现用于拾取随机对象的轮盘赌?

如何在python中实现用于拾取随机对象的轮盘赌?,python,random,probability,Python,Random,Probability,在python中,我有一个对象列表(列表大小>=2),它有一个名为score的属性,该属性的值为>=0的任何浮点值(无上限) 我想从列表中随机选取两个不同的对象,但要确保选取得分较高的值的几率较高。基本上,分数越高,被选中的机会就越大。我想做一个轮盘赌的方式,我把所有的分数加起来,然后得到每个项目的完美分数,百分比是它的分数除以总分 但我如何仍然拾取这两个对象 谢谢这个问题不是很清楚,但我想我明白你的意思了。 您应该使用反向CDF类型的方法。下面的示例将为您的分数列表返回一个索引,然后使用该索引

在python中,我有一个对象列表(列表大小>=2),它有一个名为
score
的属性,该属性的值为>=0的任何浮点值(无上限)

我想从列表中随机选取两个不同的对象,但要确保选取得分较高的值的几率较高。基本上,分数越高,被选中的机会就越大。我想做一个轮盘赌的方式,我把所有的分数加起来,然后得到每个项目的完美分数,百分比是它的分数除以总分

但我如何仍然拾取这两个对象


谢谢

这个问题不是很清楚,但我想我明白你的意思了。 您应该使用反向CDF类型的方法。下面的示例将为您的分数列表返回一个索引,然后使用该索引获取您想要的值。显然,从编程的角度来看,有更聪明的方法可以做到这一点,但您显然需要理解这个方法,我认为这个示例将对您有很大帮助

>>> import numpy as np
>>> import pandas as pd
>>> scores = [100, 200, 300, 400, 500]
>>> scores = np.array(scores)
>>> sum = scores.sum()
>>> sum
1500
>>> percentages = scores/float(sum)
>>> percentages
array([ 0.06666667,  0.13333333,  0.2       ,  0.26666667,  0.33333333])
>>> cdf = percentages.cumsum()
>>> cdf
array([ 0.06666667,  0.2       ,  0.4       ,  0.66666667,  1.        ])
>>> cdf = np.concatenate([np.array([0]), cdf])
>>> cdf
array([ 0.        ,  0.06666667,  0.2       ,  0.4       ,  0.66666667,  1.        ])
>>>def returnobj(cdf, randnum):
>>>    for i in range(len(cdf)-1):
>>>        if((randnum>cdf[i])&(randnum<=cdf[i+1])):
>>>            return i
##########
#This Bit is just to show how the results look, and to show it favours higher scores
>>>for i in range(10000):
>>>    results.append(returnobj(cdf, np.random.random()))
>>>results=pd.DataFrame(results)
>>>results[results.columns[0]] = results[results.columns[0]].astype(str)
>>>results['a'] = results[0]
>>>print results.groupby(0).count()
0   639
1  1375
2  2039
3  2678
4  3269
>>将numpy作为np导入
>>>作为pd进口熊猫
>>>分数=[100200300400500]
>>>分数=np.数组(分数)
>>>sum=分数。sum()
>>>总数
1500
>>>百分比=分数/浮动(总和)
>>>百分比
数组([0.06666667,0.1333333,0.2,0.26666667,0.33333333])
>>>cdf=百分比。累计金额()
>>>cdf
数组([0.066667,0.2,0.4,0.6667,1.]))
>>>cdf=np.concatenate([np.array([0]),cdf])
>>>cdf
数组([0,0.066667,0.2,0.4,0.6667,1.]))
>>>def returnobj(cdf,随机数):
>>>对于范围内的i(len(cdf)-1):
>>>if((randnum>cdf[i])&(randnum>>返回i
##########
#这一点只是为了显示结果的外观,并表明它有利于更高的分数
>>>对于范围(10000)内的i:
>>>results.append(returnobj(cdf,np.random.random())
>>>结果=pd.DataFrame(结果)
>>>结果[results.columns[0]]=results[results.columns[0]].aType(str)
>>>结果['a']=结果[0]
>>>打印结果。groupby(0)。计数()
0   639
1  1375
2  2039
3  2678
4  3269
我会使用一个静态(类)变量来跟踪单个对象的最大分数。然后我会使用一个非静态方法来计算实例分数相对于最大分数的百分比。(这基本上就是您所说的)

在我的主程序中,我会使用一个普通的
randrange
来选择一个对象的
索引
。然后我会调用该对象的百分比函数,并在0-1之间创建另一个随机变量。如果该变量大于函数的结果,则选择该对象,否则不要选择它。重复此操作,直到完成为止拾取所需数量的对象


这很可能不是最佳且灵活的方法,但它应该会给您提供所需的比例。

我将假设项目的分数不会改变,并且项目是唯一的

获取随机加权项的最佳方法是将其索引到累积权重列表中

要获得样本,只需继续随机选取项目,直到您有足够的唯一值

守则:

from bisect import bisect_left
from itertools import accumulate
from random import random, shuffle

class WeightedRandom:
    def __init__(self, items, weights):
        self.items    = list(items)
        self.weights  = list(weights)
        self.cum_wt   = list(accumulate(weights))
        self.total_wt = self.cum_wt[-1]

    def random(self):
        value = random() * self.total_wt
        index = bisect_left(self.cum_wt, value)
        return self.items[index]

    def sample(self, n):
        items = set()
        while len(items) < n:
            items.add(self.random())
        # Note: casting from set to list introduces
        #   an ordering bias; we have to remove this bias.
        items = list(items)
        shuffle(items)
        return items
但是请注意,如果第一个(n-1)项的总和占
总数的很大一部分,那么
示例运行可能需要很长时间。

下面是一个“简单”代码,可以实现我认为您需要的功能

诀窍是选择一个,将其从列表中删除,然后重试

此解决方案适用于您想要挑选的任何数量的项目

import random

class Obj(object):

    def __init__(self, score):
        self.score = score


    def __repr__(self):
        return "<Obj %.2f>"%self.score


def get_items(l, num=2):
    if num==0: return []
    total = sum(o.score for o in l)
    for obj in l:
        obj._chance = obj.score / total
    l = sorted(l, key=lambda o: o._chance)
    selected = l[0] #float problems resolved ;)
    r = random.random()
    chance = 0.0
    for o in l:
        chance += o._chance
        if chance > r:
            selected = o
            break
    l.remove(selected)
    return [selected] + get_items(l, num-1)

l = [Obj(1.0),Obj(2.0),Obj(3.0)]

print (get_items(l, num=2))  
随机导入
Obj类(对象):
定义初始(自我,分数):
self.score=分数
定义报告(自我):
返回“%self.score”
def get_项(l,num=2):
如果num==0:返回[]
总计=总和(o在l中的分数)
对于l中的obj:
目标机会=目标分数/总数
l=已排序(l,键=λo:o.。\U机会)
选定=l[0]#已解决浮点问题;)
r=random.random()
机会=0.0
对于l中的o:
机会+=机会
如果机会>r:
选定的=o
打破
l、 删除(选定)
返回[所选]+获取项目(l,num-1)
l=[Obj(1.0)、Obj(2.0)、Obj(3.0)]
打印(获取_项(l,num=2))

使用numpy的tensorflow这样的库,有几种方法可以做到这一点:

tf.random.categorical([tf.math.log(probs)], 1).numpy()[0][0]
或:

但是,使用随机模块的简单函数应该可以做到:

def roulette_wheel(re: random.Random, probs: List[float], sum_probs: float):
    """Returns the index of chosen element, with probability proportionate to its value"""

    n = re.uniform(0, sum_probs)
    for i, p in enumerate(probs):
        if n <= p:
            return i
        n -= p
    raise ValueError(f"{sum_probs} should be equal to {sum(probs)}")
def轮盘赌(re:random.random,probs:List[float],sum\u probs:float):
“”“返回所选元素的索引,其概率与其值成比例”“”
n=重新均匀(0,求和)
对于枚举中的i,p(probs):

如果n一旦选择第一个对象,是否会在列表中替换它,即,是否可以在第二次选择它?
np.random.multinomial(1, probs/sum_probs).argmax()
def roulette_wheel(re: random.Random, probs: List[float], sum_probs: float):
    """Returns the index of chosen element, with probability proportionate to its value"""

    n = re.uniform(0, sum_probs)
    for i, p in enumerate(probs):
        if n <= p:
            return i
        n -= p
    raise ValueError(f"{sum_probs} should be equal to {sum(probs)}")