我需要根据加权轮询返回不同的值,使得每20个请求中有1个收到A,1个收到B,其余的都收到C。
因此:
A => 5%
B => 5%
C => 90%
这是一个看起来可以工作的基本版本:
import random
x = random.randint(1, 100)
if x <= 5:
return 'A'
elif x > 5 and x <= 10:
return 'B'
else:
return 'C'
这个算法是否正确?如果是,它能被优化吗?
我需要根据加权轮询返回不同的值,使得每20个请求中有1个收到A,1个收到B,其余的都收到C。
因此:
A => 5%
B => 5%
C => 90%
这是一个看起来可以工作的基本版本:
import random
x = random.randint(1, 100)
if x <= 5:
return 'A'
elif x > 5 and x <= 10:
return 'B'
else:
return 'C'
这个算法是否正确?如果是,它能被优化吗?
你的算法是正确的,不过能不能来点更加优美的实现呢:
import random
my_list = ['A'] * 5 + ['B'] * 5 + ['C'] * 90
random.choice(my_list)
my_list = ['A'] * 5 + ['B'] * 5 + ['C'] * 90
呢? - Joel Cornett['A', 'B'] + ['C'] * 18
。 - Joel Cornett没问题。更普遍地说,您可以定义类似于以下内容:
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)
提供
Counter({'c': 17954, 'b': 1039, 'a': 1007})
这个比例非常接近18:1:1,你可以期待这样的比例。
如果你想使用加权随机而不是百分比随机,你可以创建自己的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)
由于您使用了独立抽样的 uniform
随机变量,每个数字的概率都将是 1/n
(n=100),因此似乎是正确的。
您可以通过运行算法大约 1000 次并查看每个字母的频率来轻松验证您的算法。
您可能还考虑另一种算法,即根据您想要的每个字母的频率生成一个包含字母的数组,并仅生成一个随机数,该随机数是数组中的索引。
这种方法在内存效率上可能不如前一种方法,但应该会更好地执行。
编辑:
为了回应 @Joel Cornett 的评论,一个示例将非常类似于 @jurgenreza,但更节省内存。
import random
data_list = ['A'] + ['B'] + ['C'] * 18
random.choice(data_list )
random.randint(1,20)
。 - Akavall