Select random item with weight

前端 未结 5 1760
执笔经年
执笔经年 2020-12-15 00:48

I have a list of approx. 10000 items. The current situation is that every item has an associated weight (priority or importance). Now the smallest weight is -100

相关标签:
5条回答
  • 2020-12-15 00:53

    If you're storing your data in a database, you can use SQL:

    SELECT * FROM table ORDER BY weight*random() DESC LIMIT 1
    
    0 讨论(0)
  • 2020-12-15 01:01

    Have a look at this, i think it's what you need with some nice comparision between different methods Weighted random generation in Python

    The simplest approach suggested is:

    import random
    
    def weighted_choice(weights):
        totals = []
        running_total = 0
    
        for w in weights:
            running_total += w
            totals.append(running_total)
    
        rnd = random.random() * running_total
        for i, total in enumerate(totals):
            if rnd < total:
                return i
    

    You can find more details and possible improvements as well as some different approaches in the link above.

    0 讨论(0)
  • 2020-12-15 01:11

    Python 3.6 introduced random.choices()

    def get_item(items, items_weights):
        return random.choices(items, weights=items_weights)[0]
    
    0 讨论(0)
  • 2020-12-15 01:13

    You should extract a random number between 0 and the sum of weights (positive by definition). Then you get the item from a list by using bisect: http://docs.python.org/library/bisect.html (the bisect standard moduke).

    import random 
    import bisect
    weight = {'a':0.3,'b':3.2,'c':2.4}
    items = weight.keys()
    mysum = 0
    breakpoints = [] 
    for i in items:
        mysum += weight[i]
        breakpoints.append(mysum)
    
    def getitem(breakpoints,items):
        score = random.random() * breakpoints[-1]
        i = bisect.bisect(breakpoints, score)
        return items[i] 
    
    print getitem(breakpoints,items)
    
    0 讨论(0)
  • 2020-12-15 01:15

    It's easier to do if the weights are not negative. If you have to have negative weights, you'll have to offset the weights by the lowest possible weight. In your case, offsetted_weight = itemweight + 100

    In pseudocode, it goes like this:

    Calculate the sum of all the weights.
    Do a random from 0 to the sum of the weights
    Set i to 0
    While the random number > 0
        Subtract the weight of the item at index i  from random
        If the random number is < 0 return item[i]
        Add 1 to i
    
    0 讨论(0)
提交回复
热议问题