Python gewogen willekeurig

Ik moet verschillende waarden retourneren op basis van een gewogen round-robin, zodat 1 op 20 A krijgt, 1 op 20 B en de rest naar C gaat.

Dus:

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

Hier is een basisversie die lijkt te werken:

import random
x = random.randint(1, 100)
if x <= 5:
    return 'A'
elif x > 5 and x <= 10:
    return 'B'
else:
    return 'C'

Is dit algoritme correct? Zo ja, kan dit verbeterd worden?


Antwoord 1, autoriteit 100%

Uw algoritme is correct, wat dacht u van iets eleganters:

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

Antwoord 2, autoriteit 66%

dat is prima. meer in het algemeen kun je zoiets definiëren als:

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)

wat geeft

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

wat zo dicht bij 18:1:1 ligt als je kunt verwachten.


Antwoord 3, autoriteit 16%

Als u gewogen willekeurig wilt gebruiken en niet willekeurig percentiel, kunt u uw eigen Randomizer-klasse maken:

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)

Antwoord 4

Het lijkt correct, omdat u een uniformwillekeurige variabele met onafhankelijke trekkingen De waarschijnlijkheid voor elk getal is 1/n(n = 100).

U kunt eenvoudig uw algoritme verifiëren door deze te laten uitvoeren, zeg 1000 keer en zie de frequentie voor elke letter.

Een ander algoritme dat u zou kunnen overwegen, is om een ​​array met uw brieven te genereren, gezien de gewenste frequentie voor elke letter en genereert alleen een enkel willekeurig nummer dat de index is in de array

Het is minder efficiënt in het geheugen, maar moet beter

uitvoeren

bewerken:

Reageren op @Joel Cornett Comments, zal een voorbeeld vergelijkbaar zijn met @jurgenreza, maar meer geheugenzuinig

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

Other episodes