English 中文(简体)
如何从已知百分比的名单中选定一个项目
原标题:How to select an item from a list with known percentages in Python
  • 时间:2009-10-12 18:46:00
  •  标签:

我想从每个字都知道的机会的清单中选取一个字句,例如:

具有可证明性的产品

Orange 0.10 Apple 0.05 Mango 0.15 etc

如何以最佳方式执行? 我将从实际清单中提取最多100个物项,而其百分比并不等于100%,以计入实际较少发生机会的项目。 我很想从我存放这一数据的CSV那里来这样做。 这不是一项关键的任务。

感谢你就如何最好地开展工作提出任何建议。

最佳回答

如果您将每个项目分配到与其概率成正比的一定范围,在零到幅度之间随机抽取数量,并找到与该项目相匹配的项目,则你可以选择加权。 下面的班级确实是:

from random import random

class WeightedChoice(object):
    def __init__(self, weights):
        """Pick items with weighted probabilities.

            weights
                a sequence of tuples of item and it s weight.
        """
        self._total_weight = 0.
        self._item_levels = []
        for item, weight in weights:
            self._total_weight += weight
            self._item_levels.append((self._total_weight, item))

    def pick(self):
        pick = self._total_weight * random()
        for level, item in self._item_levels:
            if level >= pick:
                return item

然后,你可以将CSV文档装上csv。 模块并将其输入<代码> 重量级:

import csv

weighed_items = [(item,float(weight)) for item,weight in csv.reader(open( file.csv ))]
picker = WeightedChoice(weighed_items)
print(picker.pick())
问题回答
lst = [ ( Orange , 0.10), ( Apple , 0.05), ( Mango , 0.15), ( etc , 0.69) ]

x = 0.0
lst2 = []
for fruit, chance in lst:
    tup = (x, fruit)
    lst2.append(tup)
    x += chance

tup = (x, None)
lst2.append(tup)

import random

def pick_one(lst2):
    if lst2[0][1] is None:
        raise ValueError, "no valid values to choose"
    while True:
        r = random.random()
        for x, fruit in reversed(lst2):
            if x <= r:
                if fruit is None:
                    break  # try again with a different random value
                else:
                    return fruit

pick_one(lst2)

这形成了一个新的清单,其 as价值代表了选择水果的各种价值;然后, pick(一)冲倒了清单,看着“斜”的价值;=目前的随机价值。 我们把“哨兵”价值列入清单的末尾;如果数值不超过1.0,就有可能产生一种随机价值,而这种价值与任何数值相匹配,并将与所投的价值相匹配,然后予以拒绝。 随机(0.0、1.0)将随机数值归为[0、1.0],因此,确定最终与清单中的内容相匹配。

这里的一点是,你应该能够拥有一个价值,拥有0.000001的匹配机会,而且实际上应该与这一频率相匹配;另一种解决办法是,如果你提出清单,重复并公正地使用随机选择的项目,则需要一份清单,其中列出100万件。

lst = [ ( Orange , 0.10), ( Apple , 0.05), ( Mango , 0.15), ( etc , 0.69) ]

x = 0.0
lst2 = []
for fruit, chance in lst:
    low = x
    high = x + chance
    tup = (low, high, fruit)
    lst2.append(tup)
    x += chance

if x > 1.0:
    raise ValueError, "chances add up to more than 100%"

low = x
high = 1.0
tup = (low, high, None)
lst2.append(tup)

import random

def pick_one(lst2):
    if lst2[0][2] is None:
        raise ValueError, "no valid values to choose"
    while True:
        r = random.random()
        for low, high, fruit in lst2:
            if low <= r < high:
                if fruit is None:
                    break  # try again with a different random value
                else:
                    return fruit

pick_one(lst2)


# test it 10,000 times
d = {}
for i in xrange(10000):
    x = pick_one(lst2)
    if x in d:
        d[x] += 1
    else:
        d[x] = 1

我认为这更清楚。 我们不是把幅度作为ending升值的简单方法,而是保持幅度。 由于我们正在测试范围,我们只能走到最快的2个数值上来;无需使用<代码>reversed(<>/code>)。

from numpy.random import multinomial
import numpy as np

def pickone(dist):
    return np.where(multinomial(1, dist) == 1)[0][0]

if __name__ ==  __main__ :
    lst = [ ( Orange , 0.10), ( Apple , 0.05), ( Mango , 0.15), ( etc , 0.70) ]
    dist = [p[1] for p in lst]
    
    N = 10000
    draws = np.array([pickone(dist) for i in range(N)], dtype=int)
    hist = np.histogram(draws, bins=[i for i in range(len(dist)+1)])[0]
    for i in range(len(lst)):
        print(f {lst[i]} {hist[i]/N} )
import random
d= { orange : 0.10,  mango : 0.15,  apple : 0.05}
weightedArray = []
for k in d:
  weightedArray+=[k]*int(d[k]*100)
random.choice(weightedArray)

<><><>>>>

这基本上是Brian上文所述的。





相关问题
热门标签