7

我有一个元素概率数组,比方说[0.1, 0.2, 0.5, 0.2]。数组总和为 1.0。

使用普通的 Python 或 numpy,我想绘制与它们的概率成比例的元素:第一个元素大约 10% 的时间,第二个 20%,第三个 50% 等等。“draw”应该返回绘制元素的索引。

我想出了这个:

def draw(probs):
    cumsum = numpy.cumsum(probs / sum(probs)) # sum up to 1.0, just in case
    return len(numpy.where(numpy.random.rand() >= cumsum)[0])

行得通,但是太复杂了,一定有更好的办法。谢谢。

4

5 回答 5

9
import numpy as np
def random_pick(choices, probs):
    '''
    >>> a = ['Hit', 'Out']
    >>> b = [.3, .7]
    >>> random_pick(a,b)
    '''
    cutoffs = np.cumsum(probs)
    idx = cutoffs.searchsorted(np.random.uniform(0, cutoffs[-1]))
    return choices[idx]

这个怎么运作:

In [22]: import numpy as np
In [23]: probs = [0.1, 0.2, 0.5, 0.2]

计算累积和:

In [24]: cutoffs = np.cumsum(probs)
In [25]: cutoffs
Out[25]: array([ 0.1,  0.3,  0.8,  1. ])

计算半开区间 中的均匀分布随机数[0, cutoffs[-1])

In [26]: np.random.uniform(0, cutoffs[-1])
Out[26]: 0.9723114393023948

使用searchsorted查找将插入随机数的索引cutoffs

In [27]: cutoffs.searchsorted(0.9723114393023948)
Out[27]: 3

Return choices[idx]idx该索引在哪里。

于 2012-01-23T14:45:57.830 回答
4

您想从分类分布中进行采样,这在 numpy 中没有实现。但是,多项分布是分类分布的推广,可用于该目的。

>>> import numpy as np
>>> 
>>> def sampleCategory(p):
...     return np.flatnonzero( np.random.multinomial(1,p,1) )[0]
... 
>>> sampleCategory( [0.1,0.5,0.4] )
1
于 2012-09-07T14:53:09.887 回答
1

使用numpy.random.multinomial- 最有效

于 2012-03-08T18:34:13.730 回答
0

我从未使用过 numpy,但我假设下面的代码(仅限 python)与您在一行中完成的操作相同。我把它放在这里以防万一你想要它。

看起来很c-ish所以很抱歉不是很pythonic。

weight_total 对你来说是 1。

def draw(probs)
    r = random.randrange(weight_total)
    running_total = 0
    for i, p in enumerate(probs)
        running_total += p
        if running_total > r:
            return i
于 2012-01-23T14:59:52.623 回答
0

使用平分

import bisect
import random
import numpy 
def draw(probs):
    cumsum=numpy.cumsum(probs/sum(probs))
    return bisect.bisect_left(cumsum, numpy.random.rand())

应该做的伎俩。

于 2012-01-23T17:12:42.007 回答