Welcome, guest | Sign In | My Account | Store | Cart

Choices randomly an element from a list, not uniformly, but using a given weight for each element.

Python, 48 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from __future__ import division
import random, bisect
 
class ItemGenerator(object):
    '''Choices randomly an element from a list.

    It does it not uniformly, but using a given weight for
    each element.

    Just instantiate this class passing a list of pairs 
    (item, weight), and then call it to get the items.
    '''
    def __init__(self, items):
        self.puntos = []
        self.ponderado = []
        total = sum(x[1] for x in items)
        acum = 0
        for it,peso in items:
            acum += peso
            self.puntos.append(it)
            self.ponderado.append(acum/total)
        self.total = acum - 1

    def __call__(self):
        ind = random.random()
        cual = bisect.bisect(self.ponderado, ind)
        return self.puntos[cual]
 
if __name__ == "__main__":
    # This shows the usage, and also test the recipe, as calling that
    # a lot of times, it should return the elements in the same 
    # given proportion

    items = (
        ("A", 10),
        ("B", 100),
        ("C", 5)
    )

    itgen = ItemGenerator(items)
    cuenta = {}
    for i in range(1000000):
        item = itgen()
        cuenta[item] = cuenta.get(item, 0) + 1
    print cuenta

1 comment

Paddy McCarthy 13 years, 9 months ago  # | flag

Rosetta Code has a couple of solutions in Python, (by me), as well as many more in other languages.

  • Paddy.