Подтвердить что ты не робот

Python Weighted Random

Мне нужно возвращать разные значения на основе взвешенного кругового движения, так что 1 из 20 получает A, 1 в 20 получает 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'

Правильно ли этот алгоритм? Если да, то можно ли улучшить?

4b9b3361

Ответ 1

Ваш алгоритм правильный, как насчет чего-то более элегантного:

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

Ответ 2

это хорошо. в общем, вы можете определить что-то вроде:

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.

Ответ 3

Если вы хотите использовать взвешенные случайные и не процентильные случайные, вы можете создать свой собственный класс 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)

Ответ 4

Кажется правильным, поскольку вы используете случайную переменную uniform с независимыми дроби, вероятность для каждого числа будет 1/n (n = 100).

Вы можете легко проверить свой алгоритм, запустив его, произнесите 1000 раз и увидите частоту для каждой буквы.

Другим алгоритмом, который вы можете рассмотреть, является создание массива с вашими буквами с учетом частоты, которую вы хотите для каждой буквы, и генерируете только одно случайное число, которое является индексом в массиве

Он будет менее эффективным в памяти, но должен работать лучше

Edit:

Чтобы ответить на комментарий @Joel Cornett, пример будет очень похож на @jurgenreza, но с большей эффективностью в памяти

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