A weighted version of random.choice A weighted version of random.choice python python

A weighted version of random.choice

Since version 1.7.0, NumPy has a choice function that supports probability distributions.

from numpy.random import choicedraw = choice(list_of_candidates, number_of_items_to_pick,              p=probability_distribution)

Note that probability_distribution is a sequence in the same order of list_of_candidates. You can also use the keyword replace=False to change the behavior so that drawn items are not replaced.

Since Python 3.6 there is a method choices from the random module.

In [1]: import randomIn [2]: random.choices(...:     population=[['a','b'], ['b','a'], ['c','b']],...:     weights=[0.2, 0.2, 0.6],...:     k=10...: )Out[2]:[['c', 'b'], ['c', 'b'], ['b', 'a'], ['c', 'b'], ['c', 'b'], ['b', 'a'], ['c', 'b'], ['b', 'a'], ['c', 'b'], ['c', 'b']]

Note that random.choices will sample with replacement, per the docs:

Return a k sized list of elements chosen from the population with replacement.

Note for completeness of answer:

When a sampling unit is drawn from a finite population and is returnedto that population, after its characteristic(s) have been recorded,before the next unit is drawn, the sampling is said to be "withreplacement". It basically means each element may be chosen more thanonce.

If you need to sample without replacement, then as @ronan-paix√£o's brilliant answer states, you can use numpy.choice, whose replace argument controls such behaviour.

def weighted_choice(choices):   total = sum(w for c, w in choices)   r = random.uniform(0, total)   upto = 0   for c, w in choices:      if upto + w >= r:         return c      upto += w   assert False, "Shouldn't get here"