Python加权随机

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14992521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:01:55  来源:igfitidea点击:

Python Weighted Random

pythonalgorithmround-robin

提问by doremi

I need to return different values based on a weighted round-robin such that 1 in 20 gets A, 1 in 20 gets B, and the rest go to C.

我需要根据加权循环返回不同的值,这样 20 分之 1 得到 A,20 分之一得到 B,其余的转到 C。

So:

所以:

A => 5%
B => 5%
C => 90%

Here's a basic version that appears to work:

这是一个似乎有效的基本版本:

import random

x = random.randint(1, 100)

if x <= 5:
    return 'A'
elif x > 5 and x <= 10:
    return 'B'
else:
    return 'C'

Is this algorithm correct? If so, can it be improved?

这个算法正确吗?如果是这样,是否可以改进?

采纳答案by jurgenreza

Your algorithm is correct, how about something more elegant:

你的算法是正确的,更优雅的东西怎么样:

import random
my_list = ['A'] * 5 + ['B'] * 5 + ['C'] * 90
random.choice(my_list)

回答by andrew cooke

that's fine. more generally, you can define something like:

没关系。更一般地说,您可以定义如下内容:

from collections import Counter
from random import randint

def weighted_random(pairs):
    total = sum(pair[0] for pair in pairs)
    r = randint(1, total)
    for (weight, value) in pairs:
        r -= weight
        if r <= 0: return value

results = Counter(weighted_random([(1,'a'),(1,'b'),(18,'c')])
                  for _ in range(20000))
print(results)

which gives

这使

Counter({'c': 17954, 'b': 1039, 'a': 1007})

which is as close to 18:1:1 as you can expect.

这与您预期的一样接近 18:1:1。

回答by iTech

It seems correct since you are using a uniformrandom variable with independent draws the probability for each number will be 1/n(n=100).

这似乎是正确的,因为您使用的是uniform具有独立绘制的随机变量,每个数字的概率为1/n(n=100)。

You can easily verify your algorithm by running it say 1000 time and see the frequency for each letter.

您可以通过运行 1000 次并查看每个字母的频率来轻松验证您的算法。

Another algorithm you might consider is to generate an array with your letters given the frequency you want for each letter and only generate a single random number which is the index in the array

您可能会考虑的另一种算法是给定每个字母所需的频率,用您的字母生成一个数组,并且只生成一个随机数,即数组中的索引

It will be less efficient in memory but should perform better

它的内存效率会降低,但性能应该会更好

Edit:

编辑:

To respond to @Joel Cornett comment, an example will be very similar to @jurgenreza but more memory efficient

为了回应@Joel Cornett 的评论,一个例子将与@jurgenreza 非常相似,但内存效率更高

import random
data_list = ['A'] + ['B'] + ['C'] * 18
random.choice(data_list )

回答by Hyperboreus

If you want to use weighted random and not percentile random, you can make your own Randomizer class:

如果您想使用加权随机而不是百分位随机,您可以创建自己的 Randomizer 类:

import random

class WeightedRandomizer:
    def __init__ (self, weights):
        self.__max = .0
        self.__weights = []
        for value, weight in weights.items ():
            self.__max += weight
            self.__weights.append ( (self.__max, value) )

    def random (self):
        r = random.random () * self.__max
        for ceil, value in self.__weights:
            if ceil > r: return value

w = {'A': 1.0, 'B': 1.0, 'C': 18.0}
#or w = {'A': 5, 'B': 5, 'C': 90}
#or w = {'A': 1.0/18, 'B': 1.0/18, 'C': 1.0}
#or or or

wr = WeightedRandomizer (w)

results = {'A': 0, 'B': 0, 'C': 0}
for i in range (10000):
    results [wr.random () ] += 1

print ('After 10000 rounds the distribution is:')
print (results)