Possible Duplicate:
A weighted version of random.choice
Let's say for simplicity a function takes in 4 inputs: 2 names and their respective 'bias/weights', how can I write a function such that it returns either a
or b
at random but still considers those weights into the random outcome.
a = 'x'
b = 'y'
p_a = 10
p_b = 90
def myRand(a, p_a, b, p_b):
return 'x' 10% of the time, 'y' 90% of time
What I've done so far
import random
def myRand(a, p_a, b, p_b):
probs = [a]*p_a + [b]*p_b
return random.choice(probs)
Can someone point why this is an incorrect or not the best answer? My justification is that I'm assuming every element has the same probability of being picked so the outcome should still favor 10:90. Or maybe we can shuffle the array before using random.choice()
?
Is there a better way to do this? Maybe I'm missing something obvious here or is this correct?
Thanks
I've modified the function to accept an arbitrary number of inputs and weighted probabilities so if later on you decide you want to use more than two inputs, you can.
import random
def myRand(i, w):
r = random.uniform(0, sum(w))
# loop through a list of inputs and max cutoff values, returning
# the first value for which the random num r is less than the cutoff value
for n,v in map(None, i,[sum(w[:x+1]) for x in range(len(w))]):
if r < v:
return n
Example usage:
inputs = ['e', 'f', 'g', 'h']
weights = [10, 30, 50, 10]
print myRand(inputs, weights)
This would accomplish what you're trying to do:
#assumes p_a and p_b are both positive numbers that sum to 100
def myRand(a, p_a, b, p_b):
return a if random.uniform(0,100) < p_a else b
Note that p_b becomes unnecessary in your special case of having only 2 weights, since p_b == 100-p_a
.
a = 'x';b = 'y';p_a = 10;p_b = 90
ratio = p_a+pb = 100
generate a random number between 0 and 100 and if the number is less than 10 use a=>x else use b=>y