engine - Python Weighted Random
recommendation system pandas (4)
Parece correcto, ya que está utilizando una variable aleatoria uniform
con sorteos independientes, la probabilidad de cada número será 1/n
(n = 100).
Puede verificar fácilmente su algoritmo ejecutándolo diga 1000 veces y ver la frecuencia de cada letra.
Otro algoritmo que podría considerar es generar una matriz con sus letras dada la frecuencia que desea para cada letra y solo generar un único número aleatorio que sea el índice en la matriz
Será menos eficiente en la memoria pero debería funcionar mejor
Editar:
Para responder al comentario de @Joel Cornett, un ejemplo será muy similar a @jurgenreza pero más eficiente en memoria
import random
data_list = [''A''] + [''B''] + [''C''] * 18
random.choice(data_list )
Esta pregunta ya tiene una respuesta aquí:
- Una versión ponderada de random.choice 20 respuestas
Necesito devolver valores diferentes según un round-robin ponderado, de modo que 1 de cada 20 obtenga A, 1 de 20 obtenga B, y el resto vaya a C.
Asi que:
A => 5%
B => 5%
C => 90%
Aquí hay una versión básica que parece funcionar:
import random
x = random.randint(1, 100)
if x <= 5:
return ''A''
elif x > 5 and x <= 10:
return ''B''
else:
return ''C''
¿Es este algoritmo correcto? Si es así, ¿se puede mejorar?
Si desea utilizar aleatorios ponderados y no aleatorios de percentiles, puede crear su propia clase de 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)
Su algoritmo es correcto, ¿qué tal algo más elegante:
import random
my_list = [''A''] * 5 + [''B''] * 5 + [''C''] * 90
random.choice(my_list)
esta bien. De manera más general, puedes definir algo como:
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)
lo que da
Counter({''c'': 17954, ''b'': 1039, ''a'': 1007})
que es lo más cercano a 18: 1: 1 que puede esperar.