代码之家  ›  专栏  ›  技术社区  ›  Christian

选择概率不同的列表元素的方法[重复]

  •  33
  • Christian  · 技术社区  · 14 年前

    这个问题已经有了答案:

    import random
    pos = ["A", "B", "C"]
    x = random.choice["A", "B", "C"]
    

    这段代码给了我相等概率的“a”、“b”或“c”。 当你想要30%的“A”,40%的“B”,30%的概率的“C”时,有没有更好的表达方式?

    6 回复  |  直到 6 年前
        1
  •  37
  •   jpyams David Thompson    6 年前

    applying its associated inverse cumulative distribution function

    SO explanation Wikipedia

    import random
    import bisect
    import collections
    
    def cdf(weights):
        total = sum(weights)
        result = []
        cumsum = 0
        for w in weights:
            cumsum += w
            result.append(cumsum / total)
        return result
    
    def choice(population, weights):
        assert len(population) == len(weights)
        cdf_vals = cdf(weights)
        x = random.random()
        idx = bisect.bisect(cdf_vals, x)
        return population[idx]
    
    weights=[0.3, 0.4, 0.3]
    population = 'ABC'
    counts = collections.defaultdict(int)
    for i in range(10000):
        counts[choice(population, weights)] += 1
    print(counts)
    
    # % test.py
    # defaultdict(<type 'int'>, {'A': 3066, 'C': 2964, 'B': 3970})
    

    choice bisect.bisect O(log n) n weights


    np.random.choice function [0,1,2,3] [0.1, 0.2, 0.3, 0.4]

    import numpy as np
    np.random.choice(4, 1000, p=[0.1, 0.2, 0.3, 0.4])
    

    np.random.choice replace


    Alias Method O(n) O(1) here numpy version here

        2
  •  25
  •   Ignacio Vazquez-Abrams    14 年前

    pos = ['A'] * 3 + ['B'] * 4 + ['C'] * 3
    print random.choice(pos)
    

    pos = {'A': 3, 'B': 4, 'C': 3}
    print random.choice([x for x in pos for y in range(pos[x])])
    
        3
  •  9
  •   Glenn Maynard    14 年前

    import bisect
    class WeightedTuple(object):
        """
        >>> p = WeightedTuple({'A': 2, 'B': 1, 'C': 3})
        >>> len(p)
        6
        >>> p[0], p[1], p[2], p[3], p[4], p[5]
        ('A', 'A', 'B', 'C', 'C', 'C')
        >>> p[-1], p[-2], p[-3], p[-4], p[-5], p[-6]
        ('C', 'C', 'C', 'B', 'A', 'A')
        >>> p[6]
        Traceback (most recent call last):
        ...
        IndexError
        >>> p[-7]
        Traceback (most recent call last):
        ...
        IndexError
        """
        def __init__(self, items):
            self.indexes = []
            self.items = []
            next_index = 0
            for key in sorted(items.keys()):
                val = items[key]
                self.indexes.append(next_index)
                self.items.append(key)
                next_index += val
    
            self.len = next_index
    
        def __getitem__(self, n):
            if n < 0:
                n = self.len + n
            if n < 0 or n >= self.len:
                raise IndexError
    
            idx = bisect.bisect_right(self.indexes, n)
            return self.items[idx-1]
    
        def __len__(self):
            return self.len
    

    data = WeightedTuple({'A': 30, 'B': 40, 'C': 30})
    random.choice(data)
    
        4
  •  5
  •   jsbueno    14 年前

    pos = [("A", 30), ("B", 40), ("C", 30)]
    
    
    from random import uniform
    def w_choice(seq):
        total_prob = sum(item[1] for item in seq)
        chosen = random.uniform(0, total_prob)
        cumulative = 0
        for item, probality in seq:
            cumulative += probality
            if cumulative > chosen:
                return item
    
        5
  •  5
  •   Jeet    14 年前
        6
  •  0
  •   Jeff Bradberry    14 年前

    import random
    from decimal import Decimal
    
    pos = {'A': Decimal("0.3"), 'B': Decimal("0.4"), 'C': Decimal("0.3")}
    choice = random.random()
    F_x = 0
    for k, p in pos.iteritems():
        F_x += p
        if choice <= F_x:
            x = k
            break